1 /*
2 * Copyright (C) 1999-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
5 * Copyright (C) 2006-2016 Tim Mayberry <mojofunk@gmail.com>
6 * Copyright (C) 2006 Jesse Chappell <jesse@essej.net>
7 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
9 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
10 * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
11 * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
12 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
13 * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 */
29
30
31 #ifdef WAF_BUILD
32 #include "libardour-config.h"
33 #endif
34
35 #include <stdint.h>
36
37 #include <algorithm>
38 #include <string>
39 #include <cerrno>
40 #include <cstdio> /* snprintf(3) ... grrr */
41 #include <cmath>
42
43 #include <unistd.h>
44 #include <climits>
45 #include <signal.h>
46 #include <sys/time.h>
47 /* for open(2) */
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51
52 #ifdef HAVE_SYS_VFS_H
53 #include <sys/vfs.h>
54 #endif
55
56 #if defined(__APPLE__) || defined(__FreeBSD__)
57 #include <sys/param.h>
58 #include <sys/mount.h>
59 #endif
60
61 #ifdef HAVE_SYS_STATVFS_H
62 #include <sys/statvfs.h>
63 #endif
64
65 #include <glib.h>
66 #include "pbd/gstdio_compat.h"
67 #include "pbd/locale_guard.h"
68
69 #include <glibmm.h>
70 #include <glibmm/threads.h>
71 #include <glibmm/fileutils.h>
72
73 #include <boost/algorithm/string.hpp>
74
75 #include "midi++/mmc.h"
76 #include "midi++/port.h"
77
78 #include "evoral/SMF.h"
79
80 #include "pbd/basename.h"
81 #include "pbd/debug.h"
82 #include "pbd/enumwriter.h"
83 #include "pbd/error.h"
84 #include "pbd/file_utils.h"
85 #include "pbd/pathexpand.h"
86 #include "pbd/pthread_utils.h"
87 #include "pbd/scoped_file_descriptor.h"
88 #include "pbd/types_convert.h"
89 #include "pbd/localtime_r.h"
90 #include "pbd/unwind.h"
91
92 #include "ardour/amp.h"
93 #include "ardour/async_midi_port.h"
94 #include "ardour/audio_track.h"
95 #include "ardour/audioengine.h"
96 #include "ardour/audiofilesource.h"
97 #include "ardour/audioregion.h"
98 #include "ardour/auditioner.h"
99 #include "ardour/automation_control.h"
100 #include "ardour/boost_debug.h"
101 #include "ardour/butler.h"
102 #include "ardour/control_protocol_manager.h"
103 #include "ardour/directory_names.h"
104 #include "ardour/disk_reader.h"
105 #include "ardour/filename_extensions.h"
106 #include "ardour/graph.h"
107 #include "ardour/location.h"
108 #include "ardour/lv2_plugin.h"
109 #include "ardour/midi_model.h"
110 #include "ardour/midi_region.h"
111 #include "ardour/midi_scene_changer.h"
112 #include "ardour/midi_source.h"
113 #include "ardour/midi_track.h"
114 #include "ardour/playlist_factory.h"
115 #include "ardour/playlist_source.h"
116 #include "ardour/port.h"
117 #include "ardour/processor.h"
118 #include "ardour/progress.h"
119 #include "ardour/profile.h"
120 #include "ardour/proxy_controllable.h"
121 #include "ardour/recent_sessions.h"
122 #include "ardour/region_factory.h"
123 #include "ardour/revision.h"
124 #include "ardour/route_group.h"
125 #include "ardour/send.h"
126 #include "ardour/selection.h"
127 #include "ardour/session.h"
128 #include "ardour/session_directory.h"
129 #include "ardour/session_metadata.h"
130 #include "ardour/session_playlists.h"
131 #include "ardour/session_state_utils.h"
132 #include "ardour/silentfilesource.h"
133 #include "ardour/smf_source.h"
134 #include "ardour/sndfilesource.h"
135 #include "ardour/source_factory.h"
136 #include "ardour/speakers.h"
137 #include "ardour/template_utils.h"
138 #include "ardour/tempo.h"
139 #include "ardour/ticker.h"
140 #include "ardour/transport_master_manager.h"
141 #include "ardour/types_convert.h"
142 #include "ardour/user_bundle.h"
143 #include "ardour/vca.h"
144 #include "ardour/vca_manager.h"
145
146 #include "control_protocol/control_protocol.h"
147
148 #include "LuaBridge/LuaBridge.h"
149
150 #include "pbd/i18n.h"
151 #include <locale.h>
152
153 using namespace std;
154 using namespace ARDOUR;
155 using namespace PBD;
156
157 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
158
159 void
pre_engine_init(string fullpath)160 Session::pre_engine_init (string fullpath)
161 {
162 if (fullpath.empty()) {
163 destroy ();
164 throw failed_constructor();
165 }
166
167 /* discover canonical fullpath */
168
169 _path = canonical_path(fullpath);
170
171 /* is it new ? */
172
173 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
174
175 /* finish initialization that can't be done in a normal C++ constructor
176 definition.
177 */
178
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&_processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
184 set_next_event ();
185 _all_route_group->set_active (true, this);
186
187 if (config.get_use_video_sync()) {
188 waiting_for_sync_offset = true;
189 } else {
190 waiting_for_sync_offset = false;
191 }
192
193 last_rr_session_dir = session_dirs.begin();
194
195 set_history_depth (Config->get_history_depth());
196
197 /* default: assume simple stereo speaker configuration */
198
199 _speakers->setup_default_speakers (2);
200
201 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
202 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
203 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
204 add_controllable (_solo_cut_control);
205
206 /* These are all static "per-class" signals */
207
208 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
209 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
210 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
211 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
212
213 /* stop IO objects from doing stuff until we're ready for them */
214
215 Delivery::disable_panners ();
216 IO::disable_connecting ();
217 }
218
219 int
post_engine_init()220 Session::post_engine_init ()
221 {
222 BootMessage (_("Set block size and sample rate"));
223
224 set_block_size (_engine.samples_per_cycle());
225 set_sample_rate (_engine.sample_rate());
226
227 BootMessage (_("Using configuration"));
228
229 _midi_ports = new MidiPortManager;
230
231 MIDISceneChanger* msc;
232
233 _scene_changer = msc = new MIDISceneChanger (*this);
234 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
235 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
236
237 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
238 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
239
240 setup_midi_machine_control ();
241
242 /* setup MTC generator */
243 mtc_tx_resync_latency (true);
244 LatencyUpdated.connect_same_thread (*this, boost::bind (&Session::mtc_tx_resync_latency, this, _1));
245
246 if (_butler->start_thread()) {
247 error << _("Butler did not start") << endmsg;
248 return -1;
249 }
250
251 if (start_midi_thread ()) {
252 error << _("MIDI I/O thread did not start") << endmsg;
253 return -1;
254 }
255
256 setup_click_sounds (0);
257 setup_midi_control ();
258
259 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
260 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
261
262 try {
263 /* tempo map requires sample rate knowledge */
264
265 delete _tempo_map;
266 _tempo_map = new TempoMap (_current_sample_rate);
267 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
268 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
269 } catch (std::exception const & e) {
270 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
271 return -2;
272 } catch (...) {
273 error << _("Unknown exception during session setup") << endmsg;
274 return -3;
275 }
276
277 try {
278 /* MidiClock requires a tempo map */
279
280 delete midi_clock;
281 midi_clock = new MidiClockTicker (this);
282
283 /* crossfades require sample rate knowledge */
284
285 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this, true));
286 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
287
288 DiskReader::allocate_working_buffers();
289 refresh_disk_space ();
290
291 /* we're finally ready to call set_state() ... all objects have
292 * been created, the engine is running.
293 */
294
295 if (state_tree) {
296 try {
297 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
298 error << _("Could not set session state from XML") << endmsg;
299 return -4;
300 }
301 } catch (PBD::unknown_enumeration& e) {
302 error << _("Session state: ") << e.what() << endmsg;
303 return -4;
304 }
305 } else {
306 // set_state() will call setup_raid_path(), but if it's a new session we need
307 // to call setup_raid_path() here.
308 setup_raid_path (_path);
309 }
310
311 /* ENGINE */
312
313 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
314 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
315
316 Config->map_parameters (ff);
317 config.map_parameters (ft);
318 _butler->map_parameters ();
319
320 /* Configure all processors; now that the
321 * engine is running, ports are re-established,
322 * and IOChange are complete.
323 */
324 {
325 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
326 ProcessorChangeBlocker pcb (this);
327 boost::shared_ptr<RouteList> r = routes.reader ();
328 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
329 (*i)->configure_processors (0);
330 }
331 /* release process-lock, ProcessorChangeBlocker may trigger
332 * latency-callback from non-rt thread which may take the lock */
333 lx.release ();
334 }
335
336 /* Reset all panners */
337
338 Delivery::reset_panners ();
339
340 /* this will cause the CPM to instantiate any protocols that are in use
341 * (or mandatory), which will pass it this Session, and then call
342 * set_state() on each instantiated protocol to match stored state.
343 */
344
345 ControlProtocolManager::instance().set_session (this);
346
347 /* This must be done after the ControlProtocolManager set_session above,
348 as it will set states for ports which the ControlProtocolManager creates.
349 */
350
351 // XXX set state of MIDI::Port's
352 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
353
354 /* And this must be done after the MIDI::Manager::set_port_states as
355 * it will try to make connections whose details are loaded by set_port_states.
356 */
357
358 hookup_io ();
359
360 /* Let control protocols know that we are now all connected, so they
361 * could start talking to surfaces if they want to.
362 */
363
364 ControlProtocolManager::instance().midi_connectivity_established ();
365
366 if (_is_new && !no_auto_connect()) {
367 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
368 auto_connect_master_bus ();
369 }
370
371 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave | Dirty));
372
373 /* update latencies */
374
375 initialize_latencies ();
376
377 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
378 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
379 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
380
381 if (synced_to_engine()) {
382 _engine.transport_stop ();
383 }
384
385 // send_full_time_code (0);
386
387 } catch (AudioEngine::PortRegistrationFailure& err) {
388 error << err.what() << endmsg;
389 return -5;
390 } catch (std::exception const & e) {
391 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
392 return -6;
393 } catch (...) {
394 error << _("Unknown exception during session setup") << endmsg;
395 return -7;
396 }
397
398 BootMessage (_("Reset Remote Controls"));
399
400 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
401 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
402
403 ltc_tx_initialize();
404
405 Port::set_connecting_blocked (false);
406
407 set_clean ();
408
409 /* Now, finally, we can fill the playback buffers */
410
411 BootMessage (_("Filling playback buffers"));
412
413 boost::shared_ptr<RouteList> rl = routes.reader();
414 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
415 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
416 if (trk && !trk->is_private_route()) {
417 trk->seek (_transport_sample, true);
418 }
419 }
420
421 reset_xrun_count ();
422 return 0;
423 }
424
425 void
session_loaded()426 Session::session_loaded ()
427 {
428 SessionLoaded();
429
430 set_clean ();
431
432 if (_is_new) {
433 save_state ("");
434 } else if (state_was_pending) {
435 save_state ("");
436 state_was_pending = false;
437 }
438
439 /* Now, finally, we can fill the playback buffers */
440
441 BootMessage (_("Filling playback buffers"));
442 force_locate (_transport_sample, MustStop);
443 reset_xrun_count ();
444 }
445
446 string
raid_path() const447 Session::raid_path () const
448 {
449 Searchpath raid_search_path;
450
451 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
452 raid_search_path += (*i).path;
453 }
454
455 return raid_search_path.to_string ();
456 }
457
458 void
setup_raid_path(string path)459 Session::setup_raid_path (string path)
460 {
461 if (path.empty()) {
462 return;
463 }
464
465 space_and_path sp;
466 string fspath;
467
468 session_dirs.clear ();
469
470 Searchpath search_path(path);
471 Searchpath sound_search_path;
472 Searchpath midi_search_path;
473
474 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
475 sp.path = *i;
476 sp.blocks = 0; // not needed
477 session_dirs.push_back (sp);
478
479 SessionDirectory sdir(sp.path);
480
481 sound_search_path += sdir.sound_path ();
482 midi_search_path += sdir.midi_path ();
483 }
484
485 // reset the round-robin soundfile path thingie
486 last_rr_session_dir = session_dirs.begin();
487 }
488
489 bool
path_is_within_session(const std::string & path)490 Session::path_is_within_session (const std::string& path)
491 {
492 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
493 if (PBD::path_is_within (i->path, path)) {
494 return true;
495 }
496 }
497 return false;
498 }
499
500 int
ensure_subdirs()501 Session::ensure_subdirs ()
502 {
503 string dir;
504
505 dir = session_directory().peak_path();
506
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
509 return -1;
510 }
511
512 dir = session_directory().sound_path();
513
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
516 return -1;
517 }
518
519 dir = session_directory().midi_path();
520
521 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
522 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
523 return -1;
524 }
525
526 dir = session_directory().dead_path();
527
528 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
529 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
530 return -1;
531 }
532
533 dir = session_directory().export_path();
534
535 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
536 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
537 return -1;
538 }
539
540 if(Profile->get_mixbus()) {
541 dir = session_directory().backup_path();
542
543 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
544 error << string_compose(_("Session: cannot create session backup folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
545 return -1;
546 }
547 }
548
549 dir = analysis_dir ();
550
551 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
552 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
553 return -1;
554 }
555
556 dir = plugins_dir ();
557
558 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
559 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
560 return -1;
561 }
562
563 dir = externals_dir ();
564
565 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
566 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
567 return -1;
568 }
569
570 return 0;
571 }
572
573 /** @param session_template directory containing session template, or empty.
574 * Caller must not hold process lock.
575 */
576 int
create(const string & session_template,BusProfile const * bus_profile,bool unnamed)577 Session::create (const string& session_template, BusProfile const * bus_profile, bool unnamed)
578 {
579 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
580 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
581 return -1;
582 }
583
584 if (unnamed) {
585 PBD::ScopedFileDescriptor fd = g_open (unnamed_file_name().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666);
586 }
587
588 if (ensure_subdirs ()) {
589 return -1;
590 }
591
592 _writable = exists_and_writable (_path);
593
594 if (!session_template.empty()) {
595 string in_path = session_template_dir_to_file (session_template);
596
597 FILE* in = g_fopen (in_path.c_str(), "rb");
598
599 if (in) {
600 /* no need to call legalize_for_path() since the string
601 * in session_template is already a legal path name
602 */
603 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
604
605 FILE* out = g_fopen (out_path.c_str(), "wb");
606
607 if (out) {
608 char buf[1024];
609 stringstream new_session;
610
611 while (!feof (in)) {
612 size_t charsRead = fread (buf, sizeof(char), 1024, in);
613
614 if (ferror (in)) {
615 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
616 fclose (in);
617 fclose (out);
618 return -1;
619 }
620 if (charsRead == 0) {
621 break;
622 }
623 new_session.write (buf, charsRead);
624 }
625 fclose (in);
626
627 string file_contents = new_session.str();
628 size_t writeSize = file_contents.length();
629 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
630 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
631 fclose (out);
632 return -1;
633 }
634 fclose (out);
635
636 _is_new = false;
637
638 /* Copy plugin state files from template to new session */
639 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
640 copy_recurse (template_plugins, plugins_dir ());
641
642 return 0;
643
644 } else {
645 error << string_compose (_("Could not open %1 for writing session template"), out_path)
646 << endmsg;
647 fclose(in);
648 return -1;
649 }
650
651 } else {
652 error << string_compose (_("Could not open session template %1 for reading"), in_path)
653 << endmsg;
654 return -1;
655 }
656
657 }
658
659 /* set up Master Out and Monitor Out if necessary */
660
661 if (bus_profile) {
662 RouteList rl;
663 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
664 if (bus_profile->master_out_channels) {
665 int rv = add_master_bus (count);
666
667 if (rv) {
668 return rv;
669 }
670
671 if (Config->get_use_monitor_bus())
672 add_monitor_section ();
673 }
674 }
675
676 set_clean ();
677 reset_xrun_count ();
678
679 return 0;
680 }
681
682 void
maybe_write_autosave()683 Session::maybe_write_autosave()
684 {
685 if (dirty() && record_status() != Recording) {
686 save_state("", true);
687 }
688 }
689
690 void
remove_pending_capture_state()691 Session::remove_pending_capture_state ()
692 {
693 std::string pending_state_file_path(_session_dir->root_path());
694
695 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
696
697 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) {
698 return;
699 }
700
701 if (::g_unlink (pending_state_file_path.c_str()) != 0) {
702 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
703 pending_state_file_path, g_strerror (errno)) << endmsg;
704 }
705 #ifndef NDEBUG
706 else {
707 cerr << "removed " << pending_state_file_path << endl;
708 }
709 #endif
710 }
711
712 /** Rename a state file.
713 * @param old_name Old snapshot name.
714 * @param new_name New snapshot name.
715 */
716 void
rename_state(string old_name,string new_name)717 Session::rename_state (string old_name, string new_name)
718 {
719 if (old_name == _current_snapshot_name || old_name == _name) {
720 /* refuse to rename the current snapshot or the "main" one */
721 return;
722 }
723
724 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
725 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
726
727 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
728 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
729
730 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
731 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
732 old_name, new_name, g_strerror(errno)) << endmsg;
733 }
734 }
735
736 /** Remove a state file.
737 * @param snapshot_name Snapshot name.
738 */
739 void
remove_state(string snapshot_name)740 Session::remove_state (string snapshot_name)
741 {
742 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
743 // refuse to remove the current snapshot or the "main" one
744 return;
745 }
746
747 std::string xml_path(_session_dir->root_path());
748
749 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
750
751 if (!create_backup_file (xml_path)) {
752 // don't remove it if a backup can't be made
753 // create_backup_file will log the error.
754 return;
755 }
756
757 // and delete it
758 if (g_remove (xml_path.c_str()) != 0) {
759 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
760 xml_path, g_strerror (errno)) << endmsg;
761 }
762
763 StateSaved (snapshot_name); /* EMIT SIGNAL */
764 }
765
766 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
767 int
save_state(string snapshot_name,bool pending,bool switch_to_snapshot,bool template_only,bool for_archive,bool only_used_assets)768 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
769 {
770 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
771
772 /* only_used_assets is only possible when archiving */
773 assert (!only_used_assets || for_archive);
774 /* template and archive are exclusive */
775 assert (!template_only || !for_archive);
776 /* switch_to_snapshot needs a new name and can't be pending */
777 assert (!switch_to_snapshot || (!snapshot_name.empty () && snapshot_name != _current_snapshot_name && !pending && !template_only && !for_archive));
778 /* pending saves are for current snapshot only */
779 assert (!pending || ((snapshot_name.empty () || snapshot_name == _current_snapshot_name) && !template_only && !for_archive));
780
781 XMLTree tree;
782 std::string xml_path(_session_dir->root_path());
783
784 /* prevent concurrent saves from different threads */
785
786 Glib::Threads::Mutex::Lock lm (save_state_lock);
787 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
788 if (!for_archive) {
789 lx.acquire ();
790 }
791
792 if (!_writable || cannot_save()) {
793 return 1;
794 }
795
796 if (g_atomic_int_get(&_suspend_save)) {
797 /* StateProtector cannot be used for templates or save-as */
798 assert (!template_only && !switch_to_snapshot && !for_archive && (snapshot_name.empty () || snapshot_name == _current_snapshot_name));
799 if (pending) {
800 _save_queued_pending = true;
801 } else {
802 _save_queued = true;
803 }
804 return 1;
805 }
806 if (pending) {
807 _save_queued_pending = false;
808 } else {
809 _save_queued = false;
810 }
811
812 snapshot_t fork_state = NormalSave;
813 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
814 /* snapshot, close midi */
815 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
816 }
817
818 #ifndef NDEBUG
819 const int64_t save_start_time = g_get_monotonic_time();
820 #endif
821
822 /* tell sources we're saving first, in case they write out to a new file
823 * which should be saved with the state rather than the old one */
824 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
825 try {
826 i->second->session_saved();
827 } catch (Evoral::SMF::FileError& e) {
828 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
829 }
830 }
831
832 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
833
834 SessionSaveUnderway (); /* EMIT SIGNAL */
835
836 bool mark_as_clean = true;
837 if (!snapshot_name.empty() && !switch_to_snapshot) {
838 mark_as_clean = false;
839 }
840
841 if (template_only) {
842 mark_as_clean = false;
843 tree.set_root (&get_template());
844 } else {
845 tree.set_root (&state (false, fork_state, only_used_assets));
846 }
847
848 if (snapshot_name.empty()) {
849 snapshot_name = _current_snapshot_name;
850 } else if (switch_to_snapshot) {
851 set_snapshot_name (snapshot_name);
852 }
853
854 assert (!snapshot_name.empty());
855
856 if (!pending) {
857
858 /* proper save: use statefile_suffix (.ardour in English) */
859
860 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
861
862 /* make a backup copy of the old file */
863
864 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
865 // create_backup_file will log the error
866 return -1;
867 }
868
869 } else {
870 assert (snapshot_name == _current_snapshot_name);
871 /* pending save: use pending_suffix (.pending in English) */
872 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
873 }
874
875 std::string tmp_path(_session_dir->root_path());
876 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
877
878 #ifndef NDEBUG
879 cerr << "actually writing state to " << tmp_path << endl;
880 #endif
881
882 if (!tree.write (tmp_path)) {
883 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
884 if (g_remove (tmp_path.c_str()) != 0) {
885 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
886 tmp_path, g_strerror (errno)) << endmsg;
887 }
888 return -1;
889
890 } else {
891
892 #ifndef NDEBUG
893 cerr << "renaming state to " << xml_path << endl;
894 #endif
895
896 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
897 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
898 tmp_path, xml_path, g_strerror(errno)) << endmsg;
899 if (g_remove (tmp_path.c_str()) != 0) {
900 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
901 tmp_path, g_strerror (errno)) << endmsg;
902 }
903 return -1;
904 }
905 }
906
907 //Mixbus auto-backup mechanism
908 if(Profile->get_mixbus()) {
909 if (pending) { //"pending" save means it's a backup, or some other non-user-initiated save; a good time to make a backup
910 // make a serialized safety backup
911 // (will make one periodically but only one per hour is left on disk)
912 // these backup files go into a separated folder
913 char timebuf[128];
914 time_t n;
915 struct tm local_time;
916 time (&n);
917 localtime_r (&n, &local_time);
918 strftime (timebuf, sizeof(timebuf), "%y-%m-%d.%H", &local_time);
919 std::string save_path(session_directory().backup_path());
920 save_path += G_DIR_SEPARATOR;
921 save_path += legalize_for_path(_current_snapshot_name);
922 save_path += "-";
923 save_path += timebuf;
924 save_path += statefile_suffix;
925 if (!copy_file (xml_path, save_path)) {
926 error << string_compose(_("Could not save backup file at path \"%1\" (%2)"),
927 save_path, g_strerror (errno)) << endmsg;
928 }
929 }
930 }
931
932 if (!pending && !for_archive) {
933
934 save_history (snapshot_name);
935
936 if (mark_as_clean) {
937 unset_dirty (/* EMIT SIGNAL */ true);
938 }
939
940 StateSaved (snapshot_name); /* EMIT SIGNAL */
941 }
942
943 #ifndef NDEBUG
944 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
945 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
946 #endif
947
948 if (!pending && !for_archive && ! template_only) {
949 remove_pending_capture_state ();
950 }
951
952 return 0;
953 }
954
955 int
restore_state(string snapshot_name)956 Session::restore_state (string snapshot_name)
957 {
958 try {
959 if (load_state (snapshot_name) == 0) {
960 set_state (*state_tree->root(), Stateful::loading_state_version);
961 }
962 } catch (...) {
963 // SessionException
964 // unknown_enumeration
965 return -1;
966 }
967
968 return 0;
969 }
970
971 int
load_state(string snapshot_name,bool from_template)972 Session::load_state (string snapshot_name, bool from_template)
973 {
974 delete state_tree;
975 state_tree = 0;
976
977 state_was_pending = false;
978
979 /* check for leftover pending state from a crashed capture attempt */
980
981 std::string xmlpath(_session_dir->root_path());
982 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
983
984 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
985
986 /* there is pending state from a crashed capture attempt */
987
988 boost::optional<int> r = AskAboutPendingState();
989 if (r.value_or (1)) {
990 state_was_pending = true;
991 }
992 }
993
994 if (!state_was_pending) {
995 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
996 }
997
998 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
999 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
1000 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
1001 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
1002 return 1;
1003 }
1004 }
1005
1006 state_tree = new XMLTree;
1007
1008 set_dirty();
1009
1010 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
1011
1012 if (!state_tree->read (xmlpath)) {
1013 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
1014 delete state_tree;
1015 state_tree = 0;
1016 return -1;
1017 }
1018
1019 XMLNode const & root (*state_tree->root());
1020
1021 if (root.name() != X_("Session")) {
1022 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
1023 delete state_tree;
1024 state_tree = 0;
1025 return -1;
1026 }
1027
1028 std::string version;
1029 root.get_property ("version", version);
1030 Stateful::loading_state_version = parse_stateful_loading_version (version);
1031
1032 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
1033 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
1034 throw SessionException (string_compose (_("Incompatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
1035 }
1036
1037 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable && !from_template) {
1038
1039 std::string backup_path(_session_dir->root_path());
1040 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1041 backup_path = Glib::build_filename (backup_path, backup_filename);
1042
1043 // only create a backup for a given statefile version once
1044
1045 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1046
1047 VersionMismatch (xmlpath, backup_path);
1048
1049 if (!copy_file (xmlpath, backup_path)) {;
1050 return -1;
1051 }
1052 }
1053 }
1054
1055 save_snapshot_name (snapshot_name);
1056
1057 return 0;
1058 }
1059
1060 int
load_options(const XMLNode & node)1061 Session::load_options (const XMLNode& node)
1062 {
1063 config.set_variables (node);
1064 return 0;
1065 }
1066
1067 bool
save_default_options()1068 Session::save_default_options ()
1069 {
1070 return config.save_state();
1071 }
1072
1073 XMLNode&
get_state()1074 Session::get_state ()
1075 {
1076 /* this is not directly called, but required by PBD::Stateful */
1077 assert (0);
1078 return state (false, NormalSave);
1079 }
1080
1081 XMLNode&
get_template()1082 Session::get_template ()
1083 {
1084 /* if we don't disable rec-enable, diskstreams
1085 will believe they need to store their capture
1086 sources in their state node.
1087 */
1088
1089 disable_record (false);
1090
1091 return state (true, NormalSave);
1092 }
1093
1094 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1095 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1096
1097 bool
export_track_state(boost::shared_ptr<RouteList> rl,const string & path)1098 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1099 {
1100 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1101 return false;
1102 }
1103 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1104 return false;
1105 }
1106
1107 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1108
1109 LocaleGuard lg;
1110 XMLNode* node = new XMLNode("TrackState"); // XXX
1111 XMLNode* child;
1112
1113 PlaylistSet playlists; // SessionPlaylists
1114 SourceSet sources;
1115
1116 // these will work with new_route_from_template()
1117 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1118 child = node->add_child ("Routes");
1119 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1120 if ((*i)->is_auditioner()) {
1121 continue;
1122 }
1123 if ((*i)->is_master() || (*i)->is_monitor()) {
1124 continue;
1125 }
1126 child->add_child_nocopy ((*i)->get_state());
1127 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1128 if (track) {
1129 playlists.insert (track->playlist ());
1130 }
1131 }
1132
1133 // on load, Regions in the playlists need to resolve and map Source-IDs
1134 // also playlist needs to be merged or created with new-name..
1135 // ... and Diskstream in tracks adjusted to use the correct playlist
1136 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1137 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1138 child->add_child_nocopy ((*i)->get_state ());
1139 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1140 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1141 const Region::SourceList& sl = (*s)->sources ();
1142 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1143 sources.insert (*sli);
1144 }
1145 }
1146 }
1147
1148 child = node->add_child ("Sources");
1149 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1150 child->add_child_nocopy ((*i)->get_state ());
1151 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1152 if (fs) {
1153 #ifdef PLATFORM_WINDOWS
1154 fs->close ();
1155 #endif
1156 string p = fs->path ();
1157 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1158 }
1159 }
1160
1161 std::string sn = Glib::build_filename (path, "share.axml");
1162
1163 XMLTree tree;
1164 tree.set_root (node);
1165 return tree.write (sn.c_str());
1166 }
1167
1168 static void
merge_all_sources(boost::shared_ptr<const Playlist> pl,std::set<boost::shared_ptr<Source>> * all_sources)1169 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1170 {
1171 pl->deep_sources (*all_sources);
1172 }
1173
1174 namespace
1175 {
1176 struct route_id_compare {
1177 bool
operator ()__anon16706f6d0111::route_id_compare1178 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1179 {
1180 return r1->id () < r2->id ();
1181 }
1182 };
1183 } // anon namespace
1184
1185 XMLNode&
state(bool save_template,snapshot_t snapshot_type,bool only_used_assets)1186 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1187 {
1188 LocaleGuard lg;
1189 XMLNode* node = new XMLNode("Session");
1190 XMLNode* child;
1191
1192 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1193
1194 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1195
1196 child = node->add_child ("ProgramVersion");
1197 child->set_property("created-with", created_with);
1198
1199 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1200 child->set_property("modified-with", modified_with);
1201
1202 /* store configuration settings */
1203
1204 if (!save_template) {
1205
1206 node->set_property ("name", _name);
1207 node->set_property ("sample-rate", _base_sample_rate);
1208
1209 /* store the last engine device we we can avoid autostarting on a different device with wrong i/o count */
1210 boost::shared_ptr<AudioBackend> backend = _engine.current_backend();
1211 if (_engine.running () && backend && _engine.setup_required ()) {
1212 child = node->add_child ("EngineHints");
1213 child->set_property ("backend", backend-> name ());
1214 if (backend->use_separate_input_and_output_devices()) {
1215 child->set_property ("input-device", backend->input_device_name ());
1216 child->set_property ("output-device", backend->output_device_name ());
1217 } else {
1218 child->set_property ("input-device", backend->device_name ());
1219 child->set_property ("output-device", backend->device_name ());
1220 }
1221 }
1222
1223 if (session_dirs.size() > 1) {
1224
1225 string p;
1226
1227 vector<space_and_path>::iterator i = session_dirs.begin();
1228 vector<space_and_path>::iterator next;
1229
1230 ++i; /* skip the first one */
1231 next = i;
1232 ++next;
1233
1234 while (i != session_dirs.end()) {
1235
1236 p += (*i).path;
1237
1238 if (next != session_dirs.end()) {
1239 p += G_SEARCHPATH_SEPARATOR;
1240 } else {
1241 break;
1242 }
1243
1244 ++next;
1245 ++i;
1246 }
1247
1248 child = node->add_child ("Path");
1249 child->add_content (p);
1250 }
1251 node->set_property ("end-is-free", _session_range_is_free); //deprecated, but keep storing this value for compatibility with prior v5.
1252 node->set_property ("session-range-is-free", _session_range_is_free);
1253 }
1254
1255 /* save the ID counter */
1256
1257 node->set_property ("id-counter", ID::counter());
1258
1259 node->set_property ("name-counter", name_id_counter ());
1260
1261 /* save the event ID counter */
1262
1263 node->set_property ("event-counter", Evoral::event_id_counter());
1264
1265 /* save the VCA counter */
1266
1267 node->set_property ("vca-counter", VCA::get_next_vca_number());
1268
1269 /* various options */
1270
1271 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1272 if (!midi_port_nodes.empty()) {
1273 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1274 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1275 midi_port_stuff->add_child_nocopy (**n);
1276 }
1277 node->add_child_nocopy (*midi_port_stuff);
1278 }
1279
1280 XMLNode& cfgxml (config.get_variables ());
1281 if (save_template) {
1282 /* exclude search-paths from template */
1283 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1284 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1285 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1286 }
1287 node->add_child_nocopy (cfgxml);
1288
1289 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1290
1291 child = node->add_child ("Sources");
1292
1293 if (!save_template) {
1294 Glib::Threads::Mutex::Lock sl (source_lock);
1295
1296 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1297
1298 if (only_used_assets) {
1299 _playlists->sync_all_regions_with_regions ();
1300 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1301 }
1302
1303 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1304
1305 /* Don't save information about non-file Sources, or
1306 * about file sources that are empty
1307 * and unused by any regions.
1308 */
1309 boost::shared_ptr<FileSource> fs;
1310
1311 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1312 continue;
1313 }
1314
1315 if (fs->empty() && !fs->used()) {
1316 continue;
1317 }
1318
1319 if (only_used_assets) {
1320 /* skip only unused audio files */
1321 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1322 if (afs && !afs->used()) {
1323 continue;
1324 }
1325 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1326 continue;
1327 }
1328 }
1329
1330 if (snapshot_type != NormalSave && fs->within_session ()) {
1331 /* copy MIDI sources to new file
1332 *
1333 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1334 * because the GUI (midi_region) has a direct pointer to the midi-model
1335 * of the source, as does UndoTransaction.
1336 *
1337 * On the upside, .mid files are not kept open. The file is only open
1338 * when reading the model initially and when flushing the model to disk:
1339 * source->session_saved () or export.
1340 *
1341 * We can change the _path of the existing source under the hood, keeping
1342 * all IDs, references and pointers intact.
1343 * */
1344 boost::shared_ptr<SMFSource> ms;
1345 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1346 const std::string ancestor_name = ms->ancestor_name();
1347 const std::string base = PBD::basename_nosuffix(ancestor_name);
1348 const string path = new_midi_source_path (base, false);
1349
1350 /* Session::save_state() will already have called
1351 * ms->session_saved ();
1352 */
1353
1354 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1355 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, ms->flags()));
1356 Source::Lock lm (ms->mutex());
1357
1358 if (!ms->model()) {
1359 ms->load_model (lm);
1360 }
1361 /* write_to() calls newsrc->flush_midi () to write the file to disk */
1362 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1363 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1364 } else {
1365 newsrc->session_saved (); /*< this sohuld be a no-op */
1366
1367 if (snapshot_type == SnapshotKeep) {
1368 /* keep working on current session.
1369 *
1370 * Save snapshot-state with the original filename.
1371 * Switch to use new path for future saves of the main session.
1372 */
1373 child->add_child_nocopy (ms->get_state());
1374 }
1375
1376 /* swap file-paths.
1377 * ~SMFSource unlinks removable() files.
1378 */
1379 std::string npath (ms->path ());
1380 ms->replace_file (newsrc->path ());
1381 newsrc->replace_file (npath);
1382
1383 if (snapshot_type == SwitchToSnapshot) {
1384 /* save and switch to snapshot.
1385 *
1386 * Leave the old file in place (as is).
1387 * Snapshot uses new source directly
1388 */
1389 child->add_child_nocopy (ms->get_state());
1390 }
1391 }
1392 continue;
1393 }
1394 }
1395 child->add_child_nocopy (siter->second->get_state());
1396 }
1397 }
1398
1399 child = node->add_child ("Regions");
1400
1401 if (!save_template) {
1402 Glib::Threads::Mutex::Lock rl (region_lock);
1403
1404 if (!only_used_assets) {
1405 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1406 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1407 boost::shared_ptr<Region> r = i->second;
1408 /* regions must have sources */
1409 assert (r->sources().size() > 0 && r->master_sources().size() > 0);
1410 /* only store regions not attached to playlists */
1411 if (r->playlist() == 0) {
1412 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1413 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1414 } else {
1415 child->add_child_nocopy (r->get_state ());
1416 }
1417 }
1418 }
1419 }
1420
1421 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1422
1423 if (!cassocs.empty()) {
1424 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1425
1426 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1427 if (i->first->playlist () == 0 && only_used_assets) {
1428 continue;
1429 }
1430 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1431 can->set_property (X_("copy"), i->first->id());
1432 can->set_property (X_("original"), i->second->id());
1433 ca->add_child_nocopy (*can);
1434 /* see above, child is still "Regions" here */
1435 if (i->second->playlist() == 0 && only_used_assets) {
1436 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1437 child->add_child_nocopy (ar->get_basic_state ());
1438 } else {
1439 child->add_child_nocopy (ar->get_state ());
1440 }
1441 }
1442 }
1443 }
1444 }
1445
1446 if (!save_template) {
1447
1448 node->add_child_nocopy (_selection->get_state());
1449
1450 if (_locations) {
1451 node->add_child_nocopy (_locations->get_state());
1452 }
1453 } else {
1454 Locations loc (*this);
1455 const bool was_dirty = dirty();
1456 // for a template, just create a new Locations, populate it
1457 // with the default start and end, and get the state for that.
1458 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1459 range->set (max_samplepos, 0);
1460 loc.add (range);
1461 XMLNode& locations_state = loc.get_state();
1462
1463 node->add_child_nocopy (locations_state);
1464
1465 /* adding a location above will have marked the session
1466 * dirty. This is an artifact, so fix it if the session wasn't
1467 * already dirty
1468 */
1469
1470 if (!was_dirty) {
1471 unset_dirty ();
1472 }
1473 }
1474
1475 child = node->add_child ("Bundles");
1476 {
1477 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1478 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1479 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1480 if (b) {
1481 child->add_child_nocopy (b->get_state());
1482 }
1483 }
1484 }
1485
1486 node->add_child_nocopy (_vca_manager->get_state());
1487
1488 child = node->add_child ("Routes");
1489 {
1490 boost::shared_ptr<RouteList> r = routes.reader ();
1491
1492 route_id_compare cmp;
1493 RouteList xml_node_order (*r);
1494 xml_node_order.sort (cmp);
1495
1496 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1497 if (!(*i)->is_auditioner()) {
1498 if (save_template) {
1499 child->add_child_nocopy ((*i)->get_template());
1500 } else {
1501 child->add_child_nocopy ((*i)->get_state());
1502 }
1503 }
1504 }
1505 }
1506
1507 _playlists->add_state (node, save_template, !only_used_assets);
1508
1509 child = node->add_child ("RouteGroups");
1510 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1511 child->add_child_nocopy ((*i)->get_state());
1512 }
1513
1514 if (_click_io) {
1515 XMLNode* gain_child = node->add_child ("Click");
1516 gain_child->add_child_nocopy (_click_io->get_state ());
1517 gain_child->add_child_nocopy (_click_gain->get_state ());
1518 }
1519
1520 node->add_child_nocopy (_speakers->get_state());
1521 node->add_child_nocopy (_tempo_map->get_state());
1522 node->add_child_nocopy (get_control_protocol_state());
1523
1524 if (_extra_xml) {
1525 node->add_child_copy (*_extra_xml);
1526 }
1527
1528 {
1529 Glib::Threads::Mutex::Lock lm (lua_lock);
1530 std::string saved;
1531 {
1532 luabridge::LuaRef savedstate ((*_lua_save)());
1533 saved = savedstate.cast<std::string>();
1534 }
1535 lua.collect_garbage ();
1536 lm.release ();
1537
1538 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1539 std::string b64s (b64);
1540 g_free (b64);
1541
1542 XMLNode* script_node = new XMLNode (X_("Script"));
1543 script_node->set_property (X_("lua"), LUA_VERSION);
1544 script_node->add_content (b64s);
1545 node->add_child_nocopy (*script_node);
1546 }
1547
1548 return *node;
1549 }
1550
1551 XMLNode&
get_control_protocol_state()1552 Session::get_control_protocol_state ()
1553 {
1554 return ControlProtocolManager::instance().get_state ();
1555 }
1556
1557 int
set_state(const XMLNode & node,int version)1558 Session::set_state (const XMLNode& node, int version)
1559 {
1560 LocaleGuard lg;
1561 XMLNodeList nlist;
1562 XMLNode* child;
1563 int ret = -1;
1564
1565 _state_of_the_state = StateOfTheState (_state_of_the_state | CannotSave);
1566
1567 if (node.name() != X_("Session")) {
1568 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1569 goto out;
1570 }
1571
1572 node.get_property ("name", _name);
1573
1574 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1575
1576 _nominal_sample_rate = _base_sample_rate;
1577
1578 assert (AudioEngine::instance()->running ());
1579 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1580 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1581 if (r.value_or (0)) {
1582 goto out;
1583 }
1584 }
1585 }
1586
1587 created_with = "unknown";
1588 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1589 child->get_property (X_("created-with"), created_with);
1590 }
1591
1592 setup_raid_path(_session_dir->root_path());
1593
1594 node.get_property (X_("end-is-free"), _session_range_is_free); //deprectated, but use old values if they are in the config
1595
1596 node.get_property (X_("session-range-is-free"), _session_range_is_free);
1597
1598 uint64_t counter;
1599 if (node.get_property (X_("id-counter"), counter)) {
1600 ID::init_counter (counter);
1601 } else {
1602 /* old sessions used a timebased counter, so fake
1603 * the startup ID counter based on a standard
1604 * timestamp.
1605 */
1606 time_t now;
1607 time (&now);
1608 ID::init_counter (now);
1609 }
1610
1611 if (node.get_property (X_("name-counter"), counter)) {
1612 init_name_id_counter (counter);
1613 }
1614
1615 if (node.get_property (X_("event-counter"), counter)) {
1616 Evoral::init_event_id_counter (counter);
1617 }
1618
1619 if (node.get_property (X_("vca-counter"), counter)) {
1620 VCA::set_next_vca_number (counter);
1621 } else {
1622 VCA::set_next_vca_number (1);
1623 }
1624
1625 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1626 _midi_ports->set_midi_port_states (child->children());
1627 }
1628
1629 IO::disable_connecting ();
1630
1631 Stateful::save_extra_xml (node);
1632
1633 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1634 load_options (*child);
1635 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1636 load_options (*child);
1637 } else {
1638 error << _("Session: XML state has no options section") << endmsg;
1639 }
1640
1641 if (version >= 3000) {
1642 if ((child = find_named_node (node, "Metadata")) == 0) {
1643 warning << _("Session: XML state has no metadata section") << endmsg;
1644 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1645 goto out;
1646 }
1647 }
1648
1649 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1650 _speakers->set_state (*child, version);
1651 }
1652
1653 if ((child = find_named_node (node, "Sources")) == 0) {
1654 error << _("Session: XML state has no sources section") << endmsg;
1655 goto out;
1656 } else if (load_sources (*child)) {
1657 goto out;
1658 }
1659
1660 if ((child = find_named_node (node, "TempoMap")) == 0) {
1661 error << _("Session: XML state has no Tempo Map section") << endmsg;
1662 goto out;
1663 } else if (_tempo_map->set_state (*child, version)) {
1664 goto out;
1665 }
1666
1667 if ((child = find_named_node (node, "Locations")) == 0) {
1668 error << _("Session: XML state has no locations section") << endmsg;
1669 goto out;
1670 } else if (_locations->set_state (*child, version)) {
1671 goto out;
1672 }
1673
1674 locations_changed ();
1675
1676 if (_session_range_location) {
1677 AudioFileSource::set_header_position_offset (_session_range_location->start());
1678 }
1679
1680 if ((child = find_named_node (node, "Regions")) == 0) {
1681 error << _("Session: XML state has no Regions section") << endmsg;
1682 goto out;
1683 } else if (load_regions (*child)) {
1684 goto out;
1685 }
1686
1687 if ((child = find_named_node (node, "Playlists")) == 0) {
1688 error << _("Session: XML state has no playlists section") << endmsg;
1689 goto out;
1690 } else if (_playlists->load (*this, *child)) {
1691 goto out;
1692 }
1693
1694 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1695 // this is OK
1696 } else if (_playlists->load_unused (*this, *child)) {
1697 goto out;
1698 }
1699
1700 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1701 if (load_compounds (*child)) {
1702 goto out;
1703 }
1704 }
1705
1706 if (version >= 3000) {
1707 if ((child = find_named_node (node, "Bundles")) == 0) {
1708 warning << _("Session: XML state has no bundles section") << endmsg;
1709 //goto out;
1710 } else {
1711 /* We can't load Bundles yet as they need to be able
1712 * to convert from port names to Port objects, which can't happen until
1713 * later */
1714 _bundle_xml_node = new XMLNode (*child);
1715 }
1716 }
1717
1718 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1719 _vca_manager->set_state (*child, version);
1720 }
1721
1722 if (version < 3000) {
1723 if ((child = find_named_node (node, "DiskStreams"))) {
1724 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1725 if ((*n)->name() == "AudioDiskstream" || (*n)->name() == "DiskStream") {
1726 std::string diskstream_id;
1727 std::string playlist_name;
1728 if ((*n)->get_property ("playlist", playlist_name) && (*n)->get_property ("id", diskstream_id)) {
1729 _diskstreams_2X [PBD::ID(diskstream_id)] = playlist_name;
1730 }
1731 }
1732 }
1733 }
1734 }
1735
1736 if ((child = find_named_node (node, "Routes")) == 0) {
1737 error << _("Session: XML state has no routes section") << endmsg;
1738 goto out;
1739 } else if (load_routes (*child, version)) {
1740 goto out;
1741 }
1742
1743 /* Now that we Tracks have been loaded and playlists are assigned */
1744 _playlists->update_tracking ();
1745
1746 _diskstreams_2X.clear ();
1747
1748 /* Now that we have Routes and masters loaded, connect them if appropriate */
1749
1750 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1751
1752 if (version >= 3000) {
1753
1754 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1755 error << _("Session: XML state has no route groups section") << endmsg;
1756 goto out;
1757 } else if (load_route_groups (*child, version)) {
1758 goto out;
1759 }
1760
1761 } else if (version < 3000) {
1762
1763 if ((child = find_named_node (node, "EditGroups")) == 0) {
1764 error << _("Session: XML state has no edit groups section") << endmsg;
1765 goto out;
1766 } else if (load_route_groups (*child, version)) {
1767 goto out;
1768 }
1769
1770 if ((child = find_named_node (node, "MixGroups")) == 0) {
1771 error << _("Session: XML state has no mix groups section") << endmsg;
1772 goto out;
1773 } else if (load_route_groups (*child, version)) {
1774 goto out;
1775 }
1776 }
1777
1778 if ((child = find_named_node (node, "Click")) == 0) {
1779 warning << _("Session: XML state has no click section") << endmsg;
1780 } else if (_click_io) {
1781 setup_click_state (&node);
1782 }
1783
1784 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1785 ControlProtocolManager::instance().set_state (*child, 1 /* here: session-specific state */);
1786 }
1787
1788 if ((child = find_named_node (node, "Script"))) {
1789 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1790 if (!(*n)->is_content ()) { continue; }
1791 gsize size;
1792 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1793 try {
1794 Glib::Threads::Mutex::Lock lm (lua_lock);
1795 (*_lua_load)(std::string ((const char*)buf, size));
1796 } catch (luabridge::LuaException const& e) {
1797 #ifndef NDEBUG
1798 cerr << "LuaException:" << e.what () << endl;
1799 #endif
1800 warning << "LuaException: " << e.what () << endmsg;
1801 } catch (...) { }
1802 g_free (buf);
1803 }
1804 }
1805
1806 if ((child = find_named_node (node, X_("Selection")))) {
1807 _selection->set_state (*child, version);
1808 }
1809
1810 update_route_record_state ();
1811
1812 /* here beginneth the second phase ... */
1813 set_snapshot_name (_current_snapshot_name);
1814
1815 StateReady (); /* EMIT SIGNAL */
1816
1817 delete state_tree;
1818 state_tree = 0;
1819 return 0;
1820
1821 out:
1822 delete state_tree;
1823 state_tree = 0;
1824 return ret;
1825 }
1826
1827 int
load_routes(const XMLNode & node,int version)1828 Session::load_routes (const XMLNode& node, int version)
1829 {
1830 XMLNodeList nlist;
1831 XMLNodeConstIterator niter;
1832 RouteList new_routes;
1833
1834 nlist = node.children();
1835
1836 set_dirty();
1837
1838 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1839
1840 boost::shared_ptr<Route> route;
1841
1842 if (version < 3000) {
1843 route = XMLRouteFactory_2X (**niter, version);
1844 } else if (version < 5000) {
1845 route = XMLRouteFactory_3X (**niter, version);
1846 } else {
1847 route = XMLRouteFactory (**niter, version);
1848 }
1849
1850 if (route == 0) {
1851 error << _("Session: cannot create track/bus from XML description.") << endmsg;
1852 return -1;
1853 }
1854
1855 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1856
1857 new_routes.push_back (route);
1858 }
1859
1860 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1861
1862 add_routes (new_routes, false, false, PresentationInfo::max_order);
1863
1864 /* re-subscribe to MIDI connection handler */
1865 for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
1866 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
1867 bool is_midi_route = (*r)->n_inputs().n_midi() > 0 && (*r)->n_inputs().n_midi() > 0;
1868 if (mt || is_midi_route) {
1869 (*r)->output()->changed.connect_same_thread (*this, boost::bind (&Session::midi_output_change_handler, this, _1, _2, boost::weak_ptr<Route>(*r)));
1870 }
1871 }
1872
1873
1874 BootMessage (_("Finished adding tracks/busses"));
1875
1876 return 0;
1877 }
1878
1879 boost::shared_ptr<Route>
XMLRouteFactory(const XMLNode & node,int version)1880 Session::XMLRouteFactory (const XMLNode& node, int version)
1881 {
1882 boost::shared_ptr<Route> ret;
1883
1884 if (node.name() != "Route") {
1885 return ret;
1886 }
1887
1888 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1889
1890 if (!pl_prop) {
1891 pl_prop = node.property (X_("midi-playlist"));
1892 }
1893
1894 DataType type = DataType::AUDIO;
1895 node.get_property("default-type", type);
1896
1897 assert (type != DataType::NIL);
1898
1899 if (pl_prop) {
1900
1901 /* has at least 1 playlist, therefore a track ... */
1902
1903 boost::shared_ptr<Track> track;
1904
1905 if (type == DataType::AUDIO) {
1906 track.reset (new AudioTrack (*this));
1907 } else {
1908 track.reset (new MidiTrack (*this));
1909 }
1910
1911 if (track->init()) {
1912 return ret;
1913 }
1914
1915 if (track->set_state (node, version)) {
1916 return ret;
1917 }
1918
1919 BOOST_MARK_TRACK (track);
1920 ret = track;
1921
1922 } else {
1923 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1924 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1925
1926 if (r->init () == 0 && r->set_state (node, version) == 0) {
1927 BOOST_MARK_ROUTE (r);
1928 ret = r;
1929 }
1930 }
1931
1932 return ret;
1933 }
1934
1935 boost::shared_ptr<Route>
XMLRouteFactory_3X(const XMLNode & node,int version)1936 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1937 {
1938 boost::shared_ptr<Route> ret;
1939
1940 if (node.name() != "Route") {
1941 return ret;
1942 }
1943
1944 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1945
1946 DataType type = DataType::AUDIO;
1947 node.get_property("default-type", type);
1948
1949 assert (type != DataType::NIL);
1950
1951 if (ds_child) {
1952
1953 boost::shared_ptr<Track> track;
1954
1955 if (type == DataType::AUDIO) {
1956 track.reset (new AudioTrack (*this));
1957 } else {
1958 track.reset (new MidiTrack (*this));
1959 }
1960
1961 if (track->init()) {
1962 return ret;
1963 }
1964
1965 if (track->set_state (node, version)) {
1966 return ret;
1967 }
1968
1969 BOOST_MARK_TRACK (track);
1970 ret = track;
1971
1972 } else {
1973 PresentationInfo::Flag flags = PresentationInfo::get_flags2X3X (node);
1974 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1975
1976 if (r->init () == 0 && r->set_state (node, version) == 0) {
1977 BOOST_MARK_ROUTE (r);
1978 ret = r;
1979 }
1980 }
1981
1982 return ret;
1983 }
1984
1985 boost::shared_ptr<Route>
XMLRouteFactory_2X(const XMLNode & node,int version)1986 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1987 {
1988 boost::shared_ptr<Route> ret;
1989
1990 if (node.name() != "Route") {
1991 return ret;
1992 }
1993
1994 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1995 if (!ds_prop) {
1996 ds_prop = node.property (X_("diskstream"));
1997 }
1998
1999 DataType type = DataType::AUDIO;
2000 node.get_property("default-type", type);
2001
2002 assert (type != DataType::NIL);
2003
2004 if (ds_prop) {
2005
2006 PBD::ID ds_id (ds_prop->value ());
2007 std::string playlist_name = _diskstreams_2X[ds_id];
2008
2009 boost::shared_ptr<Playlist> pl = playlists()->by_name (playlist_name);
2010
2011 if (playlist_name.empty () || !pl) {
2012 warning << string_compose (_("Could not find diskstream for diskstream-id: '%1', playlist: '%2'"), ds_prop->value (), playlist_name) << endmsg;
2013 }
2014
2015 boost::shared_ptr<Track> track;
2016
2017 if (type == DataType::AUDIO) {
2018 track.reset (new AudioTrack (*this));
2019 } else {
2020 track.reset (new MidiTrack (*this));
2021 }
2022
2023 if (track->init()) {
2024 return ret;
2025 }
2026
2027 if (pl) {
2028 track->use_playlist (DataType::AUDIO, pl);
2029 } else {
2030 track->use_new_playlist (DataType::AUDIO);
2031 }
2032
2033 if (track->set_state (node, version)) {
2034 return ret;
2035 }
2036
2037 if (pl) {
2038 pl->set_orig_track_id (track->id());
2039 playlists()->update_orig_2X (ds_id, track->id());
2040 }
2041
2042 BOOST_MARK_TRACK (track);
2043 ret = track;
2044
2045 } else {
2046 PresentationInfo::Flag flags = PresentationInfo::get_flags2X3X (node);
2047 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
2048
2049 if (r->init () == 0 && r->set_state (node, version) == 0) {
2050 BOOST_MARK_ROUTE (r);
2051 ret = r;
2052 }
2053 }
2054
2055 return ret;
2056 }
2057
2058 int
load_regions(const XMLNode & node)2059 Session::load_regions (const XMLNode& node)
2060 {
2061 XMLNodeList nlist;
2062 XMLNodeConstIterator niter;
2063 boost::shared_ptr<Region> region;
2064
2065 nlist = node.children();
2066
2067 set_dirty();
2068
2069 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2070 if ((region = XMLRegionFactory (**niter, false)) == 0) {
2071 error << _("Session: cannot create Region from XML description.");
2072 XMLProperty const * name = (**niter).property("name");
2073
2074 if (name) {
2075 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
2076 }
2077
2078 error << endmsg;
2079 }
2080 }
2081
2082 return 0;
2083 }
2084
2085 int
load_compounds(const XMLNode & node)2086 Session::load_compounds (const XMLNode& node)
2087 {
2088 XMLNodeList calist = node.children();
2089 XMLNodeConstIterator caiter;
2090 XMLProperty const * caprop;
2091
2092 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
2093 XMLNode* ca = *caiter;
2094 ID orig_id;
2095 ID copy_id;
2096
2097 if ((caprop = ca->property (X_("original"))) == 0) {
2098 continue;
2099 }
2100 orig_id = caprop->value();
2101
2102 if ((caprop = ca->property (X_("copy"))) == 0) {
2103 continue;
2104 }
2105 copy_id = caprop->value();
2106
2107 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2108 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2109
2110 if (!orig || !copy) {
2111 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2112 orig_id, copy_id)
2113 << endmsg;
2114 continue;
2115 }
2116
2117 RegionFactory::add_compound_association (orig, copy);
2118 }
2119
2120 return 0;
2121 }
2122
2123 void
load_nested_sources(const XMLNode & node)2124 Session::load_nested_sources (const XMLNode& node)
2125 {
2126 XMLNodeList nlist;
2127 XMLNodeConstIterator niter;
2128
2129 nlist = node.children();
2130
2131 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2132 if ((*niter)->name() == "Source") {
2133
2134 /* it may already exist, so don't recreate it unnecessarily
2135 */
2136
2137 XMLProperty const * prop = (*niter)->property (X_("id"));
2138 if (!prop) {
2139 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2140 continue;
2141 }
2142
2143 ID source_id (prop->value());
2144
2145 if (!source_by_id (source_id)) {
2146
2147 try {
2148 SourceFactory::create (*this, **niter, true);
2149 }
2150 catch (failed_constructor& err) {
2151 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2152 }
2153 }
2154 }
2155 }
2156 }
2157
2158 boost::shared_ptr<Region>
XMLRegionFactory(const XMLNode & node,bool full)2159 Session::XMLRegionFactory (const XMLNode& node, bool full)
2160 {
2161 XMLProperty const * type = node.property("type");
2162
2163 try {
2164
2165 const XMLNodeList& nlist = node.children();
2166
2167 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2168 XMLNode *child = (*niter);
2169 if (child->name() == "NestedSource") {
2170 load_nested_sources (*child);
2171 }
2172 }
2173
2174 if (!type || type->value() == "audio") {
2175 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2176 } else if (type->value() == "midi") {
2177 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2178 }
2179
2180 } catch (failed_constructor& err) {
2181 return boost::shared_ptr<Region> ();
2182 }
2183
2184 return boost::shared_ptr<Region> ();
2185 }
2186
2187 boost::shared_ptr<AudioRegion>
XMLAudioRegionFactory(const XMLNode & node,bool)2188 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2189 {
2190 XMLProperty const * prop;
2191 boost::shared_ptr<Source> source;
2192 boost::shared_ptr<AudioSource> as;
2193 SourceList sources;
2194 SourceList master_sources;
2195 uint32_t nchans = 1;
2196 char buf[128];
2197
2198 if (node.name() != X_("Region")) {
2199 return boost::shared_ptr<AudioRegion>();
2200 }
2201
2202 node.get_property (X_("channels"), nchans);
2203
2204 if ((prop = node.property ("name")) == 0) {
2205 cerr << "no name for this region\n";
2206 abort ();
2207 }
2208
2209 if ((prop = node.property (X_("source-0"))) == 0) {
2210 if ((prop = node.property ("source")) == 0) {
2211 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2212 return boost::shared_ptr<AudioRegion>();
2213 }
2214 }
2215
2216 PBD::ID s_id (prop->value());
2217
2218 if ((source = source_by_id (s_id)) == 0) {
2219 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2220 return boost::shared_ptr<AudioRegion>();
2221 }
2222
2223 as = boost::dynamic_pointer_cast<AudioSource>(source);
2224 if (!as) {
2225 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2226 return boost::shared_ptr<AudioRegion>();
2227 }
2228
2229 sources.push_back (as);
2230
2231 /* pickup other channels */
2232
2233 for (uint32_t n=1; n < nchans; ++n) {
2234 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2235 if ((prop = node.property (buf)) != 0) {
2236
2237 PBD::ID id2 (prop->value());
2238
2239 if ((source = source_by_id (id2)) == 0) {
2240 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2241 return boost::shared_ptr<AudioRegion>();
2242 }
2243
2244 as = boost::dynamic_pointer_cast<AudioSource>(source);
2245 if (!as) {
2246 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2247 return boost::shared_ptr<AudioRegion>();
2248 }
2249 sources.push_back (as);
2250 }
2251 }
2252
2253 for (uint32_t n = 0; n < nchans; ++n) {
2254 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2255 if ((prop = node.property (buf)) != 0) {
2256
2257 PBD::ID id2 (prop->value());
2258
2259 if ((source = source_by_id (id2)) == 0) {
2260 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2261 return boost::shared_ptr<AudioRegion>();
2262 }
2263
2264 as = boost::dynamic_pointer_cast<AudioSource>(source);
2265 if (!as) {
2266 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2267 return boost::shared_ptr<AudioRegion>();
2268 }
2269 master_sources.push_back (as);
2270 }
2271 }
2272
2273 try {
2274 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2275
2276 /* a final detail: this is the one and only place that we know how long missing files are */
2277
2278 if (region->whole_file()) {
2279 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2280 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2281 if (sfp) {
2282 sfp->set_length (region->length());
2283 }
2284 }
2285 }
2286
2287 if (!master_sources.empty()) {
2288 if (master_sources.size() != nchans) {
2289 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2290 } else {
2291 region->set_master_sources (master_sources);
2292 }
2293 }
2294
2295 return region;
2296
2297 }
2298
2299 catch (failed_constructor& err) {
2300 return boost::shared_ptr<AudioRegion>();
2301 }
2302 }
2303
2304 boost::shared_ptr<MidiRegion>
XMLMidiRegionFactory(const XMLNode & node,bool)2305 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2306 {
2307 XMLProperty const * prop;
2308 boost::shared_ptr<Source> source;
2309 boost::shared_ptr<MidiSource> ms;
2310 SourceList sources;
2311
2312 if (node.name() != X_("Region")) {
2313 return boost::shared_ptr<MidiRegion>();
2314 }
2315
2316 if ((prop = node.property ("name")) == 0) {
2317 cerr << "no name for this region\n";
2318 abort ();
2319 }
2320
2321 if ((prop = node.property (X_("source-0"))) == 0) {
2322 if ((prop = node.property ("source")) == 0) {
2323 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2324 return boost::shared_ptr<MidiRegion>();
2325 }
2326 }
2327
2328 PBD::ID s_id (prop->value());
2329
2330 if ((source = source_by_id (s_id)) == 0) {
2331 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2332 return boost::shared_ptr<MidiRegion>();
2333 }
2334
2335 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2336 if (!ms) {
2337 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2338 return boost::shared_ptr<MidiRegion>();
2339 }
2340
2341 sources.push_back (ms);
2342
2343 try {
2344 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2345 /* a final detail: this is the one and only place that we know how long missing files are */
2346
2347 if (region->whole_file()) {
2348 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2349 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2350 if (sfp) {
2351 sfp->set_length (region->length());
2352 }
2353 }
2354 }
2355
2356 return region;
2357 }
2358
2359 catch (failed_constructor& err) {
2360 return boost::shared_ptr<MidiRegion>();
2361 }
2362 }
2363
2364 XMLNode&
get_sources_as_xml()2365 Session::get_sources_as_xml ()
2366
2367 {
2368 XMLNode* node = new XMLNode (X_("Sources"));
2369 Glib::Threads::Mutex::Lock lm (source_lock);
2370
2371 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
2372 node->add_child_nocopy (i->second->get_state());
2373 }
2374
2375 return *node;
2376 }
2377
2378 void
reset_write_sources(bool mark_write_complete,bool force)2379 Session::reset_write_sources (bool mark_write_complete, bool force)
2380 {
2381 boost::shared_ptr<RouteList> rl = routes.reader();
2382 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2383 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2384 if (tr) {
2385 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
2386 tr->reset_write_sources(mark_write_complete, force);
2387 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2388 }
2389 }
2390 }
2391
2392 int
load_sources(const XMLNode & node)2393 Session::load_sources (const XMLNode& node)
2394 {
2395 XMLNodeList nlist;
2396 XMLNodeConstIterator niter;
2397 /* don't need this but it stops some
2398 * versions of gcc complaining about
2399 * discarded return values.
2400 */
2401 boost::shared_ptr<Source> source;
2402
2403 nlist = node.children();
2404
2405 set_dirty();
2406 std::map<std::string, std::string> relocation;
2407
2408 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2409 #ifdef PLATFORM_WINDOWS
2410 int old_mode = 0;
2411 #endif
2412
2413 XMLNode srcnode (**niter);
2414 bool try_replace_abspath = true;
2415
2416 retry:
2417 try {
2418 #ifdef PLATFORM_WINDOWS
2419 // do not show "insert media" popups (files embedded from removable media).
2420 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2421 #endif
2422 if ((source = XMLSourceFactory (srcnode)) == 0) {
2423 error << _("Session: cannot create Source from XML description.") << endmsg;
2424 }
2425 #ifdef PLATFORM_WINDOWS
2426 SetErrorMode(old_mode);
2427 #endif
2428
2429 } catch (MissingSource& err) {
2430 #ifdef PLATFORM_WINDOWS
2431 SetErrorMode(old_mode);
2432 #endif
2433
2434 /* try previous abs path replacements first */
2435 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2436 std::string dir = Glib::path_get_dirname (err.path);
2437 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2438 if (rl != relocation.end ()) {
2439 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2440 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2441 srcnode.set_property ("origin", newpath);
2442 try_replace_abspath = false;
2443 goto retry;
2444 }
2445 }
2446 }
2447
2448 int user_choice;
2449 _missing_file_replacement = "";
2450
2451 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2452 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2453 PROGRAM_NAME) << endmsg;
2454 return -1;
2455 }
2456
2457 if (!no_questions_about_missing_files) {
2458 user_choice = MissingFile (this, err.path, err.type).value_or (-1);
2459 } else {
2460 user_choice = -2;
2461 }
2462
2463 switch (user_choice) {
2464 case 0:
2465 /* user added a new search location
2466 * or selected a new absolute path,
2467 * so try again */
2468 if (Glib::path_is_absolute (err.path)) {
2469 if (!_missing_file_replacement.empty ()) {
2470 /* replace origin, in XML */
2471 std::string newpath = Glib::build_filename (
2472 _missing_file_replacement, Glib::path_get_basename (err.path));
2473 srcnode.set_property ("origin", newpath);
2474 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2475 _missing_file_replacement = "";
2476 }
2477 }
2478 goto retry;
2479
2480
2481 case 1:
2482 /* user asked to quit the entire session load */
2483 return -1;
2484
2485 case 2:
2486 no_questions_about_missing_files = true;
2487 goto retry;
2488
2489 case 3:
2490 no_questions_about_missing_files = true;
2491 /* fallthrough */
2492
2493 case -1:
2494 default:
2495 switch (err.type) {
2496
2497 case DataType::AUDIO:
2498 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2499 break;
2500
2501 case DataType::MIDI:
2502 /* The MIDI file is actually missing so
2503 * just create a new one in the same
2504 * location. Do not announce its
2505 */
2506 string fullpath;
2507
2508 if (!Glib::path_is_absolute (err.path)) {
2509 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2510 } else {
2511 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2512 * the session tree.
2513 */
2514 return -1;
2515 }
2516 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2517 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, _current_sample_rate, false, false);
2518 /* reset ID to match the missing one */
2519 source->set_id (**niter);
2520 /* Now we can announce it */
2521 SourceFactory::SourceCreated (source);
2522 break;
2523 }
2524 break;
2525 }
2526 }
2527 }
2528
2529 return 0;
2530 }
2531
2532 boost::shared_ptr<Source>
XMLSourceFactory(const XMLNode & node)2533 Session::XMLSourceFactory (const XMLNode& node)
2534 {
2535 if (node.name() != "Source") {
2536 return boost::shared_ptr<Source>();
2537 }
2538
2539 try {
2540 /* note: do peak building in another thread when loading session state */
2541 return SourceFactory::create (*this, node, true);
2542 }
2543
2544 catch (failed_constructor& err) {
2545 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2546 return boost::shared_ptr<Source>();
2547 }
2548 }
2549
2550 int
save_template(const string & template_name,const string & description,bool replace_existing)2551 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2552 {
2553 if (cannot_save () || template_name.empty ()) {
2554 return -1;
2555 }
2556
2557 bool absolute_path = Glib::path_is_absolute (template_name);
2558
2559 /* directory to put the template in */
2560 std::string template_dir_path;
2561
2562 if (!absolute_path) {
2563 std::string user_template_dir(user_template_directory());
2564
2565 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2566 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2567 user_template_dir, g_strerror (errno)) << endmsg;
2568 return -1;
2569 }
2570
2571 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2572 } else {
2573 template_dir_path = template_name;
2574 }
2575
2576 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2577 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2578 template_dir_path) << endmsg;
2579 return -2;
2580 }
2581
2582 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2583 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2584 template_dir_path, g_strerror (errno)) << endmsg;
2585 return -1;
2586 }
2587
2588 /* file to write */
2589 std::string template_file_path;
2590
2591 if (absolute_path) {
2592 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2593 } else {
2594 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2595 }
2596
2597 SessionSaveUnderway (); /* EMIT SIGNAL */
2598
2599 XMLTree tree;
2600 XMLNode* root;
2601 {
2602 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2603 root = &get_template ();
2604 }
2605
2606 root->remove_nodes_and_delete (X_("description"));
2607
2608 if (!description.empty()) {
2609 XMLNode* desc = new XMLNode (X_("description"));
2610 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2611 desc->add_child_nocopy (*desc_cont);
2612
2613 root->add_child_nocopy (*desc);
2614 }
2615
2616 tree.set_root (root);
2617
2618 if (!tree.write (template_file_path)) {
2619 error << _("template not saved") << endmsg;
2620 return -1;
2621 }
2622
2623 store_recent_templates (template_file_path);
2624
2625 return 0;
2626 }
2627
2628 void
refresh_disk_space()2629 Session::refresh_disk_space ()
2630 {
2631 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2632
2633 Glib::Threads::Mutex::Lock lm (space_lock);
2634
2635 /* get freespace on every FS that is part of the session path */
2636
2637 _total_free_4k_blocks = 0;
2638 _total_free_4k_blocks_uncertain = false;
2639
2640 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2641 #if defined(__NetBSD__)
2642 struct statvfs statfsbuf;
2643
2644 statvfs (i->path.c_str(), &statfsbuf);
2645 #else
2646 struct statfs statfsbuf;
2647
2648 statfs (i->path.c_str(), &statfsbuf);
2649 #endif
2650 double const scale = statfsbuf.f_bsize / 4096.0;
2651
2652 /* See if this filesystem is read-only */
2653 struct statvfs statvfsbuf;
2654 statvfs (i->path.c_str(), &statvfsbuf);
2655
2656 /* f_bavail can be 0 if it is undefined for whatever
2657 filesystem we are looking at; Samba shares mounted
2658 via GVFS are an example of this.
2659 */
2660 if (statfsbuf.f_bavail == 0) {
2661 /* block count unknown */
2662 i->blocks = 0;
2663 i->blocks_unknown = true;
2664 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2665 /* read-only filesystem */
2666 i->blocks = 0;
2667 i->blocks_unknown = false;
2668 } else {
2669 /* read/write filesystem with known space */
2670 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2671 i->blocks_unknown = false;
2672 }
2673
2674 _total_free_4k_blocks += i->blocks;
2675 if (i->blocks_unknown) {
2676 _total_free_4k_blocks_uncertain = true;
2677 }
2678 }
2679 #elif defined PLATFORM_WINDOWS
2680 vector<string> scanned_volumes;
2681 vector<string>::iterator j;
2682 vector<space_and_path>::iterator i;
2683 DWORD nSectorsPerCluster, nBytesPerSector,
2684 nFreeClusters, nTotalClusters;
2685 char disk_drive[4];
2686 bool volume_found;
2687
2688 _total_free_4k_blocks = 0;
2689
2690 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2691 strncpy (disk_drive, (*i).path.c_str(), 3);
2692 disk_drive[3] = 0;
2693 strupr(disk_drive);
2694
2695 volume_found = false;
2696 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2697 {
2698 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2699 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2700 i->blocks = (uint32_t)(nFreeBytes / 4096);
2701
2702 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2703 if (0 == j->compare(disk_drive)) {
2704 volume_found = true;
2705 break;
2706 }
2707 }
2708
2709 if (!volume_found) {
2710 scanned_volumes.push_back(disk_drive);
2711 _total_free_4k_blocks += i->blocks;
2712 }
2713 }
2714 }
2715
2716 if (0 == _total_free_4k_blocks) {
2717 strncpy (disk_drive, path().c_str(), 3);
2718 disk_drive[3] = 0;
2719
2720 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2721 {
2722 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2723 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2724 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2725 }
2726 }
2727 #endif
2728 }
2729
2730 string
get_best_session_directory_for_new_audio()2731 Session::get_best_session_directory_for_new_audio ()
2732 {
2733 vector<space_and_path>::iterator i;
2734 string result = _session_dir->root_path();
2735
2736 /* handle common case without system calls */
2737
2738 if (session_dirs.size() == 1) {
2739 return result;
2740 }
2741
2742 /* OK, here's the algorithm we're following here:
2743
2744 We want to select which directory to use for
2745 the next file source to be created. Ideally,
2746 we'd like to use a round-robin process so as to
2747 get maximum performance benefits from splitting
2748 the files across multiple disks.
2749
2750 However, in situations without much diskspace, an
2751 RR approach may end up filling up a filesystem
2752 with new files while others still have space.
2753 Its therefore important to pay some attention to
2754 the freespace in the filesystem holding each
2755 directory as well. However, if we did that by
2756 itself, we'd keep creating new files in the file
2757 system with the most space until it was as full
2758 as all others, thus negating any performance
2759 benefits of this RAID-1 like approach.
2760
2761 So, we use a user-configurable space threshold. If
2762 there are at least 2 filesystems with more than this
2763 much space available, we use RR selection between them.
2764 If not, then we pick the filesystem with the most space.
2765
2766 This gets a good balance between the two
2767 approaches.
2768 */
2769
2770 refresh_disk_space ();
2771
2772 int free_enough = 0;
2773
2774 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2775 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2776 free_enough++;
2777 }
2778 }
2779
2780 if (free_enough >= 2) {
2781 /* use RR selection process, ensuring that the one
2782 picked works OK.
2783 */
2784
2785 i = last_rr_session_dir;
2786
2787 do {
2788 if (++i == session_dirs.end()) {
2789 i = session_dirs.begin();
2790 }
2791
2792 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2793 SessionDirectory sdir(i->path);
2794 if (sdir.create ()) {
2795 result = (*i).path;
2796 last_rr_session_dir = i;
2797 return result;
2798 }
2799 }
2800
2801 } while (i != last_rr_session_dir);
2802
2803 } else {
2804
2805 /* pick FS with the most freespace (and that
2806 seems to actually work ...)
2807 */
2808
2809 vector<space_and_path> sorted;
2810 space_and_path_ascending_cmp cmp;
2811
2812 sorted = session_dirs;
2813 sort (sorted.begin(), sorted.end(), cmp);
2814
2815 for (i = sorted.begin(); i != sorted.end(); ++i) {
2816 SessionDirectory sdir(i->path);
2817 if (sdir.create ()) {
2818 result = (*i).path;
2819 last_rr_session_dir = i;
2820 return result;
2821 }
2822 }
2823 }
2824
2825 return result;
2826 }
2827
2828 string
automation_dir() const2829 Session::automation_dir () const
2830 {
2831 return Glib::build_filename (_path, automation_dir_name);
2832 }
2833
2834 string
analysis_dir() const2835 Session::analysis_dir () const
2836 {
2837 return Glib::build_filename (_path, analysis_dir_name);
2838 }
2839
2840 string
plugins_dir() const2841 Session::plugins_dir () const
2842 {
2843 return Glib::build_filename (_path, plugins_dir_name);
2844 }
2845
2846 string
externals_dir() const2847 Session::externals_dir () const
2848 {
2849 return Glib::build_filename (_path, externals_dir_name);
2850 }
2851
2852 int
load_bundles(XMLNode const & node)2853 Session::load_bundles (XMLNode const & node)
2854 {
2855 XMLNodeList nlist = node.children();
2856 XMLNodeConstIterator niter;
2857
2858 set_dirty();
2859
2860 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2861 if ((*niter)->name() == "InputBundle") {
2862 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2863 } else if ((*niter)->name() == "OutputBundle") {
2864 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2865 } else {
2866 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2867 return -1;
2868 }
2869 }
2870
2871 return 0;
2872 }
2873
2874 int
load_route_groups(const XMLNode & node,int version)2875 Session::load_route_groups (const XMLNode& node, int version)
2876 {
2877 XMLNodeList nlist = node.children();
2878 XMLNodeConstIterator niter;
2879
2880 set_dirty ();
2881
2882 if (version >= 3000) {
2883
2884 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2885 if ((*niter)->name() == "RouteGroup") {
2886 RouteGroup* rg = new RouteGroup (*this, "");
2887 add_route_group (rg);
2888 rg->set_state (**niter, version);
2889 }
2890 }
2891
2892 } else if (version < 3000) {
2893
2894 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2895 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2896 RouteGroup* rg = new RouteGroup (*this, "");
2897 add_route_group (rg);
2898 rg->set_state (**niter, version);
2899 }
2900 }
2901 }
2902
2903 return 0;
2904 }
2905
2906 static bool
state_file_filter(const string & str,void *)2907 state_file_filter (const string &str, void* /*arg*/)
2908 {
2909 return (str.length() > strlen(statefile_suffix) &&
2910 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2911 }
2912
2913 static string
remove_end(string state)2914 remove_end(string state)
2915 {
2916 string statename(state);
2917
2918 string::size_type start,end;
2919 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2920 statename = statename.substr (start+1);
2921 }
2922
2923 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2924 end = statename.length();
2925 }
2926
2927 return string(statename.substr (0, end));
2928 }
2929
2930 vector<string>
possible_states(string path)2931 Session::possible_states (string path)
2932 {
2933 vector<string> states;
2934 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2935
2936 transform(states.begin(), states.end(), states.begin(), remove_end);
2937
2938 sort (states.begin(), states.end());
2939
2940 return states;
2941 }
2942
2943 vector<string>
possible_states() const2944 Session::possible_states () const
2945 {
2946 return possible_states(_path);
2947 }
2948
2949 RouteGroup*
new_route_group(const std::string & name)2950 Session::new_route_group (const std::string& name)
2951 {
2952 RouteGroup* rg = NULL;
2953
2954 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2955 if ((*i)->name () == name) {
2956 rg = *i;
2957 break;
2958 }
2959 }
2960
2961 if (!rg) {
2962 rg = new RouteGroup (*this, name);
2963 add_route_group (rg);
2964 }
2965 return (rg);
2966 }
2967
2968 void
add_route_group(RouteGroup * g)2969 Session::add_route_group (RouteGroup* g)
2970 {
2971 _route_groups.push_back (g);
2972 route_group_added (g); /* EMIT SIGNAL */
2973
2974 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2975 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2976 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2977
2978 set_dirty ();
2979 }
2980
2981 void
remove_route_group(RouteGroup & rg)2982 Session::remove_route_group (RouteGroup& rg)
2983 {
2984 list<RouteGroup*>::iterator i;
2985
2986 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2987 _route_groups.erase (i);
2988 delete &rg;
2989
2990 route_group_removed (); /* EMIT SIGNAL */
2991 }
2992 }
2993
2994 /** Set a new order for our route groups, without adding or removing any.
2995 * @param groups Route group list in the new order.
2996 */
2997 void
reorder_route_groups(list<RouteGroup * > groups)2998 Session::reorder_route_groups (list<RouteGroup*> groups)
2999 {
3000 _route_groups = groups;
3001
3002 route_groups_reordered (); /* EMIT SIGNAL */
3003 set_dirty ();
3004 }
3005
3006
3007 RouteGroup *
route_group_by_name(string name)3008 Session::route_group_by_name (string name)
3009 {
3010 list<RouteGroup *>::iterator i;
3011
3012 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
3013 if ((*i)->name() == name) {
3014 return* i;
3015 }
3016 }
3017 return 0;
3018 }
3019
3020 RouteGroup&
all_route_group() const3021 Session::all_route_group() const
3022 {
3023 return *_all_route_group;
3024 }
3025
3026 void
add_commands(vector<Command * > const & cmds)3027 Session::add_commands (vector<Command*> const & cmds)
3028 {
3029 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
3030 add_command (*i);
3031 }
3032 }
3033
3034 void
add_command(Command * const cmd)3035 Session::add_command (Command* const cmd)
3036 {
3037 assert (_current_trans);
3038 DEBUG_UNDO_HISTORY (
3039 string_compose ("Current Undo Transaction %1, adding command: %2",
3040 _current_trans->name (),
3041 cmd->name ()));
3042 _current_trans->add_command (cmd);
3043 }
3044
3045 PBD::StatefulDiffCommand*
add_stateful_diff_command(boost::shared_ptr<PBD::StatefulDestructible> sfd)3046 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
3047 {
3048 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
3049 add_command (cmd);
3050 return cmd;
3051 }
3052
3053 void
begin_reversible_command(const string & name)3054 Session::begin_reversible_command (const string& name)
3055 {
3056 begin_reversible_command (g_quark_from_string (name.c_str ()));
3057 }
3058
3059 /** Begin a reversible command using a GQuark to identify it.
3060 * begin_reversible_command() and commit_reversible_command() calls may be nested,
3061 * but there must be as many begin...()s as there are commit...()s.
3062 */
3063 void
begin_reversible_command(GQuark q)3064 Session::begin_reversible_command (GQuark q)
3065 {
3066 /* If nested begin/commit pairs are used, we create just one UndoTransaction
3067 to hold all the commands that are committed. This keeps the order of
3068 commands correct in the history.
3069 */
3070
3071 if (_current_trans == 0) {
3072 DEBUG_UNDO_HISTORY (string_compose (
3073 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
3074
3075 /* start a new transaction */
3076 assert (_current_trans_quarks.empty ());
3077 _current_trans = new UndoTransaction();
3078 _current_trans->set_name (g_quark_to_string (q));
3079 } else {
3080 DEBUG_UNDO_HISTORY (
3081 string_compose ("Begin Reversible Command, current transaction: %1",
3082 _current_trans->name ()));
3083 }
3084
3085 _current_trans_quarks.push_front (q);
3086 }
3087
3088 void
abort_reversible_command()3089 Session::abort_reversible_command ()
3090 {
3091 if (_current_trans != 0) {
3092 DEBUG_UNDO_HISTORY (
3093 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3094 _current_trans->clear();
3095 delete _current_trans;
3096 _current_trans = 0;
3097 _current_trans_quarks.clear();
3098 }
3099 }
3100
3101 bool
abort_empty_reversible_command()3102 Session::abort_empty_reversible_command ()
3103 {
3104 if (!collected_undo_commands ()) {
3105 abort_reversible_command ();
3106 return true;
3107 }
3108 return false;
3109 }
3110
3111 void
commit_reversible_command(Command * cmd)3112 Session::commit_reversible_command (Command *cmd)
3113 {
3114 assert (_current_trans);
3115 assert (!_current_trans_quarks.empty ());
3116
3117 struct timeval now;
3118
3119 if (cmd) {
3120 DEBUG_UNDO_HISTORY (
3121 string_compose ("Current Undo Transaction %1, adding command: %2",
3122 _current_trans->name (),
3123 cmd->name ()));
3124 _current_trans->add_command (cmd);
3125 }
3126
3127 DEBUG_UNDO_HISTORY (
3128 string_compose ("Commit Reversible Command, current transaction: %1",
3129 _current_trans->name ()));
3130
3131 _current_trans_quarks.pop_front ();
3132
3133 if (!_current_trans_quarks.empty ()) {
3134 DEBUG_UNDO_HISTORY (
3135 string_compose ("Commit Reversible Command, transaction is not "
3136 "top-level, current transaction: %1",
3137 _current_trans->name ()));
3138 /* the transaction we're committing is not the top-level one */
3139 return;
3140 }
3141
3142 if (_current_trans->empty()) {
3143 /* no commands were added to the transaction, so just get rid of it */
3144 DEBUG_UNDO_HISTORY (
3145 string_compose ("Commit Reversible Command, No commands were "
3146 "added to current transaction: %1",
3147 _current_trans->name ()));
3148 delete _current_trans;
3149 _current_trans = 0;
3150 return;
3151 }
3152
3153 gettimeofday (&now, 0);
3154 _current_trans->set_timestamp (now);
3155
3156 _history.add (_current_trans);
3157 _current_trans = 0;
3158 }
3159
3160 static bool
accept_all_audio_files(const string & path,void *)3161 accept_all_audio_files (const string& path, void* /*arg*/)
3162 {
3163 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3164 return false;
3165 }
3166
3167 if (!AudioFileSource::safe_audio_file_extension (path)) {
3168 return false;
3169 }
3170
3171 return true;
3172 }
3173
3174 static bool
accept_all_midi_files(const string & path,void *)3175 accept_all_midi_files (const string& path, void* /*arg*/)
3176 {
3177 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3178 return false;
3179 }
3180
3181 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3182 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3183 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3184 }
3185
3186 static bool
accept_all_state_files(const string & path,void *)3187 accept_all_state_files (const string& path, void* /*arg*/)
3188 {
3189 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3190 return false;
3191 }
3192
3193 std::string const statefile_ext (statefile_suffix);
3194 if (path.length() >= statefile_ext.length()) {
3195 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3196 } else {
3197 return false;
3198 }
3199 }
3200
3201 int
find_all_sources(string path,set<string> & result)3202 Session::find_all_sources (string path, set<string>& result)
3203 {
3204 XMLTree tree;
3205 XMLNode* node;
3206
3207 if (!tree.read (path)) {
3208 return -1;
3209 }
3210
3211 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3212 return -2;
3213 }
3214
3215 XMLNodeList nlist;
3216 XMLNodeConstIterator niter;
3217
3218 nlist = node->children();
3219
3220 set_dirty();
3221
3222 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3223
3224 XMLProperty const * prop;
3225
3226 if ((prop = (*niter)->property (X_("type"))) == 0) {
3227 continue;
3228 }
3229
3230 DataType type (prop->value());
3231
3232 if ((prop = (*niter)->property (X_("name"))) == 0) {
3233 continue;
3234 }
3235
3236 if (Glib::path_is_absolute (prop->value())) {
3237 /* external file, ignore */
3238 continue;
3239 }
3240
3241 string found_path;
3242 bool is_new;
3243 uint16_t chan;
3244
3245 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3246 result.insert (found_path);
3247 }
3248 }
3249
3250 return 0;
3251 }
3252
3253 int
find_all_sources_across_snapshots(set<string> & result,bool exclude_this_snapshot)3254 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3255 {
3256 vector<string> state_files;
3257 string ripped;
3258 string this_snapshot_path;
3259
3260 result.clear ();
3261
3262 ripped = _path;
3263
3264 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3265 ripped = ripped.substr (0, ripped.length() - 1);
3266 }
3267
3268 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3269
3270 if (state_files.empty()) {
3271 /* impossible! */
3272 return 0;
3273 }
3274
3275 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3276 this_snapshot_path += statefile_suffix;
3277
3278 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3279
3280 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3281
3282 if (exclude_this_snapshot && *i == this_snapshot_path) {
3283 cerr << "\texcluded\n";
3284 continue;
3285
3286 }
3287
3288 if (find_all_sources (*i, result) < 0) {
3289 return -1;
3290 }
3291 }
3292
3293 return 0;
3294 }
3295
3296 struct RegionCounter {
3297 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3298 AudioSourceList::iterator iter;
3299 boost::shared_ptr<Region> region;
3300 uint32_t count;
3301
RegionCounterRegionCounter3302 RegionCounter() : count (0) {}
3303 };
3304
3305 int
ask_about_playlist_deletion(boost::shared_ptr<Playlist> p)3306 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3307 {
3308 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3309 return r.value_or (1);
3310 }
3311
3312 void
cleanup_regions()3313 Session::cleanup_regions ()
3314 {
3315 bool removed = false;
3316 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3317
3318 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3319
3320 uint32_t used = _playlists->region_use_count (i->second);
3321
3322 if (used == 0 && !i->second->automatic ()) {
3323 boost::weak_ptr<Region> w = i->second;
3324 ++i;
3325 removed = true;
3326 RegionFactory::map_remove (w);
3327 } else {
3328 ++i;
3329 }
3330 }
3331
3332 if (removed) {
3333 // re-check to remove parent references of compound regions
3334 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3335 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3336 ++i;
3337 continue;
3338 }
3339 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3340 if (0 == _playlists->region_use_count (i->second)) {
3341 boost::weak_ptr<Region> w = i->second;
3342 ++i;
3343 RegionFactory::map_remove (w);
3344 } else {
3345 ++i;
3346 }
3347 }
3348 }
3349 }
3350
3351 bool
can_cleanup_peakfiles() const3352 Session::can_cleanup_peakfiles () const
3353 {
3354 if (deletion_in_progress()) {
3355 return false;
3356 }
3357 if (!_writable || cannot_save ()) {
3358 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3359 return false;
3360 }
3361 if (record_status() == Recording) {
3362 error << _("Cannot cleanup peak-files while recording") << endmsg;
3363 return false;
3364 }
3365 return true;
3366 }
3367
3368 int
cleanup_peakfiles()3369 Session::cleanup_peakfiles ()
3370 {
3371 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3372 if (!lm.locked()) {
3373 return -1;
3374 }
3375
3376 assert (can_cleanup_peakfiles ());
3377 assert (!peaks_cleanup_in_progres());
3378
3379 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3380
3381 int timeout = 5000; // 5 seconds
3382 while (!SourceFactory::files_with_peaks.empty()) {
3383 Glib::usleep (1000);
3384 if (--timeout < 0) {
3385 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3386 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3387 return -1;
3388 }
3389 }
3390
3391 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3392 boost::shared_ptr<AudioSource> as;
3393 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3394 as->close_peakfile();
3395 }
3396 }
3397
3398 PBD::clear_directory (session_directory().peak_path());
3399
3400 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3401
3402 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3403 boost::shared_ptr<AudioSource> as;
3404 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3405 SourceFactory::setup_peakfile(as, true);
3406 }
3407 }
3408 return 0;
3409 }
3410
3411 int
cleanup_sources(CleanupReport & rep)3412 Session::cleanup_sources (CleanupReport& rep)
3413 {
3414 // FIXME: needs adaptation to midi
3415
3416 SourceList dead_sources;
3417 string audio_path;
3418 string midi_path;
3419 vector<string> candidates;
3420 vector<string> unused;
3421 set<string> sources_used_by_all_snapshots;
3422 string spath;
3423 int ret = -1;
3424 string tmppath1;
3425 string tmppath2;
3426 Searchpath asp;
3427 Searchpath msp;
3428 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3429
3430 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
3431
3432 Glib::Threads::Mutex::Lock ls (source_lock, Glib::Threads::NOT_LOCK);
3433
3434 /* this is mostly for windows which doesn't allow file
3435 * renaming if the file is in use. But we don't special
3436 * case it because we need to know if this causes
3437 * problems, and the easiest way to notice that is to
3438 * keep it in place for all platforms.
3439 */
3440
3441 request_stop (false);
3442 _butler->summon ();
3443 _butler->wait_until_finished ();
3444
3445 /* consider deleting all unused playlists */
3446
3447 if (_playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3448 ret = 0;
3449 goto out;
3450 }
3451
3452 /* sync the "all regions" property of each playlist with its current state */
3453
3454 _playlists->sync_all_regions_with_regions ();
3455
3456 /* find all un-used sources */
3457
3458 rep.paths.clear ();
3459 rep.space = 0;
3460
3461 ls.acquire ();
3462 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3463
3464 SourceMap::iterator tmp;
3465
3466 tmp = i;
3467 ++tmp;
3468
3469 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3470 * capture files.
3471 */
3472
3473 if (!i->second->used() && (i->second->length(i->second->natural_position()) > 0)) {
3474 dead_sources.push_back (i->second);
3475 }
3476
3477 i = tmp;
3478 }
3479 ls.release ();
3480
3481 /* build a list of all the possible audio directories for the session */
3482
3483 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3484 SessionDirectory sdir ((*i).path);
3485 asp += sdir.sound_path();
3486 }
3487 audio_path += asp.to_string();
3488
3489
3490 /* build a list of all the possible midi directories for the session */
3491
3492 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3493 SessionDirectory sdir ((*i).path);
3494 msp += sdir.midi_path();
3495 }
3496 midi_path += msp.to_string();
3497
3498 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3499 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3500
3501 /* add sources from all other snapshots as "used", but don't use this
3502 snapshot because the state file on disk still references sources we
3503 may have already dropped.
3504 */
3505
3506 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3507
3508 /* Although the region factory has a list of all regions ever created
3509 * for this session, we're only interested in regions actually in
3510 * playlists right now. So merge all playlist regions lists together.
3511 *
3512 * This will include the playlists used within compound regions.
3513 */
3514
3515 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3516
3517 /* add our current source list
3518 */
3519
3520 ls.acquire ();
3521 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3522 boost::shared_ptr<FileSource> fs;
3523 SourceMap::iterator tmp = i;
3524 ++tmp;
3525
3526 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3527 /* not a file */
3528 i = tmp;
3529 continue;
3530 }
3531
3532 /* this is mostly for windows which doesn't allow file
3533 * renaming if the file is in use. But we do not special
3534 * case it because we need to know if this causes
3535 * problems, and the easiest way to notice that is to
3536 * keep it in place for all platforms.
3537 */
3538
3539 fs->close ();
3540
3541 if (!fs->is_stub()) {
3542
3543 /* Note that we're checking a list of all
3544 * sources across all snapshots with the list
3545 * of sources used by this snapshot.
3546 */
3547
3548 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3549 /* this source is in use by this snapshot */
3550 sources_used_by_all_snapshots.insert (fs->path());
3551 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3552 } else {
3553 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3554 /* this source is NOT in use by this snapshot */
3555
3556 /* remove all related regions from RegionFactory master list */
3557
3558 RegionFactory::remove_regions_using_source (i->second);
3559
3560 /* remove from our current source list
3561 * also. We may not remove it from
3562 * disk, because it may be used by
3563 * other snapshots, but it isn't used inside this
3564 * snapshot anymore, so we don't need a
3565 * reference to it.
3566 */
3567
3568 dead_sources.push_back (i->second);
3569 sources.erase (i);
3570 }
3571 }
3572
3573 i = tmp;
3574 }
3575 ls.release ();
3576
3577 for (SourceList::iterator i = dead_sources.begin(); i != dead_sources.end(); ++i) {
3578 /* The following triggers Region::source_deleted (), which
3579 * causes regions to drop the given source */
3580 (*i)->drop_references ();
3581 SourceRemoved (*i); /* EMIT SIGNAL */
3582 }
3583
3584 /* now check each candidate source to see if it exists in the list of
3585 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3586 */
3587
3588 cerr << "Candidates: " << candidates.size() << endl;
3589 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3590
3591 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3592
3593 bool used = false;
3594 spath = *x;
3595
3596 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3597
3598 tmppath1 = canonical_path (spath);
3599 tmppath2 = canonical_path ((*i));
3600
3601 cerr << "\t => " << tmppath2 << endl;
3602
3603 if (tmppath1 == tmppath2) {
3604 used = true;
3605 break;
3606 }
3607 }
3608
3609 if (!used) {
3610 unused.push_back (spath);
3611 }
3612 }
3613
3614 cerr << "Actually unused: " << unused.size() << endl;
3615
3616 if (unused.empty()) {
3617 /* Nothing to do */
3618 ret = 0;
3619 goto out;
3620 }
3621
3622 /* now try to move all unused files into the "dead" directory(ies) */
3623
3624 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3625 GStatBuf statbuf;
3626
3627 string newpath;
3628
3629 /* don't move the file across filesystems, just
3630 * stick it in the `dead_dir_name' directory
3631 * on whichever filesystem it was already on.
3632 */
3633
3634 if ((*x).find ("/sounds/") != string::npos) {
3635
3636 /* old school, go up 1 level */
3637
3638 newpath = Glib::path_get_dirname (*x); // "sounds"
3639 newpath = Glib::path_get_dirname (newpath); // "session-name"
3640
3641 } else {
3642
3643 /* new school, go up 4 levels */
3644
3645 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3646 newpath = Glib::path_get_dirname (newpath); // "session-name"
3647 newpath = Glib::path_get_dirname (newpath); // "interchange"
3648 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3649 }
3650
3651 newpath = Glib::build_filename (newpath, dead_dir_name);
3652
3653 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3654 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3655 return -1;
3656 }
3657
3658 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3659
3660 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3661
3662 /* the new path already exists, try versioning */
3663
3664 char buf[PATH_MAX+1];
3665 int version = 1;
3666 string newpath_v;
3667
3668 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3669 newpath_v = buf;
3670
3671 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3672 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3673 newpath_v = buf;
3674 }
3675
3676 if (version == 999) {
3677 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3678 newpath)
3679 << endmsg;
3680 } else {
3681 newpath = newpath_v;
3682 }
3683
3684 }
3685
3686 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3687 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3688 newpath, g_strerror (errno)) << endmsg;
3689 continue;
3690 }
3691
3692 /* see if there an easy to find peakfile for this file, and remove it. */
3693
3694 string base = Glib::path_get_basename (*x);
3695 base += "%A"; /* this is what we add for the channel suffix of all native files,
3696 * or for the first channel of embedded files. it will miss
3697 * some peakfiles for other channels
3698 */
3699 string peakpath = construct_peak_filepath (base);
3700
3701 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3702 if (::g_unlink (peakpath.c_str ()) != 0) {
3703 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3704 g_strerror (errno)) << endmsg;
3705 /* try to back out */
3706 ::g_rename (newpath.c_str (), _path.c_str ());
3707 goto out;
3708 }
3709 }
3710
3711 rep.paths.push_back (*x);
3712 rep.space += statbuf.st_size;
3713 }
3714
3715 /* drop last Source references */
3716 dead_sources.clear ();
3717
3718 /* dump the history list, remove references */
3719
3720 _history.clear ();
3721
3722 /* save state so we don't end up a session file
3723 * referring to non-existent sources.
3724 */
3725
3726 save_state ();
3727 ret = 0;
3728
3729 out:
3730 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
3731
3732 return ret;
3733 }
3734
3735 int
cleanup_trash_sources(CleanupReport & rep)3736 Session::cleanup_trash_sources (CleanupReport& rep)
3737 {
3738 // FIXME: needs adaptation for MIDI
3739
3740 vector<space_and_path>::iterator i;
3741 string dead_dir;
3742
3743 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3744
3745 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3746
3747 clear_directory (dead_dir, &rep.space, &rep.paths);
3748 }
3749
3750 return 0;
3751 }
3752
3753 void
set_dirty()3754 Session::set_dirty ()
3755 {
3756 /* return early if there's nothing to do */
3757 if (dirty ()) {
3758 return;
3759 }
3760
3761 /* never mark session dirty during loading */
3762 if (loading () || deletion_in_progress ()) {
3763 return;
3764 }
3765
3766 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3767 DirtyChanged(); /* EMIT SIGNAL */
3768 }
3769
3770 void
set_clean()3771 Session::set_clean ()
3772 {
3773 bool was_dirty = dirty();
3774
3775 _state_of_the_state = Clean;
3776
3777 if (was_dirty) {
3778 DirtyChanged(); /* EMIT SIGNAL */
3779 }
3780 }
3781
3782 void
unset_dirty(bool emit_dirty_changed)3783 Session::unset_dirty (bool emit_dirty_changed)
3784 {
3785 bool was_dirty = dirty();
3786
3787 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Dirty));
3788
3789 if (was_dirty && emit_dirty_changed) {
3790 DirtyChanged (); /* EMIT SIGNAL */
3791 }
3792 }
3793
3794 void
set_deletion_in_progress()3795 Session::set_deletion_in_progress ()
3796 {
3797 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3798 }
3799
3800 void
clear_deletion_in_progress()3801 Session::clear_deletion_in_progress ()
3802 {
3803 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3804 }
3805
3806 void
add_controllable(boost::shared_ptr<Controllable> c)3807 Session::add_controllable (boost::shared_ptr<Controllable> c)
3808 {
3809 /* this adds a controllable to the list managed by the Session.
3810 this is a subset of those managed by the Controllable class
3811 itself, and represents the only ones whose state will be saved
3812 as part of the session.
3813 */
3814
3815 Glib::Threads::Mutex::Lock lm (controllables_lock);
3816 controllables.insert (c);
3817 }
3818
3819 boost::shared_ptr<Controllable>
controllable_by_id(const PBD::ID & id)3820 Session::controllable_by_id (const PBD::ID& id)
3821 {
3822 Glib::Threads::Mutex::Lock lm (controllables_lock);
3823
3824 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3825 if ((*i)->id() == id) {
3826 return *i;
3827 }
3828 }
3829
3830 return boost::shared_ptr<Controllable>();
3831 }
3832
3833 boost::shared_ptr<AutomationControl>
automation_control_by_id(const PBD::ID & id)3834 Session::automation_control_by_id (const PBD::ID& id)
3835 {
3836 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3837 }
3838
3839 void
add_instant_xml(XMLNode & node,bool write_to_config)3840 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3841 {
3842 if (_writable) {
3843 Stateful::add_instant_xml (node, _path);
3844 }
3845
3846 if (write_to_config) {
3847 Config->add_instant_xml (node);
3848 }
3849 }
3850
3851 XMLNode*
instant_xml(const string & node_name)3852 Session::instant_xml (const string& node_name)
3853 {
3854 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3855 if (get_disable_all_loaded_plugins ()) {
3856 return NULL;
3857 }
3858 #endif
3859 return Stateful::instant_xml (node_name, _path);
3860 }
3861
3862 int
save_history(string snapshot_name)3863 Session::save_history (string snapshot_name)
3864 {
3865 XMLTree tree;
3866
3867 if (!_writable) {
3868 return 0;
3869 }
3870
3871 if (snapshot_name.empty()) {
3872 snapshot_name = _current_snapshot_name;
3873 }
3874
3875 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3876 const string backup_filename = history_filename + backup_suffix;
3877 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3878 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3879
3880 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3881 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3882 error << _("could not backup old history file, current history not saved") << endmsg;
3883 return -1;
3884 }
3885 }
3886
3887 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3888 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3889 return 0;
3890 }
3891
3892 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3893
3894 if (!tree.write (xml_path))
3895 {
3896 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3897
3898 if (g_remove (xml_path.c_str()) != 0) {
3899 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3900 xml_path, g_strerror (errno)) << endmsg;
3901 }
3902 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3903 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3904 backup_path, g_strerror (errno)) << endmsg;
3905 }
3906
3907 return -1;
3908 }
3909
3910 return 0;
3911 }
3912
3913 int
restore_history(string snapshot_name)3914 Session::restore_history (string snapshot_name)
3915 {
3916 XMLTree tree;
3917
3918 if (snapshot_name.empty()) {
3919 snapshot_name = _current_snapshot_name;
3920 }
3921
3922 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3923 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3924
3925 info << "Loading history from " << xml_path << endmsg;
3926
3927 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3928 info << string_compose (_("%1: no history file \"%2\" for this session."),
3929 _name, xml_path) << endmsg;
3930 return 1;
3931 }
3932
3933 if (!tree.read (xml_path)) {
3934 error << string_compose (_("Could not understand session history file \"%1\""),
3935 xml_path) << endmsg;
3936 return -1;
3937 }
3938
3939 // replace history
3940 _history.clear();
3941
3942 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3943
3944 XMLNode *t = *it;
3945
3946 std::string name;
3947 int64_t tv_sec;
3948 int64_t tv_usec;
3949
3950 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3951 !t->get_property ("tv-usec", tv_usec)) {
3952 continue;
3953 }
3954
3955 UndoTransaction* ut = new UndoTransaction ();
3956 ut->set_name (name);
3957
3958 struct timeval tv;
3959 tv.tv_sec = tv_sec;
3960 tv.tv_usec = tv_usec;
3961 ut->set_timestamp(tv);
3962
3963 for (XMLNodeConstIterator child_it = t->children().begin();
3964 child_it != t->children().end(); child_it++)
3965 {
3966 XMLNode *n = *child_it;
3967 Command *c;
3968
3969 if (n->name() == "MementoCommand" ||
3970 n->name() == "MementoUndoCommand" ||
3971 n->name() == "MementoRedoCommand") {
3972
3973 if ((c = memento_command_factory(n))) {
3974 ut->add_command(c);
3975 }
3976
3977 } else if (n->name() == "NoteDiffCommand") {
3978 PBD::ID id (n->property("midi-source")->value());
3979 boost::shared_ptr<MidiSource> midi_source =
3980 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3981 if (midi_source) {
3982 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3983 } else {
3984 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3985 }
3986
3987 } else if (n->name() == "SysExDiffCommand") {
3988
3989 PBD::ID id (n->property("midi-source")->value());
3990 boost::shared_ptr<MidiSource> midi_source =
3991 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3992 if (midi_source) {
3993 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3994 } else {
3995 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3996 }
3997
3998 } else if (n->name() == "PatchChangeDiffCommand") {
3999
4000 PBD::ID id (n->property("midi-source")->value());
4001 boost::shared_ptr<MidiSource> midi_source =
4002 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
4003 if (midi_source) {
4004 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
4005 } else {
4006 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
4007 }
4008
4009 } else if (n->name() == "StatefulDiffCommand") {
4010 if ((c = stateful_diff_command_factory (n))) {
4011 ut->add_command (c);
4012 }
4013 } else {
4014 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
4015 }
4016 }
4017
4018 _history.add (ut);
4019 }
4020
4021 return 0;
4022 }
4023
4024 void
config_changed(std::string p,bool ours)4025 Session::config_changed (std::string p, bool ours)
4026 {
4027 if (ours) {
4028 set_dirty ();
4029 }
4030
4031 if (p == "auto-loop") {
4032
4033 } else if (p == "session-monitoring") {
4034
4035 } else if (p == "auto-input") {
4036
4037 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4038 /* auto-input only makes a difference if we're rolling */
4039 set_track_monitor_input_status (!config.get_auto_input());
4040 }
4041
4042 } else if (p == "punch-in") {
4043
4044 if (!punch_is_possible ()) {
4045 if (config.get_punch_in ()) {
4046 /* force off */
4047 config.set_punch_in (false);
4048 return;
4049 }
4050 }
4051
4052 Location* location;
4053 if ((location = _locations->auto_punch_location()) != 0) {
4054
4055 if (config.get_punch_in ()) {
4056 auto_punch_start_changed (location);
4057 } else {
4058 clear_events (SessionEvent::PunchIn);
4059 }
4060 }
4061
4062 } else if (p == "punch-out") {
4063
4064 if (!punch_is_possible ()) {
4065 if (config.get_punch_out ()) {
4066 /* force off */
4067 config.set_punch_out (false);
4068 return;
4069 }
4070 }
4071
4072 Location* location;
4073 if ((location = _locations->auto_punch_location()) != 0) {
4074
4075 if (config.get_punch_out()) {
4076 auto_punch_end_changed (location);
4077 } else {
4078 clear_events (SessionEvent::PunchOut);
4079 }
4080 }
4081
4082 } else if (p == "edit-mode") {
4083
4084 Glib::Threads::Mutex::Lock lm (_playlists->lock);
4085
4086 for (SessionPlaylists::List::iterator i = _playlists->playlists.begin(); i != _playlists->playlists.end(); ++i) {
4087 (*i)->set_edit_mode (Config->get_edit_mode ());
4088 }
4089
4090 } else if (p == "use-video-sync") {
4091
4092 waiting_for_sync_offset = config.get_use_video_sync();
4093
4094 } else if (p == "mmc-control") {
4095
4096 //poke_midi_thread ();
4097
4098 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4099
4100 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4101
4102 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4103
4104 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4105
4106 } else if (p == "midi-control") {
4107
4108 //poke_midi_thread ();
4109
4110 } else if (p == "raid-path") {
4111
4112 setup_raid_path (config.get_raid_path());
4113
4114 } else if (p == "timecode-format") {
4115
4116 sync_time_vars ();
4117
4118 } else if (p == "video-pullup") {
4119
4120 sync_time_vars ();
4121
4122 } else if (p == "seamless-loop") {
4123
4124 if (play_loop && transport_rolling()) {
4125 // to reset diskstreams etc
4126 request_play_loop (true);
4127 }
4128
4129 } else if (p == "click-sound") {
4130
4131 setup_click_sounds (1);
4132
4133 } else if (p == "click-emphasis-sound") {
4134
4135 setup_click_sounds (-1);
4136
4137 } else if (p == "clicking") {
4138
4139 if (Config->get_clicking()) {
4140 if (_click_io && click_data) { // don't require emphasis data
4141 _clicking = true;
4142 }
4143 } else {
4144 _clicking = false;
4145 }
4146
4147 } else if (p == "click-record-only") {
4148
4149 _click_rec_only = Config->get_click_record_only();
4150
4151 } else if (p == "click-gain") {
4152
4153 if (_click_gain) {
4154 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4155 }
4156
4157 } else if (p == "send-mtc") {
4158
4159 if (Config->get_send_mtc ()) {
4160 /* mark us ready to send */
4161 next_quarter_frame_to_send = 0;
4162 }
4163
4164 } else if (p == "send-mmc") {
4165
4166 _mmc->enable_send (Config->get_send_mmc ());
4167 if (Config->get_send_mmc ()) {
4168 /* re-initialize MMC */
4169 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4170 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4171 }
4172
4173 } else if (p == "jack-time-master") {
4174
4175 engine().reset_timebase ();
4176
4177 } else if (p == "native-file-header-format") {
4178
4179 if (!first_file_header_format_reset) {
4180 reset_native_file_format ();
4181 }
4182
4183 first_file_header_format_reset = false;
4184
4185 } else if (p == "native-file-data-format") {
4186
4187 if (!first_file_data_format_reset) {
4188 reset_native_file_format ();
4189 }
4190
4191 first_file_data_format_reset = false;
4192
4193 } else if (p == "external-sync") {
4194 request_sync_source (TransportMasterManager::instance().current());
4195 } else if (p == "denormal-model") {
4196 setup_fpu ();
4197 } else if (p == "history-depth") {
4198 set_history_depth (Config->get_history_depth());
4199 } else if (p == "remote-model") {
4200 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4201 TO SET REMOTE ID'S
4202 */
4203 } else if (p == "initial-program-change") {
4204
4205 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4206 MIDI::byte buf[2];
4207
4208 buf[0] = MIDI::program; // channel zero by default
4209 buf[1] = (Config->get_initial_program_change() & 0x7f);
4210
4211 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4212 }
4213 } else if (p == "solo-mute-override") {
4214 // catch_up_on_solo_mute_override ();
4215 } else if (p == "listen-position" || p == "pfl-position" || p == "afl-position") {
4216 listen_position_changed ();
4217 } else if (p == "solo-control-is-listen-control") {
4218 solo_control_mode_changed ();
4219 } else if (p == "solo-mute-gain") {
4220 _solo_cut_control->Changed (true, Controllable::NoGroup);
4221 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4222 last_timecode_valid = false;
4223 } else if (p == "ltc-sink-port") {
4224 reconnect_ltc_output ();
4225 } else if (p == "timecode-generator-offset") {
4226 ltc_tx_parse_offset();
4227 } else if (p == "auto-return-target-list") {
4228 if (!loading()) {
4229 follow_playhead_priority ();
4230 }
4231 } else if (p == "use-monitor-bus") {
4232 /* NB. This is always called when constructing a session,
4233 * after restoring session state (if any),
4234 * via post_engine_init() -> Config->map_parameters()
4235 */
4236 bool want_ms = Config->get_use_monitor_bus();
4237 bool have_ms = _monitor_out ? true : false;
4238 if (loading ()) {
4239 /* When loading an existing session, the config "use-monitor-bus"
4240 * is ignored. Instead the sesion-state (xml) will have added the
4241 * "monitor-route" and restored its state (and connections)
4242 * if the session has a monitor-section.
4243 * Update the config to reflect this.
4244 */
4245 if (want_ms != have_ms) {
4246 Config->set_use_monitor_bus (have_ms);
4247 }
4248 MonitorBusAddedOrRemoved (); /* EMIT SIGNAL */
4249 } else {
4250 /* Otherwise, Config::set_use_monitor_bus() does
4251 * control the the presence of the monitor-section
4252 * (new sessions, user initiated change)
4253 */
4254 if (want_ms && !have_ms) {
4255 add_monitor_section ();
4256 } else if (!want_ms && have_ms) {
4257 remove_monitor_section ();
4258 }
4259 }
4260 } else if (p == "loop-fade-choice") {
4261 last_loopend = 0; /* force locate to refill buffers with new loop boundary data */
4262 auto_loop_changed (_locations->auto_loop_location());
4263 } else if (p == "use-master-volume") {
4264 if (master_volume () && !Config->get_use_master_volume ()) {
4265 _master_out->set_volume_applies_to_output (true);
4266 master_volume ()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
4267 }
4268 }
4269
4270 set_dirty ();
4271 }
4272
4273 void
set_history_depth(uint32_t d)4274 Session::set_history_depth (uint32_t d)
4275 {
4276 _history.set_depth (d);
4277 }
4278
4279 /** Connect things to the MMC object */
4280 void
setup_midi_machine_control()4281 Session::setup_midi_machine_control ()
4282 {
4283 _mmc = new MIDI::MachineControl;
4284
4285 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4286 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4287
4288 if (!async_out || !async_out) {
4289 return;
4290 }
4291
4292 /* XXXX argh, passing raw pointers back into libmidi++ */
4293
4294 MIDI::Port* mmc_in = async_in.get();
4295 MIDI::Port* mmc_out = async_out.get();
4296
4297 _mmc->set_ports (mmc_in, mmc_out);
4298
4299 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4300 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4301 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4302 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4303 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4304 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4305 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4306 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4307 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4308 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4309 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4310 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4311 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4312
4313 /* also handle MIDI SPP because its so common */
4314
4315 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4316 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4317 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4318 }
4319
4320 boost::shared_ptr<Controllable>
solo_cut_control() const4321 Session::solo_cut_control() const
4322 {
4323 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4324 * controls in Ardour that currently get presented to the user in the GUI that require
4325 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4326 *
4327 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4328 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4329 * parameter.
4330 */
4331 return _solo_cut_control;
4332 }
4333
4334 void
save_snapshot_name(const std::string & n)4335 Session::save_snapshot_name (const std::string & n)
4336 {
4337 /* assure Stateful::_instant_xml is loaded
4338 * add_instant_xml() only adds to existing data and defaults
4339 * to use an empty Tree otherwise
4340 */
4341 instant_xml ("LastUsedSnapshot");
4342
4343 XMLNode last_used_snapshot ("LastUsedSnapshot");
4344 last_used_snapshot.set_property ("name", n);
4345 add_instant_xml (last_used_snapshot, false);
4346 }
4347
4348 void
set_snapshot_name(const std::string & n)4349 Session::set_snapshot_name (const std::string & n)
4350 {
4351 _current_snapshot_name = n;
4352 save_snapshot_name (n);
4353 }
4354
4355 int
rename(const std::string & new_name)4356 Session::rename (const std::string& new_name)
4357 {
4358 string legal_name = legalize_for_path (new_name);
4359 string new_path;
4360 string oldstr;
4361 string newstr;
4362 bool first = true;
4363
4364 string const old_sources_root = _session_dir->sources_root();
4365
4366 if (!_writable || cannot_save ()) {
4367 error << _("Cannot rename read-only session.") << endmsg;
4368 return 0; // don't show "messed up" warning
4369 }
4370 if (record_status() == Recording) {
4371 error << _("Cannot rename session while recording") << endmsg;
4372 return 0; // don't show "messed up" warning
4373 }
4374
4375 StateProtector stp (this);
4376
4377 /* Rename:
4378
4379 * session directory
4380 * interchange subdirectory
4381 * session file
4382 * session history
4383
4384 * Backup files are left unchanged and not renamed.
4385 */
4386
4387 /* Windows requires that we close all files before attempting the
4388 * rename. This works on other platforms, but isn't necessary there.
4389 * Leave it in place for all platforms though, since it may help
4390 * catch issues that could arise if the way Source files work ever
4391 * change (since most developers are not using Windows).
4392 */
4393
4394 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4395 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4396 if (fs) {
4397 fs->close ();
4398 }
4399 }
4400
4401 /* pass one: not 100% safe check that the new directory names don't
4402 * already exist ...
4403 */
4404
4405 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4406
4407 oldstr = (*i).path;
4408
4409 /* this is a stupid hack because Glib::path_get_dirname() is
4410 * lexical-only, and so passing it /a/b/c/ gives a different
4411 * result than passing it /a/b/c ...
4412 */
4413
4414 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4415 oldstr = oldstr.substr (0, oldstr.length() - 1);
4416 }
4417
4418 string base = Glib::path_get_dirname (oldstr);
4419
4420 newstr = Glib::build_filename (base, legal_name);
4421
4422 cerr << "Looking for " << newstr << endl;
4423
4424 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4425 cerr << " exists\n";
4426 return -1;
4427 }
4428 }
4429
4430 /* Session dirs */
4431
4432 first = true;
4433
4434 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4435
4436 vector<string> v;
4437
4438 oldstr = (*i).path;
4439
4440 /* this is a stupid hack because Glib::path_get_dirname() is
4441 * lexical-only, and so passing it /a/b/c/ gives a different
4442 * result than passing it /a/b/c ...
4443 */
4444
4445 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4446 oldstr = oldstr.substr (0, oldstr.length() - 1);
4447 }
4448
4449 string base = Glib::path_get_dirname (oldstr);
4450 newstr = Glib::build_filename (base, legal_name);
4451
4452 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4453
4454 cerr << "Rename " << oldstr << " => " << newstr << endl;
4455 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4456 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4457 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4458 return 1;
4459 }
4460
4461 /* Reset path in "session dirs" */
4462
4463 (*i).path = newstr;
4464 (*i).blocks = 0;
4465
4466 /* reset primary SessionDirectory object */
4467
4468 if (first) {
4469 (*_session_dir) = newstr;
4470 new_path = newstr;
4471 first = false;
4472 }
4473
4474 /* now rename directory below session_dir/interchange */
4475
4476 string old_interchange_dir;
4477 string new_interchange_dir;
4478
4479 /* use newstr here because we renamed the path
4480 * (folder/directory) that used to be oldstr to newstr above
4481 */
4482
4483 v.push_back (newstr);
4484 v.push_back (interchange_dir_name);
4485 v.push_back (Glib::path_get_basename (oldstr));
4486
4487 old_interchange_dir = Glib::build_filename (v);
4488
4489 v.clear ();
4490 v.push_back (newstr);
4491 v.push_back (interchange_dir_name);
4492 v.push_back (legal_name);
4493
4494 new_interchange_dir = Glib::build_filename (v);
4495
4496 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4497
4498 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4499 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4500 old_interchange_dir, new_interchange_dir,
4501 g_strerror (errno))
4502 << endl;
4503 error << string_compose (_("renaming %s as %2 failed (%3)"),
4504 old_interchange_dir, new_interchange_dir,
4505 g_strerror (errno))
4506 << endmsg;
4507 return 1;
4508 }
4509 }
4510
4511 /* state file */
4512
4513 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4514 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4515
4516 cerr << "Rename " << oldstr << " => " << newstr << endl;
4517
4518 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4519 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4520 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4521 return 1;
4522 }
4523
4524 /* history file */
4525
4526 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4527
4528 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4529 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4530
4531 cerr << "Rename " << oldstr << " => " << newstr << endl;
4532
4533 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4534 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4535 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4536 return 1;
4537 }
4538 }
4539
4540 /* remove old name from recent sessions */
4541 remove_recent_sessions (_path);
4542 _path = new_path;
4543
4544 /* update file source paths */
4545
4546 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4547 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4548 if (fs) {
4549 string p = fs->path ();
4550 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4551 fs->set_path (p);
4552 SourceFactory::setup_peakfile(i->second, true);
4553 }
4554 }
4555
4556 set_snapshot_name (new_name);
4557 _name = new_name;
4558
4559 set_dirty ();
4560
4561 /* save state again to get everything just right */
4562
4563 save_state (_current_snapshot_name);
4564
4565 /* add to recent sessions */
4566
4567 store_recent_sessions (new_name, _path);
4568
4569 /* remove unnamed file name, if any (it's not an error if it doesn't exist) */
4570 ::g_unlink (unnamed_file_name().c_str());
4571
4572 return 0;
4573 }
4574
4575 int
parse_stateful_loading_version(const std::string & version)4576 Session::parse_stateful_loading_version (const std::string& version)
4577 {
4578 if (version.empty ()) {
4579 /* no version implies very old version of Ardour */
4580 return 1000;
4581 }
4582
4583 if (version.find ('.') != string::npos) {
4584 /* old school version format */
4585 if (version[0] == '2') {
4586 return 2000;
4587 } else {
4588 return 3000;
4589 }
4590 } else {
4591 return string_to<int32_t>(version);
4592 }
4593 }
4594
4595 int
get_info_from_path(const string & xmlpath,float & sample_rate,SampleFormat & data_format,std::string & program_version,XMLNode * engine_hints)4596 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version, XMLNode* engine_hints)
4597 {
4598 bool found_sr = false;
4599 bool found_data_format = false;
4600 std::string version;
4601 program_version = "";
4602
4603 if (engine_hints) {
4604 /* clear existing properties */
4605 *engine_hints = XMLNode ("EngineHints");
4606 }
4607
4608 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4609 return -1;
4610 }
4611
4612 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4613 if (ctxt == NULL) {
4614 return -1;
4615 }
4616 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4617
4618 if (doc == NULL) {
4619 xmlFreeParserCtxt(ctxt);
4620 return -1;
4621 }
4622
4623 xmlNodePtr node = xmlDocGetRootElement(doc);
4624
4625 if (node == NULL) {
4626 xmlFreeParserCtxt(ctxt);
4627 xmlFreeDoc (doc);
4628 return -1;
4629 }
4630
4631 /* sample rate & version*/
4632
4633 xmlAttrPtr attr;
4634 for (attr = node->properties; attr; attr = attr->next) {
4635 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4636 version = std::string ((char*)attr->children->content);
4637 }
4638 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4639 sample_rate = atoi ((char*)attr->children->content);
4640 found_sr = true;
4641 }
4642 }
4643
4644 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4645 return -1;
4646 }
4647
4648 if ((parse_stateful_loading_version(version) / 1000L) <= 2) {
4649 /* sample-format '0' is implicit */
4650 data_format = FormatFloat;
4651 found_data_format = true;
4652 }
4653
4654 node = node->children;
4655 while (node != NULL) {
4656 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4657 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4658 if (val) {
4659 program_version = string ((const char*)val);
4660 size_t sep = program_version.find_first_of("-");
4661 if (sep != string::npos) {
4662 program_version = program_version.substr (0, sep);
4663 }
4664 }
4665 xmlFree (val);
4666 }
4667 if (engine_hints && strcmp((const char*) node->name, "EngineHints") == 0) {
4668 xmlChar* val = xmlGetProp (node, (const xmlChar*)"backend");
4669 if (val) {
4670 engine_hints->set_property ("backend", (const char*)val);
4671 }
4672 xmlFree (val);
4673 val = xmlGetProp (node, (const xmlChar*)"input-device");
4674 if (val) {
4675 engine_hints->set_property ("input-device", (const char*)val);
4676 }
4677 xmlFree (val);
4678 val = xmlGetProp (node, (const xmlChar*)"output-device");
4679 if (val) {
4680 engine_hints->set_property ("output-device", (const char*)val);
4681 }
4682 xmlFree (val);
4683 }
4684
4685 if (strcmp((const char*) node->name, "Config")) {
4686 node = node->next;
4687 continue;
4688 }
4689 for (node = node->children; node; node = node->next) {
4690 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4691 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4692 xmlFree (pv);
4693 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4694 if (val) {
4695 try {
4696 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4697 data_format = fmt;
4698 found_data_format = true;
4699 } catch (PBD::unknown_enumeration& e) {}
4700 }
4701 xmlFree (val);
4702 break;
4703 }
4704 xmlFree (pv);
4705 }
4706 break;
4707 }
4708
4709 xmlFreeParserCtxt(ctxt);
4710 xmlFreeDoc (doc);
4711
4712 return (found_sr && found_data_format) ? 0 : 1;
4713 }
4714
4715 std::string
get_snapshot_from_instant(const std::string & session_dir)4716 Session::get_snapshot_from_instant (const std::string& session_dir)
4717 {
4718 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4719
4720 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4721 return "";
4722 }
4723
4724 XMLTree tree;
4725 if (!tree.read (instant_xml_path)) {
4726 return "";
4727 }
4728
4729 XMLProperty const * prop;
4730 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4731 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4732 return prop->value();
4733 }
4734
4735 return "";
4736 }
4737
4738 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4739 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4740
4741 int
bring_all_sources_into_session(boost::function<void (uint32_t,uint32_t,string)> callback)4742 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4743 {
4744 uint32_t total = 0;
4745 uint32_t n = 0;
4746 SourcePathMap source_path_map;
4747 string new_path;
4748 boost::shared_ptr<AudioFileSource> afs;
4749 int ret = 0;
4750
4751 {
4752
4753 Glib::Threads::Mutex::Lock lm (source_lock);
4754
4755 cerr << " total sources = " << sources.size();
4756
4757 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4758 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4759
4760 if (!fs) {
4761 continue;
4762 }
4763
4764 if (fs->within_session()) {
4765 continue;
4766 }
4767
4768 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4769 source_path_map[fs->path()].push_back (fs);
4770 } else {
4771 SeveralFileSources v;
4772 v.push_back (fs);
4773 source_path_map.insert (make_pair (fs->path(), v));
4774 }
4775
4776 total++;
4777 }
4778
4779 cerr << " fsources = " << total << endl;
4780
4781 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4782
4783 /* tell caller where we are */
4784
4785 string old_path = i->first;
4786
4787 callback (n, total, old_path);
4788
4789 cerr << old_path << endl;
4790
4791 new_path.clear ();
4792
4793 switch (i->second.front()->type()) {
4794 case DataType::AUDIO:
4795 new_path = new_audio_source_path_for_embedded (old_path);
4796 break;
4797
4798 case DataType::MIDI:
4799 /* XXX not implemented yet */
4800 break;
4801 }
4802
4803 if (new_path.empty()) {
4804 continue;
4805 }
4806
4807 cerr << "Move " << old_path << " => " << new_path << endl;
4808
4809 if (!copy_file (old_path, new_path)) {
4810 cerr << "failed !\n";
4811 ret = -1;
4812 }
4813
4814 /* make sure we stop looking in the external
4815 dir/folder. Remember, this is an all-or-nothing
4816 operations, it doesn't merge just some files.
4817 */
4818 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4819
4820 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4821 (*f)->set_path (new_path);
4822 }
4823 }
4824 }
4825
4826 save_state ();
4827
4828 return ret;
4829 }
4830
4831 static
accept_all_files(string const &,void *)4832 bool accept_all_files (string const &, void *)
4833 {
4834 return true;
4835 }
4836
4837 void
save_as_bring_callback(uint32_t,uint32_t,string)4838 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4839 {
4840 /* It would be good if this did something useful vis-a-vis save-as, but the arguments doesn't provide the correct information right now to do this.
4841 */
4842 }
4843
4844 static string
make_new_media_path(string old_path,string new_session_folder,string new_session_name)4845 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4846 {
4847 // old_path must be in within_session ()
4848 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4849 vector<string> v;
4850 v.push_back (new_session_folder); /* full path */
4851 v.push_back (interchange_dir_name);
4852 v.push_back (new_session_name); /* just one directory/folder */
4853 v.push_back (typedir);
4854 v.push_back (Glib::path_get_basename (old_path));
4855
4856 return Glib::build_filename (v);
4857 }
4858
4859 static string
make_new_audio_path(string filename,string new_session_folder,string new_session_name)4860 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4861 {
4862 vector<string> v;
4863 v.push_back (new_session_folder); /* full path */
4864 v.push_back (interchange_dir_name);
4865 v.push_back (new_session_name);
4866 v.push_back (ARDOUR::sound_dir_name);
4867 v.push_back (filename);
4868
4869 return Glib::build_filename (v);
4870 }
4871
4872 int
save_as(SaveAs & saveas)4873 Session::save_as (SaveAs& saveas)
4874 {
4875 vector<string> files;
4876 string current_folder = Glib::path_get_dirname (_path);
4877 string new_folder = legalize_for_path (saveas.new_name);
4878 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4879 int64_t total_bytes = 0;
4880 int64_t copied = 0;
4881 int64_t cnt = 0;
4882 int64_t all = 0;
4883 int32_t internal_file_cnt = 0;
4884
4885 vector<string> do_not_copy_extensions;
4886 do_not_copy_extensions.push_back (statefile_suffix);
4887 do_not_copy_extensions.push_back (pending_suffix);
4888 do_not_copy_extensions.push_back (backup_suffix);
4889 do_not_copy_extensions.push_back (temp_suffix);
4890 do_not_copy_extensions.push_back (history_suffix);
4891
4892 /* get total size */
4893
4894 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4895
4896 /* need to clear this because
4897 * find_files_matching_filter() is cumulative
4898 */
4899
4900 files.clear ();
4901
4902 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4903
4904 all += files.size();
4905
4906 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4907 GStatBuf gsb;
4908 g_stat ((*i).c_str(), &gsb);
4909 total_bytes += gsb.st_size;
4910 }
4911 }
4912
4913 /* save old values so we can switch back if we are not switching to the new session */
4914
4915 string old_path = _path;
4916 string old_name = _name;
4917 string old_snapshot = _current_snapshot_name;
4918 string old_sd = _session_dir->root_path();
4919 vector<string> old_search_path[DataType::num_types];
4920 string old_config_search_path[DataType::num_types];
4921
4922 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4923 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4924 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4925 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4926
4927 /* switch session directory */
4928
4929 (*_session_dir) = to_dir;
4930
4931 /* create new tree */
4932
4933 if (!_session_dir->create()) {
4934 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4935 return -1;
4936 }
4937
4938 try {
4939 /* copy all relevant files. Find each location in session_dirs,
4940 * and copy files from there to target.
4941 */
4942
4943 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4944
4945 /* need to clear this because
4946 * find_files_matching_filter() is cumulative
4947 */
4948
4949 files.clear ();
4950
4951 const size_t prefix_len = (*sd).path.size();
4952
4953 /* Work just on the files within this session dir */
4954
4955 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4956
4957 /* add dir separator to protect against collisions with
4958 * track names (e.g. track named "audiofiles" or
4959 * "analysis".
4960 */
4961
4962 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4963 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4964 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4965
4966 /* copy all the files. Handling is different for media files
4967 than others because of the *silly* subtree we have below the interchange
4968 folder. That really was a bad idea, but I'm not fixing it as part of
4969 implementing ::save_as().
4970 */
4971
4972 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4973
4974 std::string from = *i;
4975
4976 #ifdef __APPLE__
4977 string filename = Glib::path_get_basename (from);
4978 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4979 if (filename == ".DS_STORE") {
4980 continue;
4981 }
4982 #endif
4983
4984 if (from.find (audiofile_dir_string) != string::npos) {
4985
4986 /* audio file: only copy if asked */
4987
4988 if (saveas.include_media && saveas.copy_media) {
4989
4990 string to = make_new_media_path (*i, to_dir, new_folder);
4991
4992 info << "media file copying from " << from << " to " << to << endmsg;
4993
4994 if (!copy_file (from, to)) {
4995 throw Glib::FileError (Glib::FileError::IO_ERROR,
4996 string_compose(_("\ncopying \"%1\" failed !"), from));
4997 }
4998 }
4999
5000 /* we found media files inside the session folder */
5001
5002 internal_file_cnt++;
5003
5004 } else if (from.find (midifile_dir_string) != string::npos) {
5005
5006 /* midi file: always copy unless
5007 * creating an empty new session
5008 */
5009
5010 if (saveas.include_media) {
5011
5012 string to = make_new_media_path (*i, to_dir, new_folder);
5013
5014 info << "media file copying from " << from << " to " << to << endmsg;
5015
5016 if (!copy_file (from, to)) {
5017 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
5018 }
5019 }
5020
5021 /* we found media files inside the session folder */
5022
5023 internal_file_cnt++;
5024
5025 } else if (from.find (analysis_dir_string) != string::npos) {
5026
5027 /* make sure analysis dir exists in
5028 * new session folder, but we're not
5029 * copying analysis files here, see
5030 * below
5031 */
5032
5033 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
5034 continue;
5035
5036 } else {
5037
5038 /* normal non-media file. Don't copy state, history, etc.
5039 */
5040
5041 bool do_copy = true;
5042
5043 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5044 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5045 /* end of filename matches extension, do not copy file */
5046 do_copy = false;
5047 break;
5048 }
5049 }
5050
5051 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
5052 /* don't copy peakfiles if
5053 * we're not copying media
5054 */
5055 do_copy = false;
5056 }
5057
5058 if (do_copy) {
5059 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
5060
5061 info << "attempting to make directory/folder " << to << endmsg;
5062
5063 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
5064 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
5065 }
5066
5067 info << "attempting to copy " << from << " to " << to << endmsg;
5068
5069 if (!copy_file (from, to)) {
5070 throw Glib::FileError (Glib::FileError::IO_ERROR,
5071 string_compose(_("\ncopying \"%1\" failed !"), from));
5072 }
5073 }
5074 }
5075
5076 /* measure file size even if we're not going to copy so that our Progress
5077 signals are correct, since we included these do-not-copy files
5078 in the computation of the total size and file count.
5079 */
5080
5081 GStatBuf gsb;
5082 g_stat (from.c_str(), &gsb);
5083 copied += gsb.st_size;
5084 cnt++;
5085
5086 double fraction = (double) copied / total_bytes;
5087
5088 bool keep_going = true;
5089
5090 if (saveas.copy_media) {
5091
5092 /* no need or expectation of this if
5093 * media is not being copied, because
5094 * it will be fast(ish).
5095 */
5096
5097 /* tell someone "X percent, file M of N"; M is one-based */
5098
5099 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
5100
5101 if (res) {
5102 keep_going = *res;
5103 }
5104 }
5105
5106 if (!keep_going) {
5107 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5108 }
5109 }
5110
5111 }
5112
5113 /* copy optional folders, if any */
5114
5115 string old = plugins_dir ();
5116 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5117 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5118 copy_files (old, newdir);
5119 }
5120
5121 old = externals_dir ();
5122 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5123 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5124 copy_files (old, newdir);
5125 }
5126
5127 old = automation_dir ();
5128 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5129 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5130 copy_files (old, newdir);
5131 }
5132
5133 if (saveas.include_media) {
5134
5135 if (saveas.copy_media) {
5136 #ifndef PLATFORM_WINDOWS
5137 /* There are problems with analysis files on
5138 * Windows, because they used a colon in their
5139 * names as late as 4.0. Colons are not legal
5140 * under Windows even if NTFS allows them.
5141 *
5142 * This is a tricky problem to solve so for
5143 * just don't copy these files. They will be
5144 * regenerated as-needed anyway, subject to the
5145 * existing issue that the filenames will be
5146 * rejected by Windows, which is a separate
5147 * problem (though related).
5148 */
5149
5150 /* only needed if we are copying media, since the
5151 * analysis data refers to media data
5152 */
5153
5154 old = analysis_dir ();
5155 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5156 string newdir = Glib::build_filename (to_dir, "analysis");
5157 copy_files (old, newdir);
5158 }
5159 #endif /* PLATFORM_WINDOWS */
5160 }
5161 }
5162
5163 _path = to_dir;
5164 set_snapshot_name (saveas.new_name);
5165 _name = saveas.new_name;
5166
5167 if (saveas.include_media && !saveas.copy_media) {
5168
5169 /* reset search paths of the new session (which we're pretending to be right now) to
5170 include the original session search path, so we can still find all audio.
5171 */
5172
5173 if (internal_file_cnt) {
5174 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5175 ensure_search_path_includes (*s, DataType::AUDIO);
5176 cerr << "be sure to include " << *s << " for audio" << endl;
5177 }
5178
5179 /* we do not do this for MIDI because we copy
5180 all MIDI files if saveas.include_media is
5181 true
5182 */
5183 }
5184 }
5185
5186 bool was_dirty = dirty ();
5187
5188 save_default_options ();
5189
5190 if (saveas.copy_media && saveas.copy_external) {
5191 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5192 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5193 }
5194 }
5195
5196 saveas.final_session_folder_name = _path;
5197
5198 store_recent_sessions (_name, _path);
5199
5200 if (!saveas.switch_to) {
5201
5202 /* save the new state */
5203
5204 save_state ("", false, false, !saveas.include_media);
5205
5206 /* switch back to the way things were */
5207
5208 _path = old_path;
5209 _name = old_name;
5210 set_snapshot_name (old_snapshot);
5211
5212 (*_session_dir) = old_sd;
5213
5214 if (was_dirty) {
5215 set_dirty ();
5216 }
5217
5218 if (internal_file_cnt) {
5219 /* reset these to their original values */
5220 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5221 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5222 }
5223
5224 } else {
5225
5226 /* prune session dirs, and update disk space statistics
5227 */
5228
5229 space_and_path sp;
5230 sp.path = _path;
5231 session_dirs.clear ();
5232 session_dirs.push_back (sp);
5233 refresh_disk_space ();
5234
5235 _writable = exists_and_writable (_path);
5236
5237 /* ensure that all existing tracks reset their current capture source paths
5238 */
5239 reset_write_sources (true, true);
5240
5241 /* creating new write sources marks the session as
5242 dirty. If the new session is empty, then
5243 save_state() thinks we're saving a template and will
5244 not mark the session as clean. So do that here,
5245 before we save state.
5246 */
5247
5248 if (!saveas.include_media) {
5249 unset_dirty ();
5250 }
5251
5252 save_state ("", false, false, !saveas.include_media);
5253
5254 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5255 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5256 */
5257
5258 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5259 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5260
5261 if (!fs) {
5262 continue;
5263 }
5264
5265 if (fs->within_session()) {
5266 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5267 fs->set_path (newpath);
5268 }
5269 }
5270 }
5271
5272 } catch (Glib::FileError& e) {
5273
5274 saveas.failure_message = e.what();
5275
5276 /* recursively remove all the directories */
5277
5278 remove_directory (to_dir);
5279
5280 /* return error */
5281
5282 return -1;
5283
5284 } catch (...) {
5285
5286 saveas.failure_message = _("unknown reason");
5287
5288 /* recursively remove all the directories */
5289
5290 remove_directory (to_dir);
5291
5292 /* return error */
5293
5294 return -1;
5295 }
5296
5297 return 0;
5298 }
5299
set_progress(Progress * p,size_t n,size_t t)5300 static void set_progress (Progress* p, size_t n, size_t t)
5301 {
5302 p->set_progress (float (n) / float(t));
5303 }
5304
5305 int
archive_session(const std::string & dest,const std::string & name,ArchiveEncode compress_audio,FileArchive::CompressionLevel compression_level,bool only_used_sources,Progress * progress)5306 Session::archive_session (const std::string& dest,
5307 const std::string& name,
5308 ArchiveEncode compress_audio,
5309 FileArchive::CompressionLevel compression_level,
5310 bool only_used_sources,
5311 Progress* progress)
5312 {
5313 if (dest.empty () || name.empty ()) {
5314 return -1;
5315 }
5316
5317 /* We are going to temporarily change some source properties,
5318 * don't allow any concurrent saves (periodic or otherwise */
5319 Glib::Threads::Mutex::Lock lm (save_source_lock);
5320
5321 disable_record (false);
5322
5323 /* save current values */
5324 string old_path = _path;
5325 string old_name = _name;
5326 string old_snapshot = _current_snapshot_name;
5327 string old_sd = _session_dir->root_path();
5328 string old_config_search_path[DataType::num_types];
5329 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5330 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5331
5332 /* ensure that session-path is included in search-path */
5333 bool ok = false;
5334 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5335 if ((*sd).path == old_path) {
5336 ok = true;
5337 }
5338 }
5339 if (!ok) {
5340 return -1;
5341 }
5342
5343 /* create temporary dir to save session to */
5344 GError* err = NULL;
5345 char* td = g_dir_make_tmp ("ardourarchive-XXXXXX", &err);
5346
5347 if (!td) {
5348 error << string_compose(_("Could not make tmpdir: %1"), err->message) << endmsg;
5349 return -1;
5350 }
5351 const string to_dir = PBD::canonical_path (td);
5352 g_free (td);
5353 g_clear_error (&err);
5354
5355 /* switch session directory temporarily */
5356 (*_session_dir) = to_dir;
5357
5358 if (!_session_dir->create()) {
5359 (*_session_dir) = old_sd;
5360 remove_directory (to_dir);
5361 return -1;
5362 }
5363
5364 /* prepare archive */
5365 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5366
5367 PBD::ScopedConnectionList progress_connection;
5368 PBD::FileArchive ar (archive);
5369 if (progress) {
5370 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5371 }
5372
5373 /* collect files to archive */
5374 std::map<string,string> filemap;
5375
5376 vector<string> do_not_copy_extensions;
5377 do_not_copy_extensions.push_back (statefile_suffix);
5378 do_not_copy_extensions.push_back (pending_suffix);
5379 do_not_copy_extensions.push_back (backup_suffix);
5380 do_not_copy_extensions.push_back (temp_suffix);
5381 do_not_copy_extensions.push_back (history_suffix);
5382
5383 vector<string> blacklist_dirs;
5384 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5385 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5386 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5387 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5388 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5389 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5390
5391 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5392 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5393 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5394
5395 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5396 if (only_used_sources) {
5397 _playlists->sync_all_regions_with_regions ();
5398 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5399 }
5400
5401 /* collect audio sources for this session, calc total size for encoding
5402 * add option to only include *used* sources (see Session::cleanup_sources)
5403 */
5404 size_t total_size = 0;
5405 {
5406 Glib::Threads::Mutex::Lock lm (source_lock);
5407
5408 /* build a list of used names */
5409 std::set<std::string> audio_file_names;
5410 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5411 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5412 continue;
5413 }
5414 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5415 if (!afs || afs->readable_length () == 0) {
5416 continue;
5417 }
5418 if (only_used_sources) {
5419 if (!afs->used()) {
5420 continue;
5421 }
5422 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5423 continue;
5424 }
5425 }
5426 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5427 }
5428
5429 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5430 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5431 continue;
5432 }
5433 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5434 if (!afs || afs->readable_length () == 0) {
5435 continue;
5436 }
5437
5438 if (only_used_sources) {
5439 if (!afs->used()) {
5440 continue;
5441 }
5442 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5443 continue;
5444 }
5445 }
5446
5447 std::string from = afs->path();
5448
5449 if (compress_audio != NO_ENCODE) {
5450 total_size += afs->readable_length ();
5451 } else {
5452 /* copy files as-is */
5453 if (!afs->within_session()) {
5454 string to = Glib::path_get_basename (from);
5455
5456 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5457 * - avoid conflict with files existing in interchange
5458 * - avoid conflict with other embedded sources
5459 */
5460 if (audio_file_names.find (to) == audio_file_names.end ()) {
5461 // we need a new name, add a '-<num>' before the '.<ext>'
5462 string bn = to.substr (0, to.find_last_of ('.'));
5463 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5464 to = bn + "-1" + ext;
5465 }
5466 while (audio_file_names.find (to) == audio_file_names.end ()) {
5467 to = bump_name_once (to, '-');
5468 }
5469
5470 audio_file_names.insert (to);
5471 filemap[from] = make_new_audio_path (to, name, name);
5472
5473 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5474
5475 orig_origin[afs] = afs->origin ();
5476 afs->set_origin ("");
5477
5478 } else {
5479 filemap[from] = make_new_media_path (from, name, name);
5480 }
5481 }
5482 }
5483 }
5484
5485 /* encode audio */
5486 if (compress_audio != NO_ENCODE) {
5487 if (progress) {
5488 progress->set_progress (2); // set to "encoding"
5489 progress->set_progress (0);
5490 }
5491
5492 Glib::Threads::Mutex::Lock lm (source_lock);
5493 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5494 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5495 continue;
5496 }
5497 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5498 if (!afs || afs->readable_length () == 0) {
5499 continue;
5500 }
5501
5502 if (only_used_sources) {
5503 if (!afs->used()) {
5504 continue;
5505 }
5506 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5507 continue;
5508 }
5509 }
5510
5511 orig_sources[afs] = afs->path();
5512 orig_gain[afs] = afs->gain();
5513
5514 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5515
5516 std::string channelsuffix = "";
5517 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5518 /* embedded external multi-channel files are converted to multiple-mono */
5519 channelsuffix = string_compose ("-c%1", afs->channel ());
5520 }
5521 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5522 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5523
5524 /* avoid name collisions of external files with same name */
5525 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5526 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5527 }
5528 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5529 new_path = bump_name_once (new_path, '-');
5530 }
5531
5532 if (progress) {
5533 progress->descend ((float)afs->readable_length () / total_size);
5534 }
5535
5536 try {
5537 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5538 afs->replace_file (new_path);
5539 afs->set_gain (ns->gain(), true);
5540 delete ns;
5541 } catch (...) {
5542 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5543 }
5544
5545 if (progress) {
5546 progress->ascend ();
5547 }
5548 }
5549 }
5550
5551 if (progress) {
5552 progress->set_progress (-1); // set to "archiving"
5553 progress->set_progress (0);
5554 }
5555
5556 /* index files relevant for this session */
5557 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5558 vector<string> files;
5559
5560 size_t prefix_len = (*sd).path.size();
5561 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5562 ++prefix_len;
5563 }
5564
5565 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5566
5567 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5568 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5569 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5570
5571 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5572 std::string from = *i;
5573
5574 #ifdef __APPLE__
5575 string filename = Glib::path_get_basename (from);
5576 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5577 if (filename == ".DS_STORE") {
5578 continue;
5579 }
5580 #endif
5581
5582 if (from.find (audiofile_dir_string) != string::npos) {
5583 ; // handled above
5584 } else if (from.find (midifile_dir_string) != string::npos) {
5585 filemap[from] = make_new_media_path (from, name, name);
5586 } else if (from.find (videofile_dir_string) != string::npos) {
5587 filemap[from] = make_new_media_path (from, name, name);
5588 } else {
5589 bool do_copy = true;
5590 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5591 if (from.find (*v) != string::npos) {
5592 do_copy = false;
5593 break;
5594 }
5595 }
5596 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5597 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5598 do_copy = false;
5599 break;
5600 }
5601 }
5602
5603 if (do_copy) {
5604 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5605 }
5606 }
5607 }
5608 }
5609
5610 /* write session file */
5611 _path = to_dir;
5612 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5613
5614 save_state (name, false, false, false, true, only_used_sources);
5615
5616 save_default_options ();
5617
5618 size_t prefix_len = _path.size();
5619 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5620 ++prefix_len;
5621 }
5622
5623 /* collect session-state files */
5624 vector<string> files;
5625 do_not_copy_extensions.clear ();
5626 do_not_copy_extensions.push_back (history_suffix);
5627
5628 blacklist_dirs.clear ();
5629 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5630
5631 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5632 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5633 std::string from = *i;
5634 bool do_copy = true;
5635 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5636 if (from.find (*v) != string::npos) {
5637 do_copy = false;
5638 break;
5639 }
5640 }
5641 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5642 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5643 do_copy = false;
5644 break;
5645 }
5646 }
5647 if (do_copy) {
5648 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5649 }
5650 }
5651
5652 /* restore original values */
5653 _path = old_path;
5654 _name = old_name;
5655 set_snapshot_name (old_snapshot);
5656 (*_session_dir) = old_sd;
5657 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5658 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5659
5660 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5661 i->first->set_origin (i->second);
5662 }
5663 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5664 i->first->replace_file (i->second);
5665 }
5666 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5667 i->first->set_gain (i->second, true);
5668 }
5669
5670 int rv = ar.create (filemap, compression_level);
5671 remove_directory (to_dir);
5672
5673 return rv;
5674 }
5675
5676 void
undo(uint32_t n)5677 Session::undo (uint32_t n)
5678 {
5679 if (actively_recording()) {
5680 return;
5681 }
5682 StateProtector stp (this);
5683 _history.undo (n);
5684 }
5685
5686 void
redo(uint32_t n)5687 Session::redo (uint32_t n)
5688 {
5689 if (actively_recording()) {
5690 return;
5691 }
5692
5693 StateProtector stp (this);
5694 _history.redo (n);
5695 }
5696
5697 std::string
unnamed_file_name() const5698 Session::unnamed_file_name() const
5699 {
5700 return Glib::build_filename (_path, X_(".unnamed"));
5701 }
5702
5703 bool
unnamed() const5704 Session::unnamed() const
5705 {
5706 return Glib::file_test (unnamed_file_name(), Glib::FILE_TEST_EXISTS);
5707 }
5708
5709 void
end_unnamed_status() const5710 Session::end_unnamed_status () const
5711 {
5712 ::g_remove (unnamed_file_name().c_str());
5713 }
5714