/*
- Copyright (C) 1999-2002 Paul Davis
+ Copyright (C) 1999-2013 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#endif
#include <glib.h>
+#include <glib/gstdio.h>
#include <glibmm.h>
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
#include <boost/algorithm/string.hpp>
#include "midi++/mmc.h"
#include "midi++/port.h"
-#include "midi++/manager.h"
#include "evoral/SMF.hpp"
#include "pbd/controllable_descriptor.h"
#include "pbd/enumwriter.h"
#include "pbd/error.h"
-#include "pbd/filesystem.h"
#include "pbd/file_utils.h"
#include "pbd/pathscanner.h"
#include "pbd/pthread_utils.h"
-#include "pbd/search_path.h"
#include "pbd/stacktrace.h"
#include "pbd/convert.h"
#include "pbd/clear_dir.h"
#include "ardour/control_protocol_manager.h"
#include "ardour/directory_names.h"
#include "ardour/filename_extensions.h"
+#include "ardour/graph.h"
#include "ardour/location.h"
#include "ardour/midi_model.h"
#include "ardour/midi_patch_manager.h"
#include "ardour/midi_region.h"
#include "ardour/midi_source.h"
#include "ardour/midi_track.h"
-#include "ardour/named_selection.h"
#include "ardour/pannable.h"
#include "ardour/playlist_factory.h"
#include "ardour/port.h"
#include "ardour/session_metadata.h"
#include "ardour/session_playlists.h"
#include "ardour/session_state_utils.h"
-#include "ardour/session_utils.h"
#include "ardour/silentfilesource.h"
#include "ardour/sndfilesource.h"
#include "ardour/source_factory.h"
using namespace ARDOUR;
using namespace PBD;
-/** @param snapshot_name Snapshot name, without the .ardour prefix */
void
-Session::first_stage_init (string fullpath, string snapshot_name)
+Session::pre_engine_init (string fullpath)
{
- if (fullpath.length() == 0) {
+ if (fullpath.empty()) {
destroy ();
throw failed_constructor();
}
+ /* discover canonical fullpath */
+
char buf[PATH_MAX+1];
if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
- error << string_compose(_("Could not use path %1 (%s)"), buf, strerror(errno)) << endmsg;
+ error << string_compose(_("Could not use path %1 (%2)"), buf, strerror(errno)) << endmsg;
destroy ();
throw failed_constructor();
}
_path = string(buf);
+
+ /* we require _path to end with a dir separator */
if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
_path += G_DIR_SEPARATOR;
}
- /* these two are just provisional settings. set_state()
- will likely override them.
- */
-
- _name = _current_snapshot_name = snapshot_name;
-
- set_history_depth (Config->get_history_depth());
-
- _current_frame_rate = _engine.frame_rate ();
- _nominal_frame_rate = _current_frame_rate;
- _base_frame_rate = _current_frame_rate;
+ /* is it new ? */
- _tempo_map = new TempoMap (_current_frame_rate);
- _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
+ _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+ /* finish initialization that can't be done in a normal C++ constructor
+ definition.
+ */
- _non_soloed_outs_muted = false;
- _listen_cnt = 0;
- _solo_isolated_cnt = 0;
+ timerclear (&last_mmc_step);
g_atomic_int_set (&processing_prohibited, 0);
- _transport_speed = 0;
- _default_transport_speed = 1.0;
- _last_transport_speed = 0;
- _target_transport_speed = 0;
- auto_play_legal = false;
- transport_sub_state = 0;
- _transport_frame = 0;
- _requested_return_frame = -1;
- _session_range_location = 0;
g_atomic_int_set (&_record_status, Disabled);
- loop_changing = false;
- play_loop = false;
- have_looped = false;
- _last_roll_location = 0;
- _last_roll_or_reversal_location = 0;
- _last_record_location = 0;
- pending_locate_frame = 0;
- pending_locate_roll = false;
- pending_locate_flush = false;
- state_was_pending = false;
- set_next_event ();
- outbound_mtc_timecode_frame = 0;
- next_quarter_frame_to_send = -1;
- current_block_size = 0;
- solo_update_disabled = false;
- _have_captured = false;
- _worst_output_latency = 0;
- _worst_input_latency = 0;
- _worst_track_latency = 0;
- _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading);
- _was_seamless = Config->get_seamless_loop ();
- _slave = 0;
- _send_qf_mtc = false;
- _pframes_since_last_mtc = 0;
g_atomic_int_set (&_playback_load, 100);
g_atomic_int_set (&_capture_load, 100);
- _play_range = false;
- _exporting = false;
- pending_abort = false;
- destructive_index = 0;
- first_file_data_format_reset = true;
- first_file_header_format_reset = true;
- post_export_sync = false;
- midi_control_ui = 0;
- _step_editors = 0;
- no_questions_about_missing_files = false;
- _speakers.reset (new Speakers);
- _clicks_cleared = 0;
- ignore_route_processor_changes = false;
- _pre_export_mmc_enabled = false;
-
- AudioDiskstream::allocate_working_buffers();
-
- /* default short fade = 15ms */
-
- SndFileSource::setup_standard_crossfades (*this, frame_rate());
-
- last_mmc_step.tv_sec = 0;
- last_mmc_step.tv_usec = 0;
- step_speed = 0.0;
-
- /* click sounds are unset by default, which causes us to internal
- waveforms for clicks.
- */
-
- click_length = 0;
- click_emphasis_length = 0;
- _clicking = false;
-
- process_function = &Session::process_with_events;
+ set_next_event ();
+ _all_route_group->set_active (true, this);
+ interpolation.add_channel_to (0, 0);
if (config.get_use_video_sync()) {
waiting_for_sync_offset = true;
waiting_for_sync_offset = false;
}
- last_timecode_when = 0;
- last_timecode_valid = false;
-
- sync_time_vars ();
-
last_rr_session_dir = session_dirs.begin();
- refresh_disk_space ();
+ set_history_depth (Config->get_history_depth());
+
/* default: assume simple stereo speaker configuration */
_speakers->setup_default_speakers (2);
- /* slave stuff */
-
- average_slave_delta = 1800; // !!! why 1800 ????
- have_first_delta_accumulator = false;
- delta_accumulator_cnt = 0;
- _slave_state = Stopped;
-
_solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
add_controllable (_solo_cut_control);
- _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
-
/* These are all static "per-class" signals */
SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
Delivery::disable_panners ();
IO::disable_connecting ();
+
+ AudioFileSource::set_peak_dir (_session_dir->peak_path());
}
int
-Session::second_stage_init ()
+Session::post_engine_init ()
{
- AudioFileSource::set_peak_dir (_session_dir->peak_path());
+ BootMessage (_("Set block size and sample rate"));
- if (!_is_new) {
- if (load_state (_current_snapshot_name)) {
- return -1;
- }
- }
+ set_block_size (_engine.samples_per_cycle());
+ set_frame_rate (_engine.sample_rate());
+ BootMessage (_("Using configuration"));
+
+ _midi_ports = new MidiPortManager;
+ setup_midi_machine_control ();
+
if (_butler->start_thread()) {
return -1;
}
-
+
if (start_midi_thread ()) {
return -1;
}
-
- setup_midi_machine_control ();
-
- // set_state() will call setup_raid_path(), but if it's a new session we need
- // to call setup_raid_path() here.
-
- if (state_tree) {
- if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
- return -1;
- }
- } else {
- setup_raid_path(_path);
- }
-
- /* we can't save till after ::when_engine_running() is called,
- because otherwise we save state with no connections made.
- therefore, we reset _state_of_the_state because ::set_state()
- will have cleared it.
-
- we also have to include Loading so that any events that get
- generated between here and the end of ::when_engine_running()
- will be processed directly rather than queued.
- */
-
- _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading);
-
- _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
- _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
+
setup_click_sounds (0);
setup_midi_control ();
- /* Pay attention ... */
-
_engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
_engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
- midi_clock = new MidiClockTicker ();
- midi_clock->set_session (this);
-
try {
- when_engine_running ();
- }
+ /* tempo map requires sample rate knowledge */
+
+ _tempo_map = new TempoMap (_current_frame_rate);
+ _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
+
+ /* MidiClock requires a tempo map */
+
+ midi_clock = new MidiClockTicker ();
+ midi_clock->set_session (this);
+
+ /* crossfades require sample rate knowledge */
+
+ SndFileSource::setup_standard_crossfades (*this, frame_rate());
+ _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
+
+ AudioDiskstream::allocate_working_buffers();
+ refresh_disk_space ();
+
+ /* we're finally ready to call set_state() ... all objects have
+ * been created, the engine is running.
+ */
+
+ if (state_tree) {
+ if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
+ return -1;
+ }
+ } else {
+ // set_state() will call setup_raid_path(), but if it's a new session we need
+ // to call setup_raid_path() here.
+ setup_raid_path (_path);
+ }
+
+ /* ENGINE */
- /* handle this one in a different way than all others, so that its clear what happened */
+ boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
+ boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
+
+ Config->map_parameters (ff);
+ config.map_parameters (ft);
- catch (AudioEngine::PortRegistrationFailure& err) {
+ /* Reset all panners */
+
+ Delivery::reset_panners ();
+
+ /* this will cause the CPM to instantiate any protocols that are in use
+ * (or mandatory), which will pass it this Session, and then call
+ * set_state() on each instantiated protocol to match stored state.
+ */
+
+ ControlProtocolManager::instance().set_session (this);
+
+ /* This must be done after the ControlProtocolManager set_session above,
+ as it will set states for ports which the ControlProtocolManager creates.
+ */
+
+ // XXX set state of MIDI::Port's
+ // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
+
+ /* And this must be done after the MIDI::Manager::set_port_states as
+ * it will try to make connections whose details are loaded by set_port_states.
+ */
+
+ hookup_io ();
+
+ /* Let control protocols know that we are now all connected, so they
+ * could start talking to surfaces if they want to.
+ */
+
+ ControlProtocolManager::instance().midi_connectivity_established ();
+
+ if (_is_new && !no_auto_connect()) {
+ Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
+ auto_connect_master_bus ();
+ }
+
+ _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
+
+ /* update latencies */
+
+ initialize_latencies ();
+
+ _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
+ _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
+
+ } catch (AudioEngine::PortRegistrationFailure& err) {
+ /* handle this one in a different way than all others, so that its clear what happened */
error << err.what() << endmsg;
return -1;
- }
-
- catch (...) {
+ } catch (...) {
return -1;
}
BootMessage (_("Reset Remote Controls"));
- send_full_time_code (0);
+ // send_full_time_code (0);
_engine.transport_locate (0);
- MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
- MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (Timecode::Time ()));
+ _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
+ _mmc->send (MIDI::MachineControlCommand (Timecode::Time ()));
MIDI::Name::MidiPatchManager::instance().set_session (this);
+ ltc_tx_initialize();
/* initial program change will be delivered later; see ::config_changed() */
_state_of_the_state = Clean;
DirtyChanged (); /* EMIT SIGNAL */
- if (state_was_pending) {
- save_state (_current_snapshot_name);
+ if (_is_new) {
+ save_state ("");
+ } else if (state_was_pending) {
+ save_state ("");
remove_pending_capture_state ();
state_was_pending = false;
}
- BootMessage (_("Session loading complete"));
-
return 0;
}
return -1;
}
- _writable = sys::exists_and_writable (_path);
+ _writable = exists_and_writable (_path);
if (!session_template.empty()) {
std::string in_path = session_template_dir_to_file (session_template);
ifstream in(in_path.c_str());
if (in) {
- string out_path = _path;
- out_path += _name;
- out_path += statefile_suffix;
+ /* no need to call legalize_for_path() since the string
+ * in session_template is already a legal path name
+ */
+ string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
ofstream out(out_path.c_str());
// boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
#endif
{
- Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
}
add_monitor_section ();
}
- save_state ("");
-
return 0;
}
void
Session::remove_pending_capture_state ()
{
- sys::path pending_state_file_path(_session_dir->root_path());
+ std::string pending_state_file_path(_session_dir->root_path());
- pending_state_file_path /= legalize_for_path (_current_snapshot_name) + pending_suffix;
+ pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
- try
- {
- sys::remove (pending_state_file_path);
- }
- catch(sys::filesystem_error& ex)
- {
- error << string_compose(_("Could remove pending capture state at path \"%1\" (%2)"),
- pending_state_file_path.to_string(), ex.what()) << endmsg;
+ if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
+
+ if (g_remove (pending_state_file_path.c_str()) != 0) {
+ error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
+ pending_state_file_path, g_strerror (errno)) << endmsg;
}
}
const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
- const sys::path old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
- const sys::path new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
+ const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
+ const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
- try
- {
- sys::rename (old_xml_path, new_xml_path);
- }
- catch (const sys::filesystem_error& err)
- {
+ if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
- old_name, new_name, err.what()) << endmsg;
+ old_name, new_name, g_strerror(errno)) << endmsg;
}
}
}
// and delete it
- sys::remove (xml_path);
-}
-
-#ifdef HAVE_JACK_SESSION
-void
-Session::jack_session_event (jack_session_event_t * event)
-{
- char timebuf[128];
- time_t n;
- struct tm local_time;
-
- time (&n);
- localtime_r (&n, &local_time);
- strftime (timebuf, sizeof(timebuf), "JS_%FT%T", &local_time);
-
- if (event->type == JackSessionSaveTemplate)
- {
- if (save_template( timebuf )) {
- event->flags = JackSessionSaveError;
- } else {
- string cmd ("ardour3 -P -U ");
- cmd += event->client_uuid;
- cmd += " -T ";
- cmd += timebuf;
-
- event->command_line = strdup (cmd.c_str());
- }
- }
- else
- {
- if (save_state (timebuf)) {
- event->flags = JackSessionSaveError;
- } else {
- sys::path xml_path (_session_dir->root_path());
- xml_path /= legalize_for_path (timebuf) + statefile_suffix;
-
- string cmd ("ardour3 -P -U ");
- cmd += event->client_uuid;
- cmd += " \"";
- cmd += xml_path.to_string();
- cmd += '\"';
-
- event->command_line = strdup (cmd.c_str());
- }
- }
-
- jack_session_reply (_engine.jack(), event);
-
- if (event->type == JackSessionSaveAndQuit) {
- Quit (); /* EMIT SIGNAL */
+ if (g_remove (xml_path.c_str()) != 0) {
+ error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
+ xml_path, g_strerror (errno)) << endmsg;
}
-
- jack_session_event_free( event );
}
-#endif
/** @param snapshot_name Name to save under, without .ardour / .pending prefix */
int
}
}
+ SaveSession (); /* EMIT SIGNAL */
+
tree.set_root (&get_state());
if (snapshot_name.empty()) {
/* make a backup copy of the old file */
- if (sys::exists(xml_path) && !create_backup_file (xml_path)) {
+ if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
// create_backup_file will log the error
return -1;
}
xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
}
- sys::path tmp_path(_session_dir->root_path());
-
- tmp_path /= legalize_for_path (snapshot_name) + temp_suffix;
+ std::string tmp_path(_session_dir->root_path());
+ tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
- // cerr << "actually writing state to " << xml_path.to_string() << endl;
+ // cerr << "actually writing state to " << xml_path << endl;
- if (!tree.write (tmp_path.to_string())) {
- error << string_compose (_("state could not be saved to %1"), tmp_path.to_string()) << endmsg;
- sys::remove (tmp_path);
+ if (!tree.write (tmp_path)) {
+ error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
+ if (g_remove (tmp_path.c_str()) != 0) {
+ error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
+ tmp_path, g_strerror (errno)) << endmsg;
+ }
return -1;
} else {
- if (::rename (tmp_path.to_string().c_str(), xml_path.c_str()) != 0) {
+ if (::rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
error << string_compose (_("could not rename temporary session file %1 to %2"),
- tmp_path.to_string(), xml_path) << endmsg;
- sys::remove (tmp_path);
+ tmp_path, xml_path) << endmsg;
+ if (g_remove (tmp_path.c_str()) != 0) {
+ error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
+ tmp_path, g_strerror (errno)) << endmsg;
+ }
return -1;
}
}
/* check for leftover pending state from a crashed capture attempt */
- sys::path xmlpath(_session_dir->root_path());
- xmlpath /= legalize_for_path (snapshot_name) + pending_suffix;
+ std::string xmlpath(_session_dir->root_path());
+ xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
- if (sys::exists (xmlpath)) {
+ if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
/* there is pending state from a crashed capture attempt */
}
if (!state_was_pending) {
- xmlpath = _session_dir->root_path();
- xmlpath /= snapshot_name;
+ xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
}
- if (!sys::exists (xmlpath)) {
- xmlpath = _session_dir->root_path();
- xmlpath /= legalize_for_path (snapshot_name) + statefile_suffix;
- if (!sys::exists (xmlpath)) {
- error << string_compose(_("%1: session state information file \"%2\" doesn't exist!"), _name, xmlpath.to_string()) << endmsg;
+ if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
+ xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
+ if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
+ error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
return 1;
}
}
set_dirty();
- _writable = sys::exists_and_writable (xmlpath.to_string());
+ _writable = exists_and_writable (xmlpath);
- if (!state_tree->read (xmlpath.to_string())) {
- error << string_compose(_("Could not understand ardour file %1"), xmlpath.to_string()) << endmsg;
+ if (!state_tree->read (xmlpath)) {
+ error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
delete state_tree;
state_tree = 0;
return -1;
XMLNode& root (*state_tree->root());
if (root.name() != X_("Session")) {
- error << string_compose (_("Session file %1 is not a session"), xmlpath.to_string()) << endmsg;
+ error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
delete state_tree;
state_tree = 0;
return -1;
if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
- sys::path backup_path(_session_dir->root_path());
-
- backup_path /= string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
+ std::string backup_path(_session_dir->root_path());
+ std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
+ backup_path = Glib::build_filename (backup_path, backup_filename);
// only create a backup for a given statefile version once
- if (!sys::exists (backup_path)) {
+ if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
- info << string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
- xmlpath.to_string(), backup_path.to_string(), PROGRAM_NAME)
- << endmsg;
+ VersionMismatch (xmlpath, backup_path);
- if (!copy_file (xmlpath.to_string(), backup_path.to_string())) {;
+ if (!copy_file (xmlpath, backup_path)) {;
return -1;
}
}
/* various options */
+ list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
+ if (!midi_port_nodes.empty()) {
+ XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
+ for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
+ midi_port_stuff->add_child_nocopy (**n);
+ }
+ node->add_child_nocopy (*midi_port_stuff);
+ }
+
node->add_child_nocopy (config.get_variables ());
node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
child = node->add_child ("Sources");
if (full_state) {
- Glib::Mutex::Lock sl (source_lock);
+ Glib::Threads::Mutex::Lock sl (source_lock);
for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
child = node->add_child ("Regions");
if (full_state) {
- Glib::Mutex::Lock rl (region_lock);
+ Glib::Threads::Mutex::Lock rl (region_lock);
const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
boost::shared_ptr<Region> r = i->second;
/* only store regions not attached to playlists */
if (r->playlist() == 0) {
- child->add_child_nocopy (r->state ());
+ if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
+ child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
+ } else {
+ child->add_child_nocopy (r->get_state ());
+ }
}
}
}
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
- if (!(*i)->is_hidden()) {
+ if (!(*i)->is_auditioner()) {
if (full_state) {
child->add_child_nocopy ((*i)->get_state());
} else {
gain_child->add_child_nocopy (_click_gain->state (full_state));
}
- if (full_state) {
- XMLNode* ns_child = node->add_child ("NamedSelections");
- for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) {
- if (full_state) {
- ns_child->add_child_nocopy ((*i)->get_state());
- }
- }
+ if (_ltc_input) {
+ XMLNode* ltc_input_child = node->add_child ("LTC-In");
+ ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
+ }
+
+ if (_ltc_input) {
+ XMLNode* ltc_output_child = node->add_child ("LTC-Out");
+ ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
}
node->add_child_nocopy (_speakers->get_state());
Evoral::init_event_id_counter (atoi (prop->value()));
}
+
+ if ((child = find_named_node (node, "MIDIPorts")) != 0) {
+ _midi_ports->set_midi_port_states (child->children());
+ }
+
IO::disable_connecting ();
Stateful::save_extra_xml (node);
}
}
- if ((child = find_named_node (node, "NamedSelections")) != 0) {
- if (load_named_selections (*child)) {
- goto out;
- }
- }
-
if (version >= 3000) {
if ((child = find_named_node (node, "Bundles")) == 0) {
warning << _("Session: XML state has no bundles section") << endmsg;
if ((child = find_named_node (node, "Click")) == 0) {
warning << _("Session: XML state has no click section") << endmsg;
} else if (_click_io) {
- const XMLNodeList& children (child->children());
- XMLNodeList::const_iterator i = children.begin();
- _click_io->set_state (**i, version);
- ++i;
- if (i != children.end()) {
- _click_gain->set_state (**i, version);
- }
+ setup_click_state (&node);
}
- if ((child = find_named_node (node, "ControlProtocols")) != 0) {
- ControlProtocolManager::instance().set_protocol_states (*child);
+ if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
+ ControlProtocolManager::instance().set_state (*child, version);
}
update_have_rec_enabled_track ();
XMLProperty* prop = (*niter)->property (X_("id"));
if (!prop) {
- error << _("Nested source has no ID info in session state file! (ignored)") << endmsg;
+ error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
continue;
}
{
XMLNode* node = new XMLNode (X_("Sources"));
- Glib::Mutex::Lock lm (source_lock);
+ Glib::Threads::Mutex::Lock lm (source_lock);
for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
node->add_child_nocopy (i->second->get_state());
char buf[PATH_MAX+1];
uint32_t n;
SessionDirectory sdir(get_best_session_directory_for_new_source());
- sys::path source_dir = ((type == DataType::AUDIO)
+ std::string source_dir = ((type == DataType::AUDIO)
? sdir.sound_path() : sdir.midi_path());
string ext = native_header_format_extension (config.get_native_file_header_format(), type);
n, ext.c_str());
}
- sys::path source_path = source_dir / buf;
+ std::string source_path = Glib::build_filename (source_dir, buf);
- if (!sys::exists (source_path)) {
- return source_path.to_string();
+ if (!Glib::file_test (source_path, Glib::FILE_TEST_EXISTS)) {
+ return source_path;
}
}
return -1;
}
- sys::path user_template_dir(user_template_directory());
+ std::string user_template_dir(user_template_directory());
- try
- {
- sys::create_directories (user_template_dir);
- }
- catch(sys::filesystem_error& ex)
- {
+ if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
- user_template_dir.to_string(), ex.what()) << endmsg;
+ user_template_dir, g_strerror (errno)) << endmsg;
return -1;
}
tree.set_root (&get_template());
- sys::path template_dir_path(user_template_dir);
+ std::string template_dir_path(user_template_dir);
/* directory to put the template in */
- template_dir_path /= template_name;
- if (sys::exists (template_dir_path))
- {
+ template_dir_path = Glib::build_filename (template_dir_path, template_name);
+
+ if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
warning << string_compose(_("Template \"%1\" already exists - new version not created"),
- template_dir_path.to_string()) << endmsg;
+ template_dir_path) << endmsg;
return -1;
}
- sys::create_directories (template_dir_path);
+ if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
+ error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
+ template_dir_path, g_strerror (errno)) << endmsg;
+ return -1;
+ }
/* file to write */
- sys::path template_file_path = template_dir_path;
- template_file_path /= template_name + template_suffix;
+ std::string template_file_path(template_dir_path);
+ template_file_path = Glib::build_filename (template_file_path, template_name + template_suffix);
- if (!tree.write (template_file_path.to_string())) {
+ if (!tree.write (template_file_path)) {
error << _("template not saved") << endmsg;
return -1;
}
/* copy plugin state directory */
- sys::path template_plugin_state_path = template_dir_path;
- template_plugin_state_path /= X_("plugins");
- sys::create_directories (template_plugin_state_path);
- copy_files (plugins_dir(), template_plugin_state_path.to_string());
+ std::string template_plugin_state_path(template_dir_path);
+ template_plugin_state_path = Glib::build_filename (template_plugin_state_path, X_("plugins"));
+
+ if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
+ error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
+ template_plugin_state_path, g_strerror (errno)) << endmsg;
+ return -1;
+ }
+
+ copy_files (plugins_dir(), template_plugin_state_path);
return 0;
}
void
Session::refresh_disk_space ()
{
-#if HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H
+#if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
- Glib::Mutex::Lock lm (space_lock);
+ Glib::Threads::Mutex::Lock lm (space_lock);
/* get freespace on every FS that is part of the session path */
}
if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
- if (create_session_directory ((*i).path)) {
+ SessionDirectory sdir(i->path);
+ if (sdir.create ()) {
result = (*i).path;
last_rr_session_dir = i;
return result;
sort (sorted.begin(), sorted.end(), cmp);
for (i = sorted.begin(); i != sorted.end(); ++i) {
- if (create_session_directory ((*i).path)) {
+ SessionDirectory sdir(i->path);
+ if (sdir.create ()) {
result = (*i).path;
last_rr_session_dir = i;
return result;
return result;
}
-int
-Session::load_named_selections (const XMLNode& node)
-{
- XMLNodeList nlist;
- XMLNodeConstIterator niter;
- NamedSelection *ns;
-
- nlist = node.children();
-
- set_dirty();
-
- for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
- if ((ns = XMLNamedSelectionFactory (**niter)) == 0) {
- error << _("Session: cannot create Named Selection from XML description.") << endmsg;
- }
- }
-
- return 0;
-}
-
-NamedSelection *
-Session::XMLNamedSelectionFactory (const XMLNode& node)
-{
- try {
- return new NamedSelection (*this, node);
- }
-
- catch (failed_constructor& err) {
- return 0;
- }
-}
-
string
Session::automation_dir () const
{
} else if ((*niter)->name() == "OutputBundle") {
add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
} else {
- error << string_compose(_("Unknown node \"%1\" found in Bundles list from state file"), (*niter)->name()) << endmsg;
+ error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
return -1;
}
}
ripped = ripped.substr (0, ripped.length() - 1);
}
- state_files = scanner (ripped, accept_all_state_files, (void *) 0, false, true);
+ state_files = scanner (ripped, accept_all_state_files, (void *) 0, true, true);
if (state_files == 0) {
/* impossible! */
as part of the session.
*/
- Glib::Mutex::Lock lm (controllables_lock);
+ Glib::Threads::Mutex::Lock lm (controllables_lock);
controllables.insert (c);
}
return;
}
- Glib::Mutex::Lock lm (controllables_lock);
+ Glib::Threads::Mutex::Lock lm (controllables_lock);
Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
boost::shared_ptr<Controllable>
Session::controllable_by_id (const PBD::ID& id)
{
- Glib::Mutex::Lock lm (controllables_lock);
+ Glib::Threads::Mutex::Lock lm (controllables_lock);
for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
if ((*i)->id() == id) {
if (p) {
boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
boost::shared_ptr<Amp> a = s->amp();
-
+
if (a) {
c = s->amp()->gain_control();
}
const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
const string backup_filename = history_filename + backup_suffix;
- const sys::path xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
- const sys::path backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
+ const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
+ const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
- if (sys::exists (xml_path)) {
- try
- {
- sys::rename (xml_path, backup_path);
- }
- catch (const sys::filesystem_error& err)
- {
+ if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
+ if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
error << _("could not backup old history file, current history not saved") << endmsg;
return -1;
}
tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
- if (!tree.write (xml_path.to_string()))
+ if (!tree.write (xml_path))
{
- error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg;
+ error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
- try
- {
- sys::remove (xml_path);
- sys::rename (backup_path, xml_path);
+ if (g_remove (xml_path.c_str()) != 0) {
+ error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
+ xml_path, g_strerror (errno)) << endmsg;
}
- catch (const sys::filesystem_error& err)
- {
+ if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
error << string_compose (_("could not restore history file from backup %1 (%2)"),
- backup_path.to_string(), err.what()) << endmsg;
+ backup_path, g_strerror (errno)) << endmsg;
}
return -1;
snapshot_name = _current_snapshot_name;
}
- const string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
- const sys::path xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
+ const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
+ const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
- info << "Loading history from " << xml_path.to_string() << endmsg;
+ info << "Loading history from " << xml_path << endmsg;
- if (!sys::exists (xml_path)) {
+ if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
info << string_compose (_("%1: no history file \"%2\" for this session."),
- _name, xml_path.to_string()) << endmsg;
+ _name, xml_path) << endmsg;
return 1;
}
- if (!tree.read (xml_path.to_string())) {
+ if (!tree.read (xml_path)) {
error << string_compose (_("Could not understand session history file \"%1\""),
- xml_path.to_string()) << endmsg;
+ xml_path) << endmsg;
return -1;
}
} else if (p == "edit-mode") {
- Glib::Mutex::Lock lm (playlists->lock);
+ Glib::Threads::Mutex::Lock lm (playlists->lock);
for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
(*i)->set_edit_mode (Config->get_edit_mode ());
} else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
- MIDI::Manager::instance()->mmc()->set_receive_device_id (Config->get_mmc_receive_device_id());
+ _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
} else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
- MIDI::Manager::instance()->mmc()->set_send_device_id (Config->get_mmc_send_device_id());
+ _mmc->set_send_device_id (Config->get_mmc_send_device_id());
} else if (p == "midi-control") {
} else if (p == "send-mmc") {
- MIDI::Manager::instance()->mmc()->enable_send (Config->get_send_mmc ());
+ _mmc->enable_send (Config->get_send_mmc ());
} else if (p == "midi-feedback") {
if (!config.get_external_sync()) {
drop_sync_source ();
} else {
- switch_to_sync_source (config.get_sync_source());
+ switch_to_sync_source (Config->get_sync_source());
}
- } else if (p == "remote-model") {
- set_remote_control_ids ();
} else if (p == "denormal-model") {
setup_fpu ();
} else if (p == "history-depth") {
set_history_depth (Config->get_history_depth());
- } else if (p == "sync-all-route-ordering") {
- sync_order_keys ("session");
+ } else if (p == "remote-model") {
+ /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
+ TO SET REMOTE ID'S
+ */
} else if (p == "initial-program-change") {
- if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) {
+ if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
MIDI::byte buf[2];
buf[0] = MIDI::program; // channel zero by default
buf[1] = (Config->get_initial_program_change() & 0x7f);
- MIDI::Manager::instance()->mmc()->output_port()->midimsg (buf, sizeof (buf), 0);
+ _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
}
} else if (p == "solo-mute-override") {
// catch_up_on_solo_mute_override ();
AudioSource::allocate_working_buffers (frame_rate());
} else if (p == "automation-thinning-factor") {
Evoral::ControlList::set_thinning_factor (Config->get_automation_thinning_factor());
+ } else if (p == "ltc-source-port") {
+ reconnect_ltc_input ();
+ } else if (p == "ltc-sink-port") {
+ reconnect_ltc_output ();
+ } else if (p == "timecode-generator-offset") {
+ ltc_tx_parse_offset();
}
set_dirty ();
void
Session::setup_midi_machine_control ()
{
- MIDI::MachineControl* mmc = MIDI::Manager::instance()->mmc ();
-
- mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
- mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
- mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
- mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
- mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
- mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
- mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
- mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
- mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
- mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
- mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
- mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
- mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
+ _mmc = new MIDI::MachineControl;
+ _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
+
+ _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
+ _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
+ _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
+ _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
+ _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
+ _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
+ _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
+ _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
+ _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
+ _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
+ _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
+ _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
+ _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
/* also handle MIDI SPP because its so common */
- mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
- mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
- mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
+ _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
+ _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
+ _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
}
boost::shared_ptr<Controllable>
#undef RENAME
}
+
+int
+Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
+{
+ if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
+ return -1;
+ }
+
+ if (!tree.read (xmlpath)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
+{
+ XMLTree tree;
+ bool found_sr = false;
+ bool found_data_format = false;
+
+ if (get_session_info_from_path (tree, xmlpath)) {
+ return -1;
+ }
+
+ /* sample rate */
+
+ const XMLProperty* prop;
+ if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
+ sample_rate = atoi (prop->value());
+ found_sr = true;
+ }
+
+ const XMLNodeList& children (tree.root()->children());
+ for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
+ const XMLNode* child = *c;
+ if (child->name() == "Config") {
+ const XMLNodeList& options (child->children());
+ for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
+ const XMLNode* option = *oc;
+ const XMLProperty* name = option->property("name");
+
+ if (!name) {
+ continue;
+ }
+
+ if (name->value() == "native-file-data-format") {
+ const XMLProperty* value = option->property ("value");
+ if (value) {
+ SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
+ data_format = fmt;
+ found_data_format = true;
+ break;
+ }
+ }
+ }
+ }
+ if (found_data_format) {
+ break;
+ }
+ }
+
+ return !(found_sr && found_data_format); // zero if they are both found
+}