2 Copyright (C) 1999-2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #define __STDC_FORMAT_MACROS 1
28 #include <sigc++/bind.h>
30 #include <cstdio> /* snprintf(3) ... grrr */
45 #include <sys/param.h>
46 #include <sys/mount.h>
51 #include <midi++/mmc.h>
52 #include <midi++/port.h>
53 #include <pbd/error.h>
55 #include <glibmm/thread.h>
56 #include <pbd/pathscanner.h>
57 #include <pbd/pthread_utils.h>
58 #include <pbd/strsplit.h>
59 #include <pbd/stacktrace.h>
60 #include <pbd/copyfile.h>
62 #include <ardour/audioengine.h>
63 #include <ardour/configuration.h>
64 #include <ardour/session.h>
65 #include <ardour/buffer.h>
66 #include <ardour/audio_diskstream.h>
67 #include <ardour/midi_diskstream.h>
68 #include <ardour/utils.h>
69 #include <ardour/audioplaylist.h>
70 #include <ardour/midi_playlist.h>
71 #include <ardour/smf_source.h>
72 #include <ardour/audiofilesource.h>
73 #include <ardour/silentfilesource.h>
74 #include <ardour/sndfilesource.h>
75 #include <ardour/midi_source.h>
76 #include <ardour/sndfile_helpers.h>
77 #include <ardour/auditioner.h>
78 #include <ardour/export.h>
79 #include <ardour/redirect.h>
80 #include <ardour/send.h>
81 #include <ardour/insert.h>
82 #include <ardour/connection.h>
83 #include <ardour/slave.h>
84 #include <ardour/tempo.h>
85 #include <ardour/audio_track.h>
86 #include <ardour/midi_track.h>
87 #include <ardour/cycle_timer.h>
88 #include <ardour/utils.h>
89 #include <ardour/named_selection.h>
90 #include <ardour/version.h>
91 #include <ardour/location.h>
92 #include <ardour/audioregion.h>
93 #include <ardour/midi_region.h>
94 #include <ardour/crossfade.h>
95 #include <ardour/control_protocol_manager.h>
96 #include <ardour/region_factory.h>
97 #include <ardour/source_factory.h>
98 #include <ardour/playlist_factory.h>
99 #include <ardour/filename_extensions.h>
100 #include <control_protocol/control_protocol.h>
106 using namespace ARDOUR;
110 Session::first_stage_init (string fullpath, string snapshot_name)
112 if (fullpath.length() == 0) {
114 throw failed_constructor();
117 char buf[PATH_MAX+1];
118 if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
119 error << string_compose(_("Could not use path %1 (%s)"), buf, strerror(errno)) << endmsg;
121 throw failed_constructor();
126 if (_path[_path.length()-1] != '/') {
130 /* these two are just provisional settings. set_state()
131 will likely override them.
134 _name = _current_snapshot_name = snapshot_name;
136 _current_frame_rate = _engine.frame_rate ();
137 _tempo_map = new TempoMap (_current_frame_rate);
138 _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
140 g_atomic_int_set (&processing_prohibited, 0);
142 _transport_speed = 0;
143 _last_transport_speed = 0;
144 auto_play_legal = false;
145 transport_sub_state = 0;
146 _transport_frame = 0;
148 end_location = new Location (0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
149 start_location = new Location (0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
150 _end_location_is_free = true;
151 g_atomic_int_set (&_record_status, Disabled);
152 loop_changing = false;
154 _last_roll_location = 0;
155 _last_record_location = 0;
156 pending_locate_frame = 0;
157 pending_locate_roll = false;
158 pending_locate_flush = false;
159 dstream_buffer_size = 0;
161 state_was_pending = false;
163 outbound_mtc_smpte_frame = 0;
164 next_quarter_frame_to_send = -1;
165 current_block_size = 0;
166 solo_update_disabled = false;
167 currently_soloing = false;
168 _have_captured = false;
169 _worst_output_latency = 0;
170 _worst_input_latency = 0;
171 _worst_track_latency = 0;
172 _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading|Deletion);
174 butler_mixdown_buffer = 0;
175 butler_gain_buffer = 0;
177 session_send_mmc = false;
178 session_send_mtc = false;
179 post_transport_work = PostTransportWork (0);
180 g_atomic_int_set (&butler_should_do_transport_work, 0);
181 g_atomic_int_set (&butler_active, 0);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
184 g_atomic_int_set (&_playback_load_min, 100);
185 g_atomic_int_set (&_capture_load_min, 100);
187 waiting_to_start = false;
189 _gain_automation_buffer = 0;
190 _pan_automation_buffer = 0;
192 pending_abort = false;
193 destructive_index = 0;
195 first_file_data_format_reset = true;
196 first_file_header_format_reset = true;
197 butler_thread = (pthread_t) 0;
198 //midi_thread = (pthread_t) 0;
200 AudioDiskstream::allocate_working_buffers();
202 /* default short fade = 15ms */
204 Crossfade::set_short_xfade_length ((nframes_t) floor (Config->get_short_xfade_seconds() * frame_rate()));
205 SndFileSource::setup_standard_crossfades (frame_rate());
207 last_mmc_step.tv_sec = 0;
208 last_mmc_step.tv_usec = 0;
211 /* click sounds are unset by default, which causes us to internal
212 waveforms for clicks.
216 click_emphasis_data = 0;
218 click_emphasis_length = 0;
221 process_function = &Session::process_with_events;
223 if (Config->get_use_video_sync()) {
224 waiting_for_sync_offset = true;
226 waiting_for_sync_offset = false;
229 _current_frame_rate = 48000;
230 _base_frame_rate = 48000;
234 _smpte_offset_negative = true;
235 last_smpte_valid = false;
239 last_rr_session_dir = session_dirs.begin();
240 refresh_disk_space ();
242 // set_default_fade (0.2, 5.0); /* steepness, millisecs */
246 average_slave_delta = 1800;
247 have_first_delta_accumulator = false;
248 delta_accumulator_cnt = 0;
249 slave_state = Stopped;
251 _engine.GraphReordered.connect (mem_fun (*this, &Session::graph_reordered));
253 /* These are all static "per-class" signals */
255 RegionFactory::CheckNewRegion.connect (mem_fun (*this, &Session::add_region));
256 SourceFactory::SourceCreated.connect (mem_fun (*this, &Session::add_source));
257 PlaylistFactory::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
258 Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect));
259 NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection));
260 AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));
262 Controllable::Destroyed.connect (mem_fun (*this, &Session::remove_controllable));
264 IO::MoreChannels.connect (mem_fun (*this, &Session::ensure_buffers));
266 /* stop IO objects from doing stuff until we're ready for them */
268 IO::disable_panners ();
269 IO::disable_ports ();
270 IO::disable_connecting ();
274 Session::second_stage_init (bool new_session)
276 AudioFileSource::set_peak_dir (peak_dir());
279 if (load_state (_current_snapshot_name)) {
282 remove_empty_sounds ();
285 if (start_butler_thread()) {
289 /*if (start_midi_thread ()) {
293 // set_state() will call setup_raid_path(), but if it's a new session we need
294 // to call setup_raid_path() here.
296 if (set_state (*state_tree->root())) {
300 setup_raid_path(_path);
303 /* we can't save till after ::when_engine_running() is called,
304 because otherwise we save state with no connections made.
305 therefore, we reset _state_of_the_state because ::set_state()
306 will have cleared it.
308 we also have to include Loading so that any events that get
309 generated between here and the end of ::when_engine_running()
310 will be processed directly rather than queued.
313 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading);
315 // set_auto_input (true);
316 _locations.changed.connect (mem_fun (this, &Session::locations_changed));
317 _locations.added.connect (mem_fun (this, &Session::locations_added));
318 setup_click_sounds (0);
319 setup_midi_control ();
321 /* Pay attention ... */
323 _engine.Halted.connect (mem_fun (*this, &Session::engine_halted));
324 _engine.Xrun.connect (mem_fun (*this, &Session::xrun_recovery));
327 when_engine_running();
330 /* handle this one in a different way than all others, so that its clear what happened */
332 catch (AudioEngine::PortRegistrationFailure& err) {
333 error << _("Unable to create all required ports")
342 //send_full_time_code ();
343 _engine.transport_locate (0);
344 deliver_mmc (MIDI::MachineControl::cmdMmcReset, 0);
345 deliver_mmc (MIDI::MachineControl::cmdLocate, 0);
347 ControlProtocolManager::instance().set_session (*this);
350 _end_location_is_free = true;
352 _end_location_is_free = false;
359 Session::raid_path () const
363 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
368 return path.substr (0, path.length() - 1); // drop final colon
372 Session::setup_raid_path (string path)
374 string::size_type colon;
378 string::size_type len = path.length();
383 if (path.length() == 0) {
387 session_dirs.clear ();
389 for (string::size_type n = 0; n < len; ++n) {
390 if (path[n] == ':') {
397 /* no multiple search path, just one location (common case) */
401 session_dirs.push_back (sp);
408 if (fspath[fspath.length()-1] != '/') {
412 fspath += sound_dir (false);
414 AudioFileSource::set_search_path (fspath);
415 SMFSource::set_search_path (fspath); // FIXME: should be different
422 while ((colon = remaining.find_first_of (':')) != string::npos) {
425 sp.path = remaining.substr (0, colon);
426 session_dirs.push_back (sp);
428 /* add sounds to file search path */
431 if (fspath[fspath.length()-1] != '/') {
434 fspath += sound_dir (false);
437 remaining = remaining.substr (colon+1);
440 if (remaining.length()) {
447 if (fspath[fspath.length()-1] != '/') {
450 fspath += sound_dir (false);
453 session_dirs.push_back (sp);
456 /* set the AudioFileSource search path */
458 AudioFileSource::set_search_path (fspath);
459 SMFSource::set_search_path (fspath); // FIXME: should be different
461 /* reset the round-robin soundfile path thingie */
463 last_rr_session_dir = session_dirs.begin();
467 Session::initialize_start_and_end_locations (nframes_t start, nframes_t end)
469 start_location->set_end (start);
470 _locations.add (start_location);
472 end_location->set_end (end);
473 _locations.add (end_location);
477 Session::create_session_file ()
479 _state_of_the_state = Clean;
481 if (save_state (_current_snapshot_name)) {
482 error << "Could not create new session file" << endmsg;
489 Session::create_session_file_from_template (const string& template_path)
491 string out_path = _path + _name + statefile_suffix;
493 if(!copy_file (template_path, out_path)) {
494 error << string_compose (_("Could not use session template %1 to create new session."), template_path)
502 Session::create (bool& new_session, string* mix_template, nframes_t initial_length)
506 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
507 error << string_compose(_("Session: cannot create session dir \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
513 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
514 error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
518 /* if this is is an existing session with an old "sounds" directory, just use it. see Session::sound_dir() for more details */
520 if (!Glib::file_test (old_sound_dir(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
524 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
525 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
530 dir = dead_sound_dir ();
532 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
533 error << string_compose(_("Session: cannot create session dead sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
539 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
540 error << string_compose(_("Session: cannot create session export dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
545 /* check new_session so we don't overwrite an existing one */
548 if(!create_session_file_from_template(*mix_template)) return -1;
553 initialize_start_and_end_locations(0, initial_length);
555 if (!create_session_file()) return -1;
561 Session::load_diskstreams (const XMLNode& node)
564 XMLNodeConstIterator citer;
566 clist = node.children();
568 for (citer = clist.begin(); citer != clist.end(); ++citer) {
571 /* diskstreams added automatically by DiskstreamCreated handler */
572 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
573 boost::shared_ptr<AudioDiskstream> dstream (new AudioDiskstream (*this, **citer));
574 add_diskstream (dstream);
575 } else if ((*citer)->name() == "MidiDiskstream") {
576 boost::shared_ptr<MidiDiskstream> dstream (new MidiDiskstream (*this, **citer));
577 add_diskstream (dstream);
579 error << _("Session: unknown diskstream type in XML") << endmsg;
583 catch (failed_constructor& err) {
584 error << _("Session: could not load diskstream via XML state") << endmsg;
593 Session::maybe_write_autosave()
595 if (dirty() && record_status() != Recording) {
596 save_state("", true);
601 Session::remove_pending_capture_state ()
606 xml_path += _current_snapshot_name;
607 xml_path += pending_suffix;
609 unlink (xml_path.c_str());
612 /** Rename a state file.
613 * @param snapshot_name Snapshot name.
616 Session::rename_state (string old_name, string new_name)
618 if (old_name == _current_snapshot_name || old_name == _name) {
619 /* refuse to rename the current snapshot or the "main" one */
623 const string old_xml_path = _path + old_name + statefile_suffix;
624 const string new_xml_path = _path + new_name + statefile_suffix;
626 if (rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
627 error << string_compose(_("could not rename snapshot %1 to %2"), old_name, new_name) << endmsg;
631 /** Remove a state file.
632 * @param snapshot_name Snapshot name.
635 Session::remove_state (string snapshot_name)
637 if (snapshot_name == _current_snapshot_name || snapshot_name == _name) {
638 /* refuse to remove the current snapshot or the "main" one */
642 const string xml_path = _path + snapshot_name + statefile_suffix;
644 /* make a backup copy of the state file */
645 const string bak_path = xml_path + ".bak";
646 if (g_file_test (xml_path.c_str(), G_FILE_TEST_EXISTS)) {
647 copy_file (xml_path, bak_path);
651 unlink (xml_path.c_str());
655 Session::save_state (string snapshot_name, bool pending)
661 if (_state_of_the_state & CannotSave) {
665 if (!_engine.connected ()) {
666 error << _("Ardour's audio engine is not connected and state saving would lose all I/O connections. Session not saved")
671 tree.set_root (&get_state());
673 if (snapshot_name.empty()) {
674 snapshot_name = _current_snapshot_name;
679 /* proper save: use statefile_suffix (.ardour in English) */
681 xml_path += snapshot_name;
682 xml_path += statefile_suffix;
684 /* make a backup copy of the old file */
688 if (g_file_test (xml_path.c_str(), G_FILE_TEST_EXISTS)) {
689 copy_file (xml_path, bak_path);
694 /* pending save: use pending_suffix (.pending in English) */
696 xml_path += snapshot_name;
697 xml_path += pending_suffix;
704 tmp_path += snapshot_name;
707 // cerr << "actually writing state to " << xml_path << endl;
709 if (!tree.write (tmp_path)) {
710 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
711 unlink (tmp_path.c_str());
716 if (rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
717 error << string_compose (_("could not rename temporary session file %1 to %2"), tmp_path, xml_path) << endmsg;
718 unlink (tmp_path.c_str());
725 save_history (snapshot_name);
727 bool was_dirty = dirty();
729 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
732 DirtyChanged (); /* EMIT SIGNAL */
735 StateSaved (snapshot_name); /* EMIT SIGNAL */
742 Session::restore_state (string snapshot_name)
744 if (load_state (snapshot_name) == 0) {
745 set_state (*state_tree->root());
752 Session::load_state (string snapshot_name)
761 state_was_pending = false;
763 /* check for leftover pending state from a crashed capture attempt */
766 xmlpath += snapshot_name;
767 xmlpath += pending_suffix;
769 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
771 /* there is pending state from a crashed capture attempt */
773 if (AskAboutPendingState()) {
774 state_was_pending = true;
778 if (!state_was_pending) {
781 xmlpath += snapshot_name;
782 xmlpath += statefile_suffix;
785 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
786 error << string_compose(_("%1: session state information file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
790 state_tree = new XMLTree;
794 if (!state_tree->read (xmlpath)) {
795 error << string_compose(_("Could not understand ardour file %1"), xmlpath) << endmsg;
801 XMLNode& root (*state_tree->root());
803 if (root.name() != X_("Session")) {
804 error << string_compose (_("Session file %1 is not an Ardour session"), xmlpath) << endmsg;
810 const XMLProperty* prop;
813 if ((prop = root.property ("version")) == 0) {
814 /* no version implies very old version of Ardour */
818 major_version = atoi (prop->value()); // grab just the first number before the period
819 if (major_version < 2) {
828 backup_path += snapshot_name;
830 backup_path += statefile_suffix;
832 info << string_compose (_("Copying old session file %1 to %2\nUse %2 with Ardour versions before 2.0 from now on"),
833 xmlpath, backup_path)
836 copy_file (xmlpath, backup_path);
838 /* if it fails, don't worry. right? */
845 Session::load_options (const XMLNode& node)
849 LocaleGuard lg (X_("POSIX"));
851 Config->set_variables (node, ConfigVariableBase::Session);
853 if ((child = find_named_node (node, "end-marker-is-free")) != 0) {
854 if ((prop = child->property ("val")) != 0) {
855 _end_location_is_free = (prop->value() == "yes");
863 Session::save_config_options_predicate (ConfigVariableBase::Owner owner) const
865 const ConfigVariableBase::Owner modified_by_session_or_user = (ConfigVariableBase::Owner)
866 (ConfigVariableBase::Session|ConfigVariableBase::Interface);
868 return owner & modified_by_session_or_user;
872 Session::get_options () const
875 LocaleGuard lg (X_("POSIX"));
877 XMLNode& option_root = Config->get_variables (mem_fun (*this, &Session::save_config_options_predicate));
879 child = option_root.add_child ("end-marker-is-free");
880 child->add_property ("val", _end_location_is_free ? "yes" : "no");
892 Session::get_template()
894 /* if we don't disable rec-enable, diskstreams
895 will believe they need to store their capture
896 sources in their state node.
899 disable_record (false);
905 Session::state(bool full_state)
907 XMLNode* node = new XMLNode("Session");
910 // store libardour version, just in case
912 snprintf(buf, sizeof(buf)-1, "%d.%d.%d",
913 libardour_major_version, libardour_minor_version, libardour_micro_version);
914 node->add_property("version", string(buf));
916 /* store configuration settings */
921 node->add_property ("name", _name);
923 if (session_dirs.size() > 1) {
927 vector<space_and_path>::iterator i = session_dirs.begin();
928 vector<space_and_path>::iterator next;
930 ++i; /* skip the first one */
934 while (i != session_dirs.end()) {
938 if (next != session_dirs.end()) {
948 child = node->add_child ("Path");
949 child->add_content (p);
953 /* save the ID counter */
955 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
956 node->add_property ("id-counter", buf);
958 /* various options */
960 node->add_child_nocopy (get_options());
962 child = node->add_child ("Sources");
965 Glib::Mutex::Lock sl (source_lock);
967 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
969 /* Don't save information about AudioFileSources that are empty */
971 boost::shared_ptr<AudioFileSource> fs;
973 if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) {
975 /* Don't save sources that are empty, unless they're destructive (which are OK
976 if they are empty, because we will re-use them every time.)
979 if (!fs->destructive()) {
980 if (fs->length() == 0) {
986 child->add_child_nocopy (siter->second->get_state());
990 child = node->add_child ("Regions");
993 Glib::Mutex::Lock rl (region_lock);
995 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
997 /* only store regions not attached to playlists */
999 if (i->second->playlist() == 0) {
1000 child->add_child_nocopy (i->second->state (true));
1005 child = node->add_child ("DiskStreams");
1008 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
1009 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
1010 if (!(*i)->hidden()) {
1011 child->add_child_nocopy ((*i)->get_state());
1017 node->add_child_nocopy (_locations.get_state());
1019 // for a template, just create a new Locations, populate it
1020 // with the default start and end, and get the state for that.
1022 Location* start = new Location(0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
1023 Location* end = new Location(0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
1026 end->set_end(compute_initial_length());
1028 node->add_child_nocopy (loc.get_state());
1031 child = node->add_child ("Connections");
1033 Glib::Mutex::Lock lm (connection_lock);
1034 for (ConnectionList::iterator i = _connections.begin(); i != _connections.end(); ++i) {
1035 if (!(*i)->system_dependent()) {
1036 child->add_child_nocopy ((*i)->get_state());
1041 child = node->add_child ("Routes");
1043 boost::shared_ptr<RouteList> r = routes.reader ();
1045 RoutePublicOrderSorter cmp;
1046 RouteList public_order (*r);
1047 public_order.sort (cmp);
1049 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1050 if (!(*i)->hidden()) {
1052 child->add_child_nocopy ((*i)->get_state());
1054 child->add_child_nocopy ((*i)->get_template());
1061 child = node->add_child ("EditGroups");
1062 for (list<RouteGroup *>::iterator i = edit_groups.begin(); i != edit_groups.end(); ++i) {
1063 child->add_child_nocopy ((*i)->get_state());
1066 child = node->add_child ("MixGroups");
1067 for (list<RouteGroup *>::iterator i = mix_groups.begin(); i != mix_groups.end(); ++i) {
1068 child->add_child_nocopy ((*i)->get_state());
1071 child = node->add_child ("Playlists");
1072 for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
1073 if (!(*i)->hidden()) {
1074 if (!(*i)->empty()) {
1076 child->add_child_nocopy ((*i)->get_state());
1078 child->add_child_nocopy ((*i)->get_template());
1084 child = node->add_child ("UnusedPlaylists");
1085 for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
1086 if (!(*i)->hidden()) {
1087 if (!(*i)->empty()) {
1089 child->add_child_nocopy ((*i)->get_state());
1091 child->add_child_nocopy ((*i)->get_template());
1099 child = node->add_child ("Click");
1100 child->add_child_nocopy (_click_io->state (full_state));
1104 child = node->add_child ("NamedSelections");
1105 for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) {
1107 child->add_child_nocopy ((*i)->get_state());
1112 node->add_child_nocopy (_tempo_map->get_state());
1114 node->add_child_nocopy (get_control_protocol_state());
1117 node->add_child_copy (*_extra_xml);
1124 Session::get_control_protocol_state ()
1126 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1127 return cpm.get_state();
1131 Session::set_state (const XMLNode& node)
1135 const XMLProperty* prop;
1138 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1140 if (node.name() != X_("Session")){
1141 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1145 if ((prop = node.property ("name")) != 0) {
1146 _name = prop->value ();
1149 setup_raid_path(_path);
1151 if ((prop = node.property (X_("id-counter"))) != 0) {
1153 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1154 ID::init_counter (x);
1156 /* old sessions used a timebased counter, so fake
1157 the startup ID counter based on a standard
1162 ID::init_counter (now);
1166 IO::disable_ports ();
1167 IO::disable_connecting ();
1169 /* Object loading order:
1187 if (use_config_midi_ports ()) {
1190 if ((child = find_named_node (node, "extra")) != 0) {
1191 _extra_xml = new XMLNode (*child);
1194 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1195 load_options (*child);
1196 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1197 load_options (*child);
1199 error << _("Session: XML state has no options section") << endmsg;
1202 if ((child = find_named_node (node, "Locations")) == 0) {
1203 error << _("Session: XML state has no locations section") << endmsg;
1205 } else if (_locations.set_state (*child)) {
1211 if ((location = _locations.auto_loop_location()) != 0) {
1212 set_auto_loop_location (location);
1215 if ((location = _locations.auto_punch_location()) != 0) {
1216 set_auto_punch_location (location);
1219 if ((location = _locations.end_location()) == 0) {
1220 _locations.add (end_location);
1222 delete end_location;
1223 end_location = location;
1226 if ((location = _locations.start_location()) == 0) {
1227 _locations.add (start_location);
1229 delete start_location;
1230 start_location = location;
1233 AudioFileSource::set_header_position_offset (start_location->start());
1235 if ((child = find_named_node (node, "Sources")) == 0) {
1236 error << _("Session: XML state has no sources section") << endmsg;
1238 } else if (load_sources (*child)) {
1242 if ((child = find_named_node (node, "Regions")) == 0) {
1243 error << _("Session: XML state has no Regions section") << endmsg;
1245 } else if (load_regions (*child)) {
1249 if ((child = find_named_node (node, "Playlists")) == 0) {
1250 error << _("Session: XML state has no playlists section") << endmsg;
1252 } else if (load_playlists (*child)) {
1256 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1258 } else if (load_unused_playlists (*child)) {
1262 if ((child = find_named_node (node, "NamedSelections")) != 0) {
1263 if (load_named_selections (*child)) {
1268 if ((child = find_named_node (node, "DiskStreams")) == 0) {
1269 error << _("Session: XML state has no diskstreams section") << endmsg;
1271 } else if (load_diskstreams (*child)) {
1275 if ((child = find_named_node (node, "Connections")) == 0) {
1276 error << _("Session: XML state has no connections section") << endmsg;
1278 } else if (load_connections (*child)) {
1282 if ((child = find_named_node (node, "EditGroups")) == 0) {
1283 error << _("Session: XML state has no edit groups section") << endmsg;
1285 } else if (load_edit_groups (*child)) {
1289 if ((child = find_named_node (node, "MixGroups")) == 0) {
1290 error << _("Session: XML state has no mix groups section") << endmsg;
1292 } else if (load_mix_groups (*child)) {
1296 if ((child = find_named_node (node, "TempoMap")) == 0) {
1297 error << _("Session: XML state has no Tempo Map section") << endmsg;
1299 } else if (_tempo_map->set_state (*child)) {
1303 if ((child = find_named_node (node, "Routes")) == 0) {
1304 error << _("Session: XML state has no routes section") << endmsg;
1306 } else if (load_routes (*child)) {
1310 if ((child = find_named_node (node, "Click")) == 0) {
1311 warning << _("Session: XML state has no click section") << endmsg;
1312 } else if (_click_io) {
1313 _click_io->set_state (*child);
1316 if ((child = find_named_node (node, "ControlProtocols")) != 0) {
1317 ControlProtocolManager::instance().set_protocol_states (*child);
1320 /* here beginneth the second phase ... */
1322 StateReady (); /* EMIT SIGNAL */
1324 _state_of_the_state = Clean;
1326 if (state_was_pending) {
1327 save_state (_current_snapshot_name);
1328 remove_pending_capture_state ();
1329 state_was_pending = false;
1339 Session::load_routes (const XMLNode& node)
1342 XMLNodeConstIterator niter;
1343 RouteList new_routes;
1345 nlist = node.children();
1349 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1351 boost::shared_ptr<Route> route (XMLRouteFactory (**niter));
1354 error << _("Session: cannot create Route from XML description.") << endmsg;
1358 new_routes.push_back (route);
1361 add_routes (new_routes);
1366 boost::shared_ptr<Route>
1367 Session::XMLRouteFactory (const XMLNode& node)
1369 if (node.name() != "Route") {
1370 return boost::shared_ptr<Route> ((Route*) 0);
1373 bool has_diskstream = (node.property ("diskstream") != 0 || node.property ("diskstream-id") != 0);
1375 DataType type = DataType::AUDIO;
1376 const XMLProperty* prop = node.property("default-type");
1378 type = DataType(prop->value());
1380 assert(type != DataType::NIL);
1382 if (has_diskstream) {
1383 if (type == DataType::AUDIO) {
1384 boost::shared_ptr<Route> ret (new AudioTrack (*this, node));
1387 boost::shared_ptr<Route> ret (new MidiTrack (*this, node));
1391 boost::shared_ptr<Route> ret (new Route (*this, node));
1397 Session::load_regions (const XMLNode& node)
1400 XMLNodeConstIterator niter;
1401 boost::shared_ptr<Region> region;
1403 nlist = node.children();
1407 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1408 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1409 error << _("Session: cannot create Region from XML description.") << endmsg;
1416 boost::shared_ptr<Region>
1417 Session::XMLRegionFactory (const XMLNode& node, bool full)
1419 const XMLProperty* type = node.property("type");
1423 if ( !type || type->value() == "audio" ) {
1425 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1427 } else if (type->value() == "midi") {
1429 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1433 } catch (failed_constructor& err) {
1434 return boost::shared_ptr<Region> ();
1437 return boost::shared_ptr<Region> ();
1440 boost::shared_ptr<AudioRegion>
1441 Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
1443 const XMLProperty* prop;
1444 boost::shared_ptr<Source> source;
1445 boost::shared_ptr<AudioSource> as;
1447 uint32_t nchans = 1;
1450 if (node.name() != X_("Region")) {
1451 return boost::shared_ptr<AudioRegion>();
1454 if ((prop = node.property (X_("channels"))) != 0) {
1455 nchans = atoi (prop->value().c_str());
1459 if ((prop = node.property ("name")) == 0) {
1460 cerr << "no name for this region\n";
1464 if ((prop = node.property (X_("source-0"))) == 0) {
1465 if ((prop = node.property ("source")) == 0) {
1466 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1467 return boost::shared_ptr<AudioRegion>();
1471 PBD::ID s_id (prop->value());
1473 if ((source = source_by_id (s_id)) == 0) {
1474 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1475 return boost::shared_ptr<AudioRegion>();
1478 as = boost::dynamic_pointer_cast<AudioSource>(source);
1480 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1481 return boost::shared_ptr<AudioRegion>();
1484 sources.push_back (as);
1486 /* pickup other channels */
1488 for (uint32_t n=1; n < nchans; ++n) {
1489 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1490 if ((prop = node.property (buf)) != 0) {
1492 PBD::ID id2 (prop->value());
1494 if ((source = source_by_id (id2)) == 0) {
1495 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1496 return boost::shared_ptr<AudioRegion>();
1499 as = boost::dynamic_pointer_cast<AudioSource>(source);
1501 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1502 return boost::shared_ptr<AudioRegion>();
1504 sources.push_back (as);
1509 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1511 /* a final detail: this is the one and only place that we know how long missing files are */
1513 if (region->whole_file()) {
1514 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1515 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1517 sfp->set_length (region->length());
1527 catch (failed_constructor& err) {
1528 return boost::shared_ptr<AudioRegion>();
1532 boost::shared_ptr<MidiRegion>
1533 Session::XMLMidiRegionFactory (const XMLNode& node, bool full)
1535 const XMLProperty* prop;
1536 boost::shared_ptr<Source> source;
1537 boost::shared_ptr<MidiSource> ms;
1538 MidiRegion::SourceList sources;
1539 uint32_t nchans = 1;
1541 if (node.name() != X_("Region")) {
1542 return boost::shared_ptr<MidiRegion>();
1545 if ((prop = node.property (X_("channels"))) != 0) {
1546 nchans = atoi (prop->value().c_str());
1549 // Multiple midi channels? that's just crazy talk
1550 assert(nchans == 1);
1552 if ((prop = node.property (X_("source-0"))) == 0) {
1553 if ((prop = node.property ("source")) == 0) {
1554 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1555 return boost::shared_ptr<MidiRegion>();
1559 PBD::ID s_id (prop->value());
1561 if ((source = source_by_id (s_id)) == 0) {
1562 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1563 return boost::shared_ptr<MidiRegion>();
1566 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1568 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1569 return boost::shared_ptr<MidiRegion>();
1572 sources.push_back (ms);
1575 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1579 catch (failed_constructor& err) {
1580 return boost::shared_ptr<MidiRegion>();
1585 Session::get_sources_as_xml ()
1588 XMLNode* node = new XMLNode (X_("Sources"));
1589 Glib::Mutex::Lock lm (source_lock);
1591 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1592 node->add_child_nocopy (i->second->get_state());
1595 /* XXX get MIDI and other sources here */
1601 Session::path_from_region_name (string name, string identifier)
1603 char buf[PATH_MAX+1];
1605 string dir = discover_best_sound_dir ();
1607 for (n = 0; n < 999999; ++n) {
1608 if (identifier.length()) {
1609 snprintf (buf, sizeof(buf), "%s/%s%s%" PRIu32 ".wav", dir.c_str(), name.c_str(),
1610 identifier.c_str(), n);
1612 snprintf (buf, sizeof(buf), "%s/%s-%" PRIu32 ".wav", dir.c_str(), name.c_str(), n);
1615 if (!Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
1620 error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1629 Session::load_sources (const XMLNode& node)
1632 XMLNodeConstIterator niter;
1633 boost::shared_ptr<Source> source;
1635 nlist = node.children();
1639 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1642 if ((source = XMLSourceFactory (**niter)) == 0) {
1643 error << _("Session: cannot create Source from XML description.") << endmsg;
1647 catch (non_existent_source& err) {
1648 warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
1649 source = SourceFactory::createSilent (*this, **niter, max_frames, _current_frame_rate);
1656 boost::shared_ptr<Source>
1657 Session::XMLSourceFactory (const XMLNode& node)
1659 if (node.name() != "Source") {
1660 return boost::shared_ptr<Source>();
1664 return SourceFactory::create (*this, node);
1667 catch (failed_constructor& err) {
1668 error << _("Found a sound file that cannot be used by Ardour. Talk to the progammers.") << endmsg;
1669 return boost::shared_ptr<Source>();
1674 Session::save_template (string template_name)
1677 string xml_path, bak_path, template_path;
1679 if (_state_of_the_state & CannotSave) {
1684 string dir = template_dir();
1686 if ((dp = opendir (dir.c_str()))) {
1689 if (g_mkdir_with_parents (dir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
1690 error << string_compose(_("Could not create mix templates directory \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
1695 tree.set_root (&get_template());
1698 xml_path += template_name;
1699 xml_path += template_suffix;
1701 ifstream in(xml_path.c_str());
1704 warning << string_compose(_("Template \"%1\" already exists - new version not created"), template_name) << endmsg;
1710 if (!tree.write (xml_path)) {
1711 error << _("mix template not saved") << endmsg;
1719 Session::rename_template (string old_name, string new_name)
1721 string old_path = template_dir() + old_name + template_suffix;
1722 string new_path = template_dir() + new_name + template_suffix;
1724 return rename (old_path.c_str(), new_path.c_str());
1728 Session::delete_template (string name)
1730 string template_path = template_dir();
1731 template_path += name;
1732 template_path += template_suffix;
1734 return remove (template_path.c_str());
1738 Session::refresh_disk_space ()
1741 struct statfs statfsbuf;
1742 vector<space_and_path>::iterator i;
1743 Glib::Mutex::Lock lm (space_lock);
1746 /* get freespace on every FS that is part of the session path */
1748 _total_free_4k_blocks = 0;
1750 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
1751 statfs ((*i).path.c_str(), &statfsbuf);
1753 scale = statfsbuf.f_bsize/4096.0;
1755 (*i).blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
1756 _total_free_4k_blocks += (*i).blocks;
1762 Session::ensure_sound_dir (string path, string& result)
1767 /* Ensure that the parent directory exists */
1769 if (g_mkdir_with_parents (path.c_str(), 0775)) {
1770 error << string_compose(_("cannot create session directory \"%1\"; ignored"), path) << endmsg;
1774 /* Ensure that the sounds directory exists */
1778 result += sound_dir_name;
1780 if (g_mkdir_with_parents (result.c_str(), 0775)) {
1781 error << string_compose(_("cannot create sounds directory \"%1\"; ignored"), result) << endmsg;
1787 dead += dead_sound_dir_name;
1789 if (g_mkdir_with_parents (dead.c_str(), 0775)) {
1790 error << string_compose(_("cannot create dead sounds directory \"%1\"; ignored"), dead) << endmsg;
1796 peak += peak_dir_name;
1798 if (g_mkdir_with_parents (peak.c_str(), 0775)) {
1799 error << string_compose(_("cannot create peak file directory \"%1\"; ignored"), peak) << endmsg;
1803 /* callers expect this to be terminated ... */
1810 Session::discover_best_sound_dir (bool destructive)
1812 vector<space_and_path>::iterator i;
1815 /* handle common case without system calls */
1817 if (session_dirs.size() == 1) {
1821 /* OK, here's the algorithm we're following here:
1823 We want to select which directory to use for
1824 the next file source to be created. Ideally,
1825 we'd like to use a round-robin process so as to
1826 get maximum performance benefits from splitting
1827 the files across multiple disks.
1829 However, in situations without much diskspace, an
1830 RR approach may end up filling up a filesystem
1831 with new files while others still have space.
1832 Its therefore important to pay some attention to
1833 the freespace in the filesystem holding each
1834 directory as well. However, if we did that by
1835 itself, we'd keep creating new files in the file
1836 system with the most space until it was as full
1837 as all others, thus negating any performance
1838 benefits of this RAID-1 like approach.
1840 So, we use a user-configurable space threshold. If
1841 there are at least 2 filesystems with more than this
1842 much space available, we use RR selection between them.
1843 If not, then we pick the filesystem with the most space.
1845 This gets a good balance between the two
1849 refresh_disk_space ();
1851 int free_enough = 0;
1853 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
1854 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
1859 if (free_enough >= 2) {
1861 bool found_it = false;
1863 /* use RR selection process, ensuring that the one
1867 i = last_rr_session_dir;
1870 if (++i == session_dirs.end()) {
1871 i = session_dirs.begin();
1874 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
1875 if (ensure_sound_dir ((*i).path, result) == 0) {
1876 last_rr_session_dir = i;
1882 } while (i != last_rr_session_dir);
1885 result = sound_dir();
1890 /* pick FS with the most freespace (and that
1891 seems to actually work ...)
1894 vector<space_and_path> sorted;
1895 space_and_path_ascending_cmp cmp;
1897 sorted = session_dirs;
1898 sort (sorted.begin(), sorted.end(), cmp);
1900 for (i = sorted.begin(); i != sorted.end(); ++i) {
1901 if (ensure_sound_dir ((*i).path, result) == 0) {
1902 last_rr_session_dir = i;
1907 /* if the above fails, fall back to the most simplistic solution */
1909 if (i == sorted.end()) {
1918 Session::load_playlists (const XMLNode& node)
1921 XMLNodeConstIterator niter;
1922 boost::shared_ptr<Playlist> playlist;
1924 nlist = node.children();
1928 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1930 if ((playlist = XMLPlaylistFactory (**niter)) == 0) {
1931 error << _("Session: cannot create Playlist from XML description.") << endmsg;
1939 Session::load_unused_playlists (const XMLNode& node)
1942 XMLNodeConstIterator niter;
1943 boost::shared_ptr<Playlist> playlist;
1945 nlist = node.children();
1949 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1951 if ((playlist = XMLPlaylistFactory (**niter)) == 0) {
1952 error << _("Session: cannot create Playlist from XML description.") << endmsg;
1956 // now manually untrack it
1958 track_playlist (false, boost::weak_ptr<Playlist> (playlist));
1964 boost::shared_ptr<Playlist>
1965 Session::XMLPlaylistFactory (const XMLNode& node)
1968 return PlaylistFactory::create (*this, node);
1971 catch (failed_constructor& err) {
1972 return boost::shared_ptr<Playlist>();
1977 Session::load_named_selections (const XMLNode& node)
1980 XMLNodeConstIterator niter;
1983 nlist = node.children();
1987 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1989 if ((ns = XMLNamedSelectionFactory (**niter)) == 0) {
1990 error << _("Session: cannot create Named Selection from XML description.") << endmsg;
1998 Session::XMLNamedSelectionFactory (const XMLNode& node)
2001 return new NamedSelection (*this, node);
2004 catch (failed_constructor& err) {
2010 Session::dead_sound_dir () const
2013 res += dead_sound_dir_name;
2019 Session::old_sound_dir (bool with_path) const
2027 res += old_sound_dir_name;
2033 Session::sound_dir (bool with_path) const
2044 res += interchange_dir_name;
2046 res += legalize_for_path (_name);
2048 res += sound_dir_name;
2056 /* if this already exists, don't check for the old session sound directory */
2058 if (Glib::file_test (full, Glib::FILE_TEST_IS_DIR|Glib::FILE_TEST_EXISTS)) {
2062 /* possibly support old session structure */
2065 string old_withpath;
2067 old_nopath += old_sound_dir_name;
2070 old_withpath = _path;
2071 old_withpath += old_sound_dir_name;
2073 if (Glib::file_test (old_withpath.c_str(), Glib::FILE_TEST_IS_DIR|Glib::FILE_TEST_EXISTS)) {
2075 return old_withpath;
2080 /* ok, old "sounds" directory isn't there, return the new path */
2086 Session::peak_dir () const
2089 res += peak_dir_name;
2095 Session::automation_dir () const
2098 res += "automation/";
2103 Session::template_dir ()
2105 string path = get_user_ardour_path();
2106 path += "templates/";
2112 Session::export_dir () const
2115 res += export_dir_name;
2121 Session::suffixed_search_path (string suffix, bool data)
2125 path += get_user_ardour_path();
2126 if (path[path.length()-1] != ':') {
2131 path += get_system_data_path();
2133 path += get_system_module_path();
2136 vector<string> split_path;
2138 split (path, split_path, ':');
2141 for (vector<string>::iterator i = split_path.begin(); i != split_path.end(); ++i) {
2146 if (distance (i, split_path.end()) != 1) {
2155 Session::template_path ()
2157 return suffixed_search_path (X_("templates"), true);
2161 Session::control_protocol_path ()
2163 return suffixed_search_path (X_("surfaces"), false);
2167 Session::load_connections (const XMLNode& node)
2169 XMLNodeList nlist = node.children();
2170 XMLNodeConstIterator niter;
2174 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2175 if ((*niter)->name() == "InputConnection") {
2176 add_connection (new ARDOUR::InputConnection (**niter));
2177 } else if ((*niter)->name() == "OutputConnection") {
2178 add_connection (new ARDOUR::OutputConnection (**niter));
2180 error << string_compose(_("Unknown node \"%1\" found in Connections list from state file"), (*niter)->name()) << endmsg;
2189 Session::load_edit_groups (const XMLNode& node)
2191 return load_route_groups (node, true);
2195 Session::load_mix_groups (const XMLNode& node)
2197 return load_route_groups (node, false);
2201 Session::load_route_groups (const XMLNode& node, bool edit)
2203 XMLNodeList nlist = node.children();
2204 XMLNodeConstIterator niter;
2209 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2210 if ((*niter)->name() == "RouteGroup") {
2212 rg = add_edit_group ("");
2213 rg->set_state (**niter);
2215 rg = add_mix_group ("");
2216 rg->set_state (**niter);
2225 state_file_filter (const string &str, void *arg)
2227 return (str.length() > strlen(statefile_suffix) &&
2228 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2232 bool operator()(const string* a, const string* b) {
2238 remove_end(string* state)
2240 string statename(*state);
2242 string::size_type start,end;
2243 if ((start = statename.find_last_of ('/')) != string::npos) {
2244 statename = statename.substr (start+1);
2247 if ((end = statename.rfind(".ardour")) == string::npos) {
2248 end = statename.length();
2251 return new string(statename.substr (0, end));
2255 Session::possible_states (string path)
2257 PathScanner scanner;
2258 vector<string*>* states = scanner (path, state_file_filter, 0, false, false);
2260 transform(states->begin(), states->end(), states->begin(), remove_end);
2263 sort (states->begin(), states->end(), cmp);
2269 Session::possible_states () const
2271 return possible_states(_path);
2275 Session::auto_save()
2277 save_state (_current_snapshot_name);
2281 Session::add_edit_group (string name)
2283 RouteGroup* rg = new RouteGroup (*this, name);
2284 edit_groups.push_back (rg);
2285 edit_group_added (rg); /* EMIT SIGNAL */
2291 Session::add_mix_group (string name)
2293 RouteGroup* rg = new RouteGroup (*this, name, RouteGroup::Relative);
2294 mix_groups.push_back (rg);
2295 mix_group_added (rg); /* EMIT SIGNAL */
2301 Session::remove_edit_group (RouteGroup& rg)
2303 list<RouteGroup*>::iterator i;
2305 if ((i = find (edit_groups.begin(), edit_groups.end(), &rg)) != edit_groups.end()) {
2306 (*i)->apply (&Route::drop_edit_group, this);
2307 edit_groups.erase (i);
2308 edit_group_removed (); /* EMIT SIGNAL */
2315 Session::remove_mix_group (RouteGroup& rg)
2317 list<RouteGroup*>::iterator i;
2319 if ((i = find (mix_groups.begin(), mix_groups.end(), &rg)) != mix_groups.end()) {
2320 (*i)->apply (&Route::drop_mix_group, this);
2321 mix_groups.erase (i);
2322 mix_group_removed (); /* EMIT SIGNAL */
2329 Session::mix_group_by_name (string name)
2331 list<RouteGroup *>::iterator i;
2333 for (i = mix_groups.begin(); i != mix_groups.end(); ++i) {
2334 if ((*i)->name() == name) {
2342 Session::edit_group_by_name (string name)
2344 list<RouteGroup *>::iterator i;
2346 for (i = edit_groups.begin(); i != edit_groups.end(); ++i) {
2347 if ((*i)->name() == name) {
2355 Session::begin_reversible_command (string name)
2357 current_trans = new UndoTransaction;
2358 current_trans->set_name (name);
2362 Session::commit_reversible_command (Command *cmd)
2367 current_trans->add_command (cmd);
2370 gettimeofday (&now, 0);
2371 current_trans->set_timestamp (now);
2373 _history.add (current_trans);
2376 Session::GlobalRouteBooleanState
2377 Session::get_global_route_boolean (bool (Route::*method)(void) const)
2379 GlobalRouteBooleanState s;
2380 boost::shared_ptr<RouteList> r = routes.reader ();
2382 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
2383 if (!(*i)->hidden()) {
2384 RouteBooleanState v;
2387 Route* r = (*i).get();
2388 v.second = (r->*method)();
2397 Session::GlobalRouteMeterState
2398 Session::get_global_route_metering ()
2400 GlobalRouteMeterState s;
2401 boost::shared_ptr<RouteList> r = routes.reader ();
2403 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
2404 if (!(*i)->hidden()) {
2408 v.second = (*i)->meter_point();
2418 Session::set_global_route_metering (GlobalRouteMeterState s, void* arg)
2420 for (GlobalRouteMeterState::iterator i = s.begin(); i != s.end(); ++i) {
2422 boost::shared_ptr<Route> r = (i->first.lock());
2425 r->set_meter_point (i->second, arg);
2431 Session::set_global_route_boolean (GlobalRouteBooleanState s, void (Route::*method)(bool, void*), void* arg)
2433 for (GlobalRouteBooleanState::iterator i = s.begin(); i != s.end(); ++i) {
2435 boost::shared_ptr<Route> r = (i->first.lock());
2438 Route* rp = r.get();
2439 (rp->*method) (i->second, arg);
2445 Session::set_global_mute (GlobalRouteBooleanState s, void* src)
2447 set_global_route_boolean (s, &Route::set_mute, src);
2451 Session::set_global_solo (GlobalRouteBooleanState s, void* src)
2453 set_global_route_boolean (s, &Route::set_solo, src);
2457 Session::set_global_record_enable (GlobalRouteBooleanState s, void* src)
2459 set_global_route_boolean (s, &Route::set_record_enable, src);
2464 Session::global_mute_memento (void* src)
2466 return sigc::bind (mem_fun (*this, &Session::set_global_mute), get_global_route_boolean (&Route::muted), src);
2470 Session::global_metering_memento (void* src)
2472 return sigc::bind (mem_fun (*this, &Session::set_global_route_metering), get_global_route_metering (), src);
2476 Session::global_solo_memento (void* src)
2478 return sigc::bind (mem_fun (*this, &Session::set_global_solo), get_global_route_boolean (&Route::soloed), src);
2482 Session::global_record_enable_memento (void* src)
2484 return sigc::bind (mem_fun (*this, &Session::set_global_record_enable), get_global_route_boolean (&Route::record_enabled), src);
2489 template_filter (const string &str, void *arg)
2491 return (str.length() > strlen(template_suffix) &&
2492 str.find (template_suffix) == (str.length() - strlen (template_suffix)));
2496 Session::get_template_list (list<string> &template_names)
2498 vector<string *> *templates;
2499 PathScanner scanner;
2502 path = template_path ();
2504 templates = scanner (path, template_filter, 0, false, true);
2506 vector<string*>::iterator i;
2507 for (i = templates->begin(); i != templates->end(); ++i) {
2508 string fullpath = *(*i);
2511 start = fullpath.find_last_of ('/') + 1;
2512 if ((end = fullpath.find_last_of ('.')) <0) {
2513 end = fullpath.length();
2516 template_names.push_back(fullpath.substr(start, (end-start)));
2521 Session::read_favorite_dirs (FavoriteDirs & favs)
2523 string path = get_user_ardour_path();
2524 path += "/favorite_dirs";
2526 ifstream fav (path.c_str());
2531 if (errno != ENOENT) {
2532 //error << string_compose (_("cannot open favorite file %1 (%2)"), path, strerror (errno)) << endmsg;
2543 getline(fav, newfav);
2549 favs.push_back (newfav);
2556 Session::write_favorite_dirs (FavoriteDirs & favs)
2558 string path = get_user_ardour_path();
2559 path += "/favorite_dirs";
2561 ofstream fav (path.c_str());
2567 for (FavoriteDirs::iterator i = favs.begin(); i != favs.end(); ++i) {
2568 fav << (*i) << endl;
2575 accept_all_non_peak_files (const string& path, void *arg)
2577 return (path.length() > 5 && path.find (".peak") != (path.length() - 5));
2581 accept_all_state_files (const string& path, void *arg)
2583 return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
2587 Session::find_all_sources (string path, set<string>& result)
2592 if (!tree.read (path)) {
2596 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2601 XMLNodeConstIterator niter;
2603 nlist = node->children();
2607 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2611 if ((prop = (*niter)->property (X_("name"))) == 0) {
2615 if (prop->value()[0] == '/') {
2616 /* external file, ignore */
2620 string path = _path; /* /-terminated */
2621 path += sound_dir_name;
2623 path += prop->value();
2625 result.insert (path);
2632 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2634 PathScanner scanner;
2635 vector<string*>* state_files;
2637 string this_snapshot_path;
2643 if (ripped[ripped.length()-1] == '/') {
2644 ripped = ripped.substr (0, ripped.length() - 1);
2647 state_files = scanner (ripped, accept_all_state_files, (void *) 0, false, true);
2649 if (state_files == 0) {
2654 this_snapshot_path = _path;
2655 this_snapshot_path += _current_snapshot_name;
2656 this_snapshot_path += statefile_suffix;
2658 for (vector<string*>::iterator i = state_files->begin(); i != state_files->end(); ++i) {
2660 if (exclude_this_snapshot && **i == this_snapshot_path) {
2664 if (find_all_sources (**i, result) < 0) {
2672 struct RegionCounter {
2673 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2674 AudioSourceList::iterator iter;
2675 boost::shared_ptr<Region> region;
2678 RegionCounter() : count (0) {}
2682 Session::cleanup_sources (Session::cleanup_report& rep)
2684 vector<boost::shared_ptr<Source> > dead_sources;
2685 vector<boost::shared_ptr<Playlist> > playlists_tbd;
2686 PathScanner scanner;
2688 vector<space_and_path>::iterator i;
2689 vector<space_and_path>::iterator nexti;
2690 vector<string*>* soundfiles;
2691 vector<string> unused;
2692 set<string> all_sources;
2697 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2699 /* step 1: consider deleting all unused playlists */
2701 for (PlaylistList::iterator x = unused_playlists.begin(); x != unused_playlists.end(); ++x) {
2704 status = AskAboutPlaylistDeletion (*x);
2713 playlists_tbd.push_back (*x);
2717 /* leave it alone */
2722 /* now delete any that were marked for deletion */
2724 for (vector<boost::shared_ptr<Playlist> >::iterator x = playlists_tbd.begin(); x != playlists_tbd.end(); ++x) {
2725 (*x)->drop_references ();
2728 playlists_tbd.clear ();
2730 /* step 2: find all un-used sources */
2735 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2737 SourceMap::iterator tmp;
2742 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2746 if (!i->second->used() && i->second->length() > 0) {
2747 dead_sources.push_back (i->second);
2748 i->second->GoingAway();
2754 /* build a list of all the possible sound directories for the session */
2756 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2761 sound_path += (*i).path;
2762 sound_path += sound_dir (false);
2764 if (nexti != session_dirs.end()) {
2771 /* now do the same thing for the files that ended up in the sounds dir(s)
2772 but are not referenced as sources in any snapshot.
2775 soundfiles = scanner (sound_path, accept_all_non_peak_files, (void *) 0, false, true);
2777 if (soundfiles == 0) {
2781 /* find all sources, but don't use this snapshot because the
2782 state file on disk still references sources we may have already
2786 find_all_sources_across_snapshots (all_sources, true);
2788 /* add our current source list
2791 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2792 boost::shared_ptr<AudioFileSource> fs;
2794 if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (i->second)) != 0) {
2795 all_sources.insert (fs->path());
2799 char tmppath1[PATH_MAX+1];
2800 char tmppath2[PATH_MAX+1];
2802 for (vector<string*>::iterator x = soundfiles->begin(); x != soundfiles->end(); ++x) {
2807 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2809 realpath(spath.c_str(), tmppath1);
2810 realpath((*i).c_str(), tmppath2);
2812 if (strcmp(tmppath1, tmppath2) == 0) {
2819 unused.push_back (spath);
2823 /* now try to move all unused files into the "dead_sounds" directory(ies) */
2825 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2826 struct stat statbuf;
2828 rep.paths.push_back (*x);
2829 if (stat ((*x).c_str(), &statbuf) == 0) {
2830 rep.space += statbuf.st_size;
2835 /* don't move the file across filesystems, just
2836 stick it in the `dead_sound_dir_name' directory
2837 on whichever filesystem it was already on.
2840 if ((*x).find ("/sounds/") != string::npos) {
2842 /* old school, go up 1 level */
2844 newpath = Glib::path_get_dirname (*x); // "sounds"
2845 newpath = Glib::path_get_dirname (newpath); // "session-name"
2849 /* new school, go up 4 levels */
2851 newpath = Glib::path_get_dirname (*x); // "audiofiles"
2852 newpath = Glib::path_get_dirname (newpath); // "session-name"
2853 newpath = Glib::path_get_dirname (newpath); // "interchange"
2854 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2858 newpath += dead_sound_dir_name;
2860 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2861 error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2866 newpath += Glib::path_get_basename ((*x));
2868 if (access (newpath.c_str(), F_OK) == 0) {
2870 /* the new path already exists, try versioning */
2872 char buf[PATH_MAX+1];
2876 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2879 while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) {
2880 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2884 if (version == 999) {
2885 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2889 newpath = newpath_v;
2894 /* it doesn't exist, or we can't read it or something */
2898 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2899 error << string_compose (_("cannot rename audio file source from %1 to %2 (%3)"),
2900 (*x), newpath, strerror (errno))
2905 /* see if there an easy to find peakfile for this file, and remove it.
2908 string peakpath = (*x).substr (0, (*x).find_last_of ('.'));
2909 peakpath += ".peak";
2911 if (access (peakpath.c_str(), W_OK) == 0) {
2912 if (::unlink (peakpath.c_str()) != 0) {
2913 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2914 peakpath, _path, strerror (errno))
2916 /* try to back out */
2917 rename (newpath.c_str(), _path.c_str());
2925 /* dump the history list */
2929 /* save state so we don't end up a session file
2930 referring to non-existent sources.
2936 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2941 Session::cleanup_trash_sources (Session::cleanup_report& rep)
2943 vector<space_and_path>::iterator i;
2944 string dead_sound_dir;
2945 struct dirent* dentry;
2946 struct stat statbuf;
2952 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2954 dead_sound_dir = (*i).path;
2955 dead_sound_dir += dead_sound_dir_name;
2957 if ((dead = opendir (dead_sound_dir.c_str())) == 0) {
2961 while ((dentry = readdir (dead)) != 0) {
2963 /* avoid '.' and '..' */
2965 if ((dentry->d_name[0] == '.' && dentry->d_name[1] == '\0') ||
2966 (dentry->d_name[2] == '\0' && dentry->d_name[0] == '.' && dentry->d_name[1] == '.')) {
2972 fullpath = dead_sound_dir;
2974 fullpath += dentry->d_name;
2976 if (stat (fullpath.c_str(), &statbuf)) {
2980 if (!S_ISREG (statbuf.st_mode)) {
2984 if (unlink (fullpath.c_str())) {
2985 error << string_compose (_("cannot remove dead sound file %1 (%2)"),
2986 fullpath, strerror (errno))
2990 rep.paths.push_back (dentry->d_name);
2991 rep.space += statbuf.st_size;
3002 Session::set_dirty ()
3004 bool was_dirty = dirty();
3006 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3009 DirtyChanged(); /* EMIT SIGNAL */
3015 Session::set_clean ()
3017 bool was_dirty = dirty();
3019 _state_of_the_state = Clean;
3022 DirtyChanged(); /* EMIT SIGNAL */
3027 Session::set_deletion_in_progress ()
3029 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3033 Session::add_controllable (Controllable* c)
3035 /* this adds a controllable to the list managed by the Session.
3036 this is a subset of those managed by the Controllable class
3037 itself, and represents the only ones whose state will be saved
3038 as part of the session.
3041 Glib::Mutex::Lock lm (controllables_lock);
3042 controllables.insert (c);
3046 Session::remove_controllable (Controllable* c)
3048 if (_state_of_the_state | Deletion) {
3052 Glib::Mutex::Lock lm (controllables_lock);
3054 Controllables::iterator x = controllables.find (c);
3056 if (x != controllables.end()) {
3057 controllables.erase (x);
3062 Session::controllable_by_id (const PBD::ID& id)
3064 Glib::Mutex::Lock lm (controllables_lock);
3066 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3067 if ((*i)->id() == id) {
3076 Session::add_instant_xml (XMLNode& node, const std::string& dir)
3078 Stateful::add_instant_xml (node, dir);
3079 Config->add_instant_xml (node, get_user_ardour_path());
3084 Session::save_history (string snapshot_name)
3090 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3092 if (snapshot_name.empty()) {
3093 snapshot_name = _current_snapshot_name;
3096 xml_path = _path + snapshot_name + ".history";
3098 bak_path = xml_path + ".bak";
3100 if ((access (xml_path.c_str(), F_OK) == 0) &&
3101 (rename (xml_path.c_str(), bak_path.c_str())))
3103 error << _("could not backup old history file, current history not saved.") << endmsg;
3107 if (!tree.write (xml_path))
3109 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3111 /* don't leave a corrupt file lying around if it is
3115 if (unlink (xml_path.c_str())) {
3116 error << string_compose (_("could not remove corrupt history file %1"), xml_path) << endmsg;
3118 if (rename (bak_path.c_str(), xml_path.c_str()))
3120 error << string_compose (_("could not restore history file from backup %1"), bak_path) << endmsg;
3131 Session::restore_history (string snapshot_name)
3136 if (snapshot_name.empty()) {
3137 snapshot_name = _current_snapshot_name;
3141 xmlpath = _path + snapshot_name + ".history";
3142 cerr << string_compose(_("Loading history from '%1'."), xmlpath) << endmsg;
3144 if (access (xmlpath.c_str(), F_OK)) {
3145 info << string_compose (_("%1: no history file \"%2\" for this session."), _name, xmlpath) << endmsg;
3149 if (!tree.read (xmlpath)) {
3150 error << string_compose (_("Could not understand session history file \"%1\""), xmlpath) << endmsg;
3154 /* replace history */
3157 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3160 UndoTransaction* ut = new UndoTransaction ();
3163 ut->set_name(t->property("name")->value());
3164 stringstream ss(t->property("tv_sec")->value());
3166 ss.str(t->property("tv_usec")->value());
3168 ut->set_timestamp(tv);
3170 for (XMLNodeConstIterator child_it = t->children().begin();
3171 child_it != t->children().end();
3174 XMLNode *n = *child_it;
3177 if (n->name() == "MementoCommand" ||
3178 n->name() == "MementoUndoCommand" ||
3179 n->name() == "MementoRedoCommand") {
3181 if ((c = memento_command_factory(n))) {
3185 } else if (n->name() == X_("GlobalRouteStateCommand")) {
3187 if ((c = global_state_command_factory (*n))) {
3188 ut->add_command (c);
3193 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3204 Session::config_changed (const char* parameter_name)
3206 #define PARAM_IS(x) (!strcmp (parameter_name, (x)))
3208 if (PARAM_IS ("seamless-loop")) {
3210 } else if (PARAM_IS ("rf-speed")) {
3212 } else if (PARAM_IS ("auto-loop")) {
3214 } else if (PARAM_IS ("auto-input")) {
3216 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3217 /* auto-input only makes a difference if we're rolling */
3219 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
3221 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
3222 if ((*i)->record_enabled ()) {
3223 (*i)->monitor_input (!Config->get_auto_input());
3228 } else if (PARAM_IS ("punch-in")) {
3232 if ((location = _locations.auto_punch_location()) != 0) {
3234 if (Config->get_punch_in ()) {
3235 replace_event (Event::PunchIn, location->start());
3237 remove_event (location->start(), Event::PunchIn);
3241 } else if (PARAM_IS ("punch-out")) {
3245 if ((location = _locations.auto_punch_location()) != 0) {
3247 if (Config->get_punch_out()) {
3248 replace_event (Event::PunchOut, location->end());
3250 clear_events (Event::PunchOut);
3254 } else if (PARAM_IS ("edit-mode")) {
3256 Glib::Mutex::Lock lm (playlist_lock);
3258 for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3259 (*i)->set_edit_mode (Config->get_edit_mode ());
3262 } else if (PARAM_IS ("use-video-sync")) {
3264 waiting_for_sync_offset = Config->get_use_video_sync();
3266 } else if (PARAM_IS ("mmc-control")) {
3268 //poke_midi_thread ();
3270 } else if (PARAM_IS ("mmc-device-id")) {
3273 mmc->set_device_id (Config->get_mmc_device_id());
3276 } else if (PARAM_IS ("midi-control")) {
3278 //poke_midi_thread ();
3280 } else if (PARAM_IS ("raid-path")) {
3282 setup_raid_path (Config->get_raid_path());
3284 } else if (PARAM_IS ("smpte-format")) {
3288 } else if (PARAM_IS ("video-pullup")) {
3292 } else if (PARAM_IS ("seamless-loop")) {
3294 if (play_loop && transport_rolling()) {
3295 // to reset diskstreams etc
3296 request_play_loop (true);
3299 } else if (PARAM_IS ("rf-speed")) {
3301 cumulative_rf_motion = 0;
3304 } else if (PARAM_IS ("click-sound")) {
3306 setup_click_sounds (1);
3308 } else if (PARAM_IS ("click-emphasis-sound")) {
3310 setup_click_sounds (-1);
3312 } else if (PARAM_IS ("clicking")) {
3314 if (Config->get_clicking()) {
3315 if (_click_io && click_data) { // don't require emphasis data
3322 } else if (PARAM_IS ("send-mtc")) {
3324 /* only set the internal flag if we have
3328 if (_mtc_port != 0) {
3329 session_send_mtc = Config->get_send_mtc();
3330 if (session_send_mtc) {
3331 /* mark us ready to send */
3332 next_quarter_frame_to_send = 0;
3335 session_send_mtc = false;
3338 } else if (PARAM_IS ("send-mmc")) {
3340 /* only set the internal flag if we have
3344 if (_mmc_port != 0) {
3345 session_send_mmc = Config->get_send_mmc();
3348 session_send_mmc = false;
3351 } else if (PARAM_IS ("midi-feedback")) {
3353 /* only set the internal flag if we have
3357 if (_mtc_port != 0) {
3358 session_midi_feedback = Config->get_midi_feedback();
3361 } else if (PARAM_IS ("jack-time-master")) {
3363 engine().reset_timebase ();
3365 } else if (PARAM_IS ("native-file-header-format")) {
3367 if (!first_file_header_format_reset) {
3368 reset_native_file_format ();
3371 first_file_header_format_reset = false;
3373 } else if (PARAM_IS ("native-file-data-format")) {
3375 if (!first_file_data_format_reset) {
3376 reset_native_file_format ();
3379 first_file_data_format_reset = false;
3381 } else if (PARAM_IS ("slave-source")) {
3382 set_slave_source (Config->get_slave_source());
3383 } else if (PARAM_IS ("remote-model")) {
3384 set_remote_control_ids ();