X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=19d562f84421beb4974ef574828641db9c98cda4;hb=e92c1669c1cdf857b8a3900abb9f891e6ca9fdad;hp=d20f0fcf90d50974784b30a7d54edf8da9ff6e24;hpb=d07c90b003d7680eb4e0fd91e526ce8b5596de92;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index d20f0fcf90..19d562f844 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #include #include @@ -78,6 +78,7 @@ #include #include #include +#include #ifdef HAVE_LIBLO #include @@ -96,6 +97,14 @@ static const int CPU_CACHE_ALIGN = 64; static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */ #endif +bool Session::_disable_all_loaded_plugins = false; + +Session::compute_peak_t Session::compute_peak = 0; +Session::find_peaks_t Session::find_peaks = 0; +Session::apply_gain_to_buffer_t Session::apply_gain_to_buffer = 0; +Session::mix_buffers_with_gain_t Session::mix_buffers_with_gain = 0; +Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0; + sigc::signal Session::AskAboutPendingState; sigc::signal Session::SendFeedback; @@ -104,9 +113,9 @@ sigc::signal Session::StartTimeChanged; sigc::signal Session::EndTimeChanged; Session::Session (AudioEngine &eng, - string fullpath, - string snapshot_name, - string* mix_template) + const string& fullpath, + const string& snapshot_name, + string mix_template) : _engine (eng), _scratch_buffers(new BufferSet()), @@ -122,66 +131,32 @@ Session::Session (AudioEngine &eng, diskstreams (new DiskstreamList), routes (new RouteList), auditioner ((Auditioner*) 0), + _bundle_xml_node (0), _click_io ((IO*) 0), - main_outs (0), - _automation_interval (0) + main_outs (0) { + bool new_session; + if (!eng.connected()) { throw failed_constructor(); } + + cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl; n_physical_outputs = _engine.n_physical_outputs(); n_physical_inputs = _engine.n_physical_inputs(); first_stage_init (fullpath, snapshot_name); - initialize_start_and_end_locations(0, compute_initial_length ()); - - if(mix_template) { - // try and create a new session directory - try - { - if(!_session_dir->create()) { - // an existing session. - // throw a_more_meaningful_exception() - destroy (); - throw failed_constructor (); - } - } - catch(sys::filesystem_error& ex) - { - destroy (); - throw failed_constructor (); - } - - if(!create_session_file_from_template (*mix_template)) { + new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)); + if (new_session) { + if (create (new_session, mix_template, compute_initial_length())) { destroy (); throw failed_constructor (); } - - cerr << "Creating session " << fullpath - <<" using template" << *mix_template - << endl; - } else { - // must be an existing session - try - { - // ensure the necessary session subdirectories exist - // in case the directory structure has changed etc. - _session_dir->create(); - } - catch(sys::filesystem_error& ex) - { - destroy (); - throw failed_constructor (); - } - - cerr << "Loading session " << fullpath - << " using snapshot " << snapshot_name << " (1)" - << endl; } - - if (second_stage_init (false)) { + + if (second_stage_init (new_session)) { destroy (); throw failed_constructor (); } @@ -223,10 +198,12 @@ Session::Session (AudioEngine &eng, _send_smpte_update (false), diskstreams (new DiskstreamList), routes (new RouteList), - main_outs (0), - _automation_interval (0) + _bundle_xml_node (0), + main_outs (0) { + bool new_session; + if (!eng.connected()) { throw failed_constructor(); } @@ -246,11 +223,13 @@ Session::Session (AudioEngine &eng, first_stage_init (fullpath, snapshot_name); - initialize_start_and_end_locations(0, initial_length); - - if (!_session_dir->create () || !create_session_file ()) { - destroy (); - throw failed_constructor (); + new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)); + + if (new_session) { + if (create (new_session, string(), initial_length)) { + destroy (); + throw failed_constructor (); + } } { @@ -277,7 +256,7 @@ Session::Session (AudioEngine &eng, } if (!rl.empty()) { - add_routes (rl); + add_routes (rl, false); } } @@ -285,22 +264,16 @@ Session::Session (AudioEngine &eng, Config->set_input_auto_connect (input_ac); Config->set_output_auto_connect (output_ac); - if (second_stage_init (true)) { + if (second_stage_init (new_session)) { destroy (); throw failed_constructor (); } - store_recent_sessions(_name, _path); + store_recent_sessions (_name, _path); - bool was_dirty = dirty (); - _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed)); - - if (was_dirty) { - DirtyChanged (); /* EMIT SIGNAL */ - } } Session::~Session () @@ -318,6 +291,7 @@ Session::destroy () remove_pending_capture_state (); _state_of_the_state = StateOfTheState (CannotSave|Deletion); + _engine.remove_session (); GoingAway (); /* EMIT SIGNAL */ @@ -486,20 +460,6 @@ Session::destroy () i = tmp; } -#ifdef TRACK_DESTRUCTION - cerr << "delete bundles\n"; -#endif /* TRACK_DESTRUCTION */ - for (BundleList::iterator i = _bundles.begin(); i != _bundles.end(); ) { - BundleList::iterator tmp; - - tmp = i; - ++tmp; - - delete *i; - - i = tmp; - } - if (butler_mixdown_buffer) { delete [] butler_mixdown_buffer; } @@ -614,22 +574,22 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1); - Bundle* c = new OutputBundle (buf, true); - c->set_nchannels (1); - c->add_port_to_channel (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); + shared_ptr c (new AutoBundle (buf, true)); + c->set_channels (1); + c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); - add_bundle (c); + add_bundle (c); } for (uint32_t np = 0; np < n_physical_inputs; ++np) { char buf[32]; snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1); - Bundle* c = new InputBundle (buf, true); - c->set_nchannels (1); - c->add_port_to_channel (0, _engine.get_nth_physical_input (DataType::AUDIO, np)); + shared_ptr c (new AutoBundle (buf, false)); + c->set_channels (1); + c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np)); - add_bundle (c); + add_bundle (c); } /* TWO: STEREO */ @@ -638,24 +598,24 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2); - Bundle* c = new OutputBundle (buf, true); - c->set_nchannels (2); - c->add_port_to_channel (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); - c->add_port_to_channel (1, _engine.get_nth_physical_output (DataType::AUDIO, np+1)); + shared_ptr c (new AutoBundle (buf, true)); + c->set_channels (2); + c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); + c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1)); - add_bundle (c); + add_bundle (c); } for (uint32_t np = 0; np < n_physical_inputs; np +=2) { char buf[32]; snprintf (buf, sizeof (buf), _("in %" PRIu32 "+%" PRIu32), np+1, np+2); - Bundle* c = new InputBundle (buf, true); - c->set_nchannels (2); - c->add_port_to_channel (0, _engine.get_nth_physical_input (DataType::AUDIO, np)); - c->add_port_to_channel (1, _engine.get_nth_physical_input (DataType::AUDIO, np+1)); + shared_ptr c (new AutoBundle (buf, false)); + c->set_channels (2); + c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np)); + c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1)); - add_bundle (c); + add_bundle (c); } /* THREE MASTER */ @@ -700,13 +660,13 @@ Session::when_engine_running () } - Bundle* c = new OutputBundle (_("Master Out"), true); + shared_ptr c (new AutoBundle (_("Master Out"), true)); - c->set_nchannels (_master_out->n_inputs().n_total()); - for (uint32_t n = 0; n < _master_out->n_inputs ().n_total(); ++n) { - c->add_port_to_channel ((int) n, _master_out->input(n)->name()); - } - add_bundle (c); + c->set_channels (_master_out->n_inputs().n_total()); + for (uint32_t n = 0; n < _master_out->n_inputs ().n_total(); ++n) { + c->set_port (n, _master_out->input(n)->name()); + } + add_bundle (c); } hookup_io (); @@ -740,6 +700,7 @@ Session::when_engine_running () _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty)); + /* hook us up to the engine */ _engine.set_session (this); @@ -749,10 +710,7 @@ Session::when_engine_running () osc->set_session (*this); #endif - - _state_of_the_state = Clean; - - DirtyChanged (); /* EMIT SIGNAL */ + } void @@ -764,6 +722,7 @@ Session::hookup_io () _state_of_the_state = StateOfTheState (_state_of_the_state | InitialConnecting); + if (auditioner == 0) { /* we delay creating the auditioner till now because @@ -817,7 +776,13 @@ Session::hookup_io () for (RouteList::iterator x = r->begin(); x != r->end(); ++x) { (*x)->set_control_outs (cports); } - } + } + + /* load bundles, which we may have postponed earlier on */ + if (_bundle_xml_node) { + load_bundles (*_bundle_xml_node); + delete _bundle_xml_node; + } /* Tell all IO objects to connect themselves together */ @@ -833,6 +798,7 @@ Session::hookup_io () _state_of_the_state = StateOfTheState (_state_of_the_state & ~InitialConnecting); + /* now handle the whole enchilada as if it was one graph reorder event. */ @@ -1270,8 +1236,10 @@ Session::set_frame_rate (nframes_t frames_per_second) sync_time_vars(); - _automation_interval = ((nframes_t) ceil ((double) frames_per_second * 0.25)); + Automatable::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval()))); + clear_clicks (); + // XXX we need some equivalent to this, somehow // SndFileSource::setup_standard_crossfades (frames_per_second); @@ -1495,11 +1463,13 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) char track_name[32]; uint32_t track_id = 0; uint32_t n = 0; - uint32_t channels_used = 0; string port; RouteList new_routes; list > ret; + //uint32_t control_id; + // FIXME: need physical I/O and autoconnect stuff for MIDI + /* count existing midi tracks */ { @@ -1509,18 +1479,29 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) if (dynamic_cast((*i).get()) != 0) { if (!(*i)->is_hidden()) { n++; - channels_used += (*i)->n_inputs().n_midi(); + //channels_used += (*i)->n_inputs().n_midi(); } } } } + /* + vector physinputs; + vector physoutputs; + uint32_t nphysical_in; + uint32_t nphysical_out; + + _engine.get_physical_outputs (physoutputs); + _engine.get_physical_inputs (physinputs); + control_id = ntracks() + nbusses() + 1; + */ + while (how_many) { /* check for duplicate route names, since we might have pre-existing - routes with this name (e.g. create Midi1, Midi2, delete Midi1, + routes with this name (e.g. create Audio1, Audio2, delete Audio1, save, close,restart,add new route - first named route is now - Midi2) + Audio2) */ @@ -1535,17 +1516,71 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) } while (track_id < (UINT_MAX-1)); + /* + if (Config->get_input_auto_connect() & AutoConnectPhysical) { + nphysical_in = min (n_physical_inputs, (uint32_t) physinputs.size()); + } else { + nphysical_in = 0; + } + + if (Config->get_output_auto_connect() & AutoConnectPhysical) { + nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size()); + } else { + nphysical_out = 0; + } + */ + + shared_ptr track; + try { - shared_ptr track (new MidiTrack (*this, track_name, Route::Flag (0), mode)); + track = boost::shared_ptr((new MidiTrack (*this, track_name, Route::Flag (0), mode))); - if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::MIDI, 1), false, this)) { + if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::AUDIO, 1), false, this)) { error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg; + goto failed; + } + + /* + if (nphysical_in) { + for (uint32_t x = 0; x < track->n_inputs().n_midi() && x < nphysical_in; ++x) { + + port = ""; + + if (Config->get_input_auto_connect() & AutoConnectPhysical) { + port = physinputs[(channels_used+x)%nphysical_in]; + } + + if (port.length() && track->connect_input (track->input (x), port, this)) { + break; + } + } + } + + for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) { + + port = ""; + + if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) { + port = physoutputs[(channels_used+x)%nphysical_out]; + } else if (Config->get_output_auto_connect() & AutoConnectMaster) { + if (_master_out) { + port = _master_out->input (x%_master_out->n_inputs().n_midi())->name(); + } + } + + if (port.length() && track->connect_output (track->output (x), port, this)) { + break; + } } channels_used += track->n_inputs ().n_midi(); + */ + + track->midi_diskstream()->non_realtime_input_change(); + track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes)); - track->set_remote_control_id (ntracks()); + //track->set_remote_control_id (control_id); new_routes.push_back (track); ret.push_back (track); @@ -1553,14 +1588,43 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) catch (failed_constructor &err) { error << _("Session: could not create new midi track.") << endmsg; - // XXX should we delete the tracks already created? - ret.clear (); - return ret; + + if (track) { + /* we need to get rid of this, since the track failed to be created */ + /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */ + + { + RCUWriter writer (diskstreams); + boost::shared_ptr ds = writer.get_copy(); + ds->remove (track->midi_diskstream()); + } + } + + goto failed; } - + + catch (AudioEngine::PortRegistrationFailure& pfe) { + + error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg; + + if (track) { + /* we need to get rid of this, since the track failed to be created */ + /* XXX arguably, MidiTrack::MidiTrack should not do the Session::add_diskstream() */ + + { + RCUWriter writer (diskstreams); + boost::shared_ptr ds = writer.get_copy(); + ds->remove (track->midi_diskstream()); + } + } + + goto failed; + } + --how_many; } + failed: if (!new_routes.empty()) { add_routes (new_routes, false); save_state (_current_snapshot_name); @@ -1733,8 +1797,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod failed: if (!new_routes.empty()) { - add_routes (new_routes, false); - save_state (_current_snapshot_name); + add_routes (new_routes, true); } return ret; @@ -1868,8 +1931,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ failure: if (!ret.empty()) { - add_routes (ret, false); - save_state (_current_snapshot_name); + add_routes (ret, true); } return ret; @@ -1901,7 +1963,10 @@ Session::add_routes (RouteList& new_routes, bool save) if ((*x)->is_control()) { _control_out = (*x); - } + } + + add_bundle ((*x)->bundle_for_inputs()); + add_bundle ((*x)->bundle_for_outputs()); } if (_control_out && IO::connecting_legal) { @@ -2003,13 +2068,14 @@ Session::remove_route (shared_ptr route) find_current_end (); + // We need to disconnect the routes inputs and outputs + + route->disconnect_inputs (0); + route->disconnect_outputs (0); + update_latency_compensation (false, false); set_dirty(); - // We need to disconnect the routes inputs and outputs - route->disconnect_inputs(NULL); - route->disconnect_outputs(NULL); - /* get rid of it from the dead wood collection in the route list manager */ /* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */ @@ -2742,8 +2808,6 @@ Session::source_by_id (const PBD::ID& id) source = i->second; } - /* XXX search MIDI or other searches here */ - return source; } @@ -2765,13 +2829,11 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn) return boost::shared_ptr(); } -string -Session::peak_path_from_audio_path (string audio_path) const +Glib::ustring +Session::peak_path (Glib::ustring base) const { sys::path peakfile_path(_session_dir->peak_path()); - - peakfile_path /= basename_nosuffix (audio_path) + peakfile_suffix; - + peakfile_path /= basename_nosuffix (base) + peakfile_suffix; return peakfile_path.to_string(); } @@ -3182,7 +3244,7 @@ Session::midi_path_from_name (string name) return spath; } - + boost::shared_ptr Session::create_midi_source_for_session (MidiDiskstream& ds) { @@ -3380,27 +3442,13 @@ Session::remove_empty_sounds () get_files_in_directory (_session_dir->sound_path(), audio_filenames); Glib::Mutex::Lock lm (source_lock); - - regex_t compiled_tape_track_pattern; - int err; - if ((err = regcomp (&compiled_tape_track_pattern, "/T[0-9][0-9][0-9][0-9]-", REG_EXTENDED|REG_NOSUB))) { + TapeFileMatcher tape_file_matcher; - char msg[256]; - - regerror (err, &compiled_tape_track_pattern, msg, sizeof (msg)); - - error << string_compose (_("Cannot compile tape track regexp for use (%1)"), msg) << endmsg; - return; - } + remove_if (audio_filenames.begin(), audio_filenames.end(), + sigc::mem_fun (tape_file_matcher, &TapeFileMatcher::matches)); for (vector::iterator i = audio_filenames.begin(); i != audio_filenames.end(); ++i) { - - // never remove files that appear to be a tape track - - if (regexec (&compiled_tape_track_pattern, i->c_str(), 0, 0, 0) == 0) { - continue; - } sys::path audio_file_path (_session_dir->sound_path()); @@ -3408,10 +3456,16 @@ Session::remove_empty_sounds () if (AudioFileSource::is_empty (*this, audio_file_path.to_string())) { - unlink (audio_file_path.to_string().c_str()); - - string peak_path = peak_path_from_audio_path (audio_file_path.to_string()); - unlink (peak_path.c_str()); + try + { + sys::remove (audio_file_path); + const string peakfile = peak_path (audio_file_path.to_string()); + sys::remove (peakfile); + } + catch (const sys::filesystem_error& err) + { + error << err.what() << endmsg; + } } } } @@ -3616,7 +3670,7 @@ Session::available_capture_duration () } void -Session::add_bundle (ARDOUR::Bundle* bundle) +Session::add_bundle (shared_ptr bundle) { { Glib::Mutex::Lock guard (bundle_lock); @@ -3629,7 +3683,7 @@ Session::add_bundle (ARDOUR::Bundle* bundle) } void -Session::remove_bundle (ARDOUR::Bundle* bundle) +Session::remove_bundle (shared_ptr bundle) { bool removed = false; @@ -3650,7 +3704,7 @@ Session::remove_bundle (ARDOUR::Bundle* bundle) set_dirty(); } -ARDOUR::Bundle * +shared_ptr Session::bundle_by_name (string name) const { Glib::Mutex::Lock lm (bundle_lock); @@ -3661,7 +3715,7 @@ Session::bundle_by_name (string name) const } } - return 0; + return boost::shared_ptr (); } void @@ -4112,3 +4166,29 @@ Session::compute_initial_length () return _engine.frame_rate() * 60 * 5; } +void +Session::sync_order_keys () +{ + if (!Config->get_sync_all_route_ordering()) { + /* leave order keys as they are */ + return; + } + + boost::shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + (*i)->sync_order_keys (); + } + + Route::SyncOrderKeys (); // EMIT SIGNAL +} + +void +Session::foreach_bundle (sigc::slot > sl) +{ + Glib::Mutex::Lock lm (bundle_lock); + for (BundleList::iterator i = _bundles.begin(); i != _bundles.end(); ++i) { + sl (*i); + } +} +