X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession.cc;h=19d562f84421beb4974ef574828641db9c98cda4;hb=e92c1669c1cdf857b8a3900abb9f891e6ca9fdad;hp=59c326264f54ec48664fb49f44d9844e885b7ace;hpb=1ca0e752fd1eacf2bf51afba00fef971e0ea05ee;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 59c326264f..19d562f844 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -40,10 +40,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -55,10 +57,12 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include +#include +#include #include #include #include @@ -73,6 +77,8 @@ #include #include #include +#include +#include #ifdef HAVE_LIBLO #include @@ -91,12 +97,13 @@ static const int CPU_CACHE_ALIGN = 64; static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */ #endif -const char* Session::old_sound_dir_name = X_("sounds"); -const char* Session::sound_dir_name = X_("audiofiles"); -const char* Session::peak_dir_name = X_("peaks"); -const char* Session::dead_sound_dir_name = X_("dead_sounds"); -const char* Session::interchange_dir_name = X_("interchange"); -const char* Session::export_dir_name = X_("export"); +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; @@ -106,23 +113,25 @@ 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()), _silent_buffers(new BufferSet()), - _send_buffers(new BufferSet()), + _mix_buffers(new BufferSet()), _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), + _session_dir (new SessionDirectory(fullpath)), pending_events (2048), //midi_requests (128), // the size of this should match the midi request pool size _send_smpte_update (false), diskstreams (new DiskstreamList), routes (new RouteList), auditioner ((Auditioner*) 0), + _bundle_xml_node (0), _click_io ((IO*) 0), main_outs (0) { @@ -131,18 +140,17 @@ Session::Session (AudioEngine &eng, 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); - + 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())) { - cerr << "create failed\n"; destroy (); throw failed_constructor (); } @@ -180,15 +188,17 @@ Session::Session (AudioEngine &eng, : _engine (eng), _scratch_buffers(new BufferSet()), _silent_buffers(new BufferSet()), - _send_buffers(new BufferSet()), + _mix_buffers(new BufferSet()), _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), + _session_dir ( new SessionDirectory(fullpath)), pending_events (2048), //midi_requests (16), _send_smpte_update (false), diskstreams (new DiskstreamList), routes (new RouteList), + _bundle_xml_node (0), main_outs (0) { @@ -216,7 +226,7 @@ Session::Session (AudioEngine &eng, 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, 0, initial_length)) { + if (create (new_session, string(), initial_length)) { destroy (); throw failed_constructor (); } @@ -246,7 +256,7 @@ Session::Session (AudioEngine &eng, } if (!rl.empty()) { - add_routes (rl); + add_routes (rl, false); } } @@ -259,17 +269,11 @@ Session::Session (AudioEngine &eng, 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 () @@ -287,6 +291,7 @@ Session::destroy () remove_pending_capture_state (); _state_of_the_state = StateOfTheState (CannotSave|Deletion); + _engine.remove_session (); GoingAway (); /* EMIT SIGNAL */ @@ -320,7 +325,7 @@ Session::destroy () delete _scratch_buffers; delete _silent_buffers; - delete _send_buffers; + delete _mix_buffers; AudioDiskstream::free_working_buffers(); @@ -455,20 +460,6 @@ Session::destroy () i = tmp; } -#ifdef TRACK_DESTRUCTION - cerr << "delete connections\n"; -#endif /* TRACK_DESTRUCTION */ - for (ConnectionList::iterator i = _connections.begin(); i != _connections.end(); ) { - ConnectionList::iterator tmp; - - tmp = i; - ++tmp; - - delete *i; - - i = tmp; - } - if (butler_mixdown_buffer) { delete [] butler_mixdown_buffer; } @@ -573,7 +564,7 @@ Session::when_engine_running () // XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO? } - /* Create a set of Connection objects that map + /* Create a set of Bundle objects that map to the physical outputs currently available */ @@ -583,24 +574,22 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1); - Connection* c = new OutputConnection (buf, true); + shared_ptr c (new AutoBundle (buf, true)); + c->set_channels (1); + c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); - c->add_port (); - c->add_connection (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); - - add_connection (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); - Connection* c = new InputConnection (buf, true); - - c->add_port (); - c->add_connection (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_connection (c); + add_bundle (c); } /* TWO: STEREO */ @@ -609,28 +598,24 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2); - Connection* c = new OutputConnection (buf, true); - - c->add_port (); - c->add_port (); - c->add_connection (0, _engine.get_nth_physical_output (DataType::AUDIO, np)); - c->add_connection (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_connection (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); - Connection* c = new InputConnection (buf, true); + 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)); - c->add_port (); - c->add_port (); - c->add_connection (0, _engine.get_nth_physical_input (DataType::AUDIO, np)); - c->add_connection (1, _engine.get_nth_physical_input (DataType::AUDIO, np+1)); - - add_connection (c); + add_bundle (c); } /* THREE MASTER */ @@ -675,13 +660,13 @@ Session::when_engine_running () } - Connection* c = new OutputConnection (_("Master Out"), true); + shared_ptr c (new AutoBundle (_("Master Out"), true)); - for (uint32_t n = 0; n < _master_out->n_inputs ().get_total(); ++n) { - c->add_port (); - c->add_connection ((int) n, _master_out->input(n)->name()); - } - add_connection (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 (); @@ -715,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); @@ -724,10 +710,7 @@ Session::when_engine_running () osc->set_session (*this); #endif - - _state_of_the_state = Clean; - - DirtyChanged (); /* EMIT SIGNAL */ + } void @@ -739,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 @@ -792,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 */ @@ -808,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. */ @@ -1098,7 +1089,7 @@ Session::disable_record (bool rt_context, bool force) if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) { - if (!Config->get_latched_record_enable () || force) { + if ((!Config->get_latched_record_enable () && !play_loop) || force) { g_atomic_int_set (&_record_status, Disabled); } else { if (rs == Recording) { @@ -1133,15 +1124,18 @@ Session::disable_record (bool rt_context, bool force) void Session::step_back_from_record () { - g_atomic_int_set (&_record_status, Enabled); + /* XXX really atomic compare+swap here */ + if (g_atomic_int_get (&_record_status) == Recording) { + g_atomic_int_set (&_record_status, Enabled); - if (Config->get_monitoring_model() == HardwareMonitoring) { - boost::shared_ptr dsl = diskstreams.reader(); - - for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { - if (Config->get_auto_input() && (*i)->record_enabled ()) { - //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (false); + if (Config->get_monitoring_model() == HardwareMonitoring) { + boost::shared_ptr dsl = diskstreams.reader(); + + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { + if (Config->get_auto_input() && (*i)->record_enabled ()) { + //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; + (*i)->monitor_input (false); + } } } } @@ -1242,8 +1236,10 @@ Session::set_frame_rate (nframes_t frames_per_second) sync_time_vars(); - Route::set_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); @@ -1467,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 */ { @@ -1479,20 +1477,31 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (dynamic_cast((*i).get()) != 0) { - if (!(*i)->hidden()) { + 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) */ @@ -1507,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); @@ -1525,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); @@ -1560,7 +1652,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (dynamic_cast((*i).get()) != 0) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { n++; channels_used += (*i)->n_inputs().n_audio(); } @@ -1705,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; @@ -1750,7 +1841,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (dynamic_cast((*i).get()) == 0) { - if (!(*i)->hidden() && (*i)->name() != _("master")) { + if (!(*i)->is_hidden() && (*i)->name() != _("master")) { bus_id++; } } @@ -1840,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; @@ -1865,15 +1955,18 @@ Session::add_routes (RouteList& new_routes, bool save) (*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr)); (*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed)); (*x)->output_changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x)); - (*x)->redirects_changed.connect (mem_fun (*this, &Session::update_latency_compensation_proxy)); + (*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false)); - if ((*x)->master()) { + if ((*x)->is_master()) { _master_out = (*x); } - if ((*x)->control()) { + 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) { @@ -1975,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) */ @@ -2124,7 +2218,7 @@ Session::update_route_solo_state () shared_ptr r = routes.reader (); - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->soloed()) { mute = true; if (dynamic_cast((*i).get())) { @@ -2687,14 +2781,10 @@ Session::remove_source (boost::weak_ptr src) { Glib::Mutex::Lock lm (source_lock); - - { - Glib::Mutex::Lock lm (source_lock); - - if ((i = sources.find (source->id())) != sources.end()) { - sources.erase (i); - } - } + + if ((i = sources.find (source->id())) != sources.end()) { + sources.erase (i); + } } if (!_state_of_the_state & InCleanup) { @@ -2718,8 +2808,6 @@ Session::source_by_id (const PBD::ID& id) source = i->second; } - /* XXX search MIDI or other searches here */ - return source; } @@ -2741,16 +2829,12 @@ 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 { - string res; - - res = peak_dir (); - res += PBD::basename_nosuffix (audio_path); - res += ".peak"; - - return res; + sys::path peakfile_path(_session_dir->peak_path()); + peakfile_path /= basename_nosuffix (base) + peakfile_suffix; + return peakfile_path.to_string(); } string @@ -2890,9 +2974,9 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { - spath = (*i).path; + SessionDirectory sdir((*i).path); - spath += sound_dir (false); + spath = sdir.sound_path().to_string(); if (destructive) { if (nchan < 2) { @@ -2929,7 +3013,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool } } - if (g_file_test (buf, G_FILE_TEST_EXISTS)) { + if (sys::exists(buf)) { existing++; } @@ -2952,7 +3036,9 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool string foo = buf; - spath = discover_best_sound_dir (); + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + + spath = sdir.sound_path().to_string(); spath += '/'; string::size_type pos = foo.find_last_of ('/'); @@ -3112,14 +3198,17 @@ Session::midi_path_from_name (string name) for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { - spath = (*i).path; + SessionDirectory sdir((*i).path); + + sys::path p = sdir.midi_path(); + + p /= legalized; - // FIXME: different directory from audio? - spath += sound_dir(false) + "/" + legalized; + spath = p.to_string(); snprintf (buf, sizeof(buf), "%s-%u.mid", spath.c_str(), cnt); - if (g_file_test (buf, G_FILE_TEST_EXISTS)) { + if (sys::exists (buf)) { existing++; } } @@ -3140,8 +3229,9 @@ Session::midi_path_from_name (string name) string foo = buf; - // FIXME: different directory than audio? - spath = discover_best_sound_dir (); + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + + spath = sdir.midi_path().to_string(); spath += '/'; string::size_type pos = foo.find_last_of ('/'); @@ -3154,13 +3244,13 @@ Session::midi_path_from_name (string name) return spath; } - + boost::shared_ptr Session::create_midi_source_for_session (MidiDiskstream& ds) { - string spath = midi_path_from_name (ds.name()); + string mpath = midi_path_from_name (ds.name()); - return boost::dynamic_pointer_cast (SourceFactory::createWritable (DataType::MIDI, *this, spath, false, frame_rate())); + return boost::dynamic_pointer_cast (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate())); } @@ -3347,46 +3437,37 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr a, boost:: void Session::remove_empty_sounds () { - PathScanner scanner; + vector audio_filenames; - vector* possible_audiofiles = scanner (sound_dir(), Config->get_possible_audio_file_regexp (), false, true); + 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 = possible_audiofiles->begin(); i != possible_audiofiles->end(); ++i) { - - /* never remove files that appear to be a tape track */ + for (vector::iterator i = audio_filenames.begin(); i != audio_filenames.end(); ++i) { - if (regexec (&compiled_tape_track_pattern, (*i)->c_str(), 0, 0, 0) == 0) { - delete *i; - continue; - } - - if (AudioFileSource::is_empty (*this, *(*i))) { + sys::path audio_file_path (_session_dir->sound_path()); - unlink ((*i)->c_str()); + audio_file_path /= *i; - string peak_path = peak_path_from_audio_path (**i); - unlink (peak_path.c_str()); - } + if (AudioFileSource::is_empty (*this, audio_file_path.to_string())) { - delete* i; + 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; + } + } } - - delete possible_audiofiles; } bool @@ -3406,7 +3487,7 @@ Session::set_all_solo (bool yn) shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { (*i)->set_solo (yn, this); } } @@ -3420,7 +3501,7 @@ Session::set_all_mute (bool yn) shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { (*i)->set_mute (yn, this); } } @@ -3502,65 +3583,51 @@ Session::record_enable_change_all (bool yn) } void -Session::add_redirect (Redirect* redirect) +Session::add_processor (Processor* processor) { Send* send; - Insert* insert; PortInsert* port_insert; PluginInsert* plugin_insert; - if ((insert = dynamic_cast (redirect)) != 0) { - if ((port_insert = dynamic_cast (insert)) != 0) { - _port_inserts.insert (_port_inserts.begin(), port_insert); - } else if ((plugin_insert = dynamic_cast (insert)) != 0) { - _plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert); - } else { - fatal << _("programming error: unknown type of Insert created!") << endmsg; - /*NOTREACHED*/ - } - } else if ((send = dynamic_cast (redirect)) != 0) { + if ((port_insert = dynamic_cast (processor)) != 0) { + _port_inserts.insert (_port_inserts.begin(), port_insert); + } else if ((plugin_insert = dynamic_cast (processor)) != 0) { + _plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert); + } else if ((send = dynamic_cast (processor)) != 0) { _sends.insert (_sends.begin(), send); } else { - fatal << _("programming error: unknown type of Redirect created!") << endmsg; + fatal << _("programming error: unknown type of Insert created!") << endmsg; /*NOTREACHED*/ } - redirect->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_redirect), redirect)); + processor->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_processor), processor)); set_dirty(); } void -Session::remove_redirect (Redirect* redirect) +Session::remove_processor (Processor* processor) { Send* send; - Insert* insert; PortInsert* port_insert; PluginInsert* plugin_insert; - if ((insert = dynamic_cast (redirect)) != 0) { - if ((port_insert = dynamic_cast (insert)) != 0) { - list::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert); - if (x != _port_inserts.end()) { - insert_bitset[port_insert->bit_slot()] = false; - _port_inserts.erase (x); - } - } else if ((plugin_insert = dynamic_cast (insert)) != 0) { - _plugin_inserts.remove (plugin_insert); - } else { - fatal << string_compose (_("programming error: %1"), - X_("unknown type of Insert deleted!")) - << endmsg; - /*NOTREACHED*/ - } - } else if ((send = dynamic_cast (redirect)) != 0) { + if ((port_insert = dynamic_cast (processor)) != 0) { + list::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert); + if (x != _port_inserts.end()) { + insert_bitset[port_insert->bit_slot()] = false; + _port_inserts.erase (x); + } + } else if ((plugin_insert = dynamic_cast (processor)) != 0) { + _plugin_inserts.remove (plugin_insert); + } else if ((send = dynamic_cast (processor)) != 0) { list::iterator x = find (_sends.begin(), _sends.end(), send); if (x != _sends.end()) { send_bitset[send->bit_slot()] = false; _sends.erase (x); } } else { - fatal << _("programming error: unknown type of Redirect deleted!") << endmsg; + fatal << _("programming error: unknown type of Insert deleted!") << endmsg; /*NOTREACHED*/ } @@ -3581,6 +3648,10 @@ Session::available_capture_duration () sample_bytes_on_disk = 3.0; break; + case FormatInt16: + sample_bytes_on_disk = 2.0; + break; + default: /* impossible, but keep some gcc versions happy */ fatal << string_compose (_("programming error: %1"), @@ -3599,52 +3670,52 @@ Session::available_capture_duration () } void -Session::add_connection (ARDOUR::Connection* connection) +Session::add_bundle (shared_ptr bundle) { { - Glib::Mutex::Lock guard (connection_lock); - _connections.push_back (connection); + Glib::Mutex::Lock guard (bundle_lock); + _bundles.push_back (bundle); } - ConnectionAdded (connection); /* EMIT SIGNAL */ + BundleAdded (bundle); /* EMIT SIGNAL */ set_dirty(); } void -Session::remove_connection (ARDOUR::Connection* connection) +Session::remove_bundle (shared_ptr bundle) { bool removed = false; { - Glib::Mutex::Lock guard (connection_lock); - ConnectionList::iterator i = find (_connections.begin(), _connections.end(), connection); + Glib::Mutex::Lock guard (bundle_lock); + BundleList::iterator i = find (_bundles.begin(), _bundles.end(), bundle); - if (i != _connections.end()) { - _connections.erase (i); + if (i != _bundles.end()) { + _bundles.erase (i); removed = true; } } if (removed) { - ConnectionRemoved (connection); /* EMIT SIGNAL */ + BundleRemoved (bundle); /* EMIT SIGNAL */ } set_dirty(); } -ARDOUR::Connection * -Session::connection_by_name (string name) const +shared_ptr +Session::bundle_by_name (string name) const { - Glib::Mutex::Lock lm (connection_lock); + Glib::Mutex::Lock lm (bundle_lock); - for (ConnectionList::const_iterator i = _connections.begin(); i != _connections.end(); ++i) { + for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) { if ((*i)->name() == name) { return* i; } } - return 0; + return boost::shared_ptr (); } void @@ -3660,9 +3731,17 @@ Session::tempo_map_changed (Change ignored) void Session::ensure_buffers (ChanCount howmany) { - // FIXME: NASTY assumption (midi block size == audio block size) + if (current_block_size == 0) + return; // too early? (is this ok?) + + // We need at least 2 MIDI scratch buffers to mix/merge + if (howmany.n_midi() < 2) + howmany.set_midi(2); + + // FIXME: JACK needs to tell us maximum MIDI buffer size + // Using nasty assumption (max # events == nframes) for now _scratch_buffers->ensure_buffers(howmany, current_block_size); - _send_buffers->ensure_buffers(howmany, current_block_size); + _mix_buffers->ensure_buffers(howmany, current_block_size); _silent_buffers->ensure_buffers(howmany, current_block_size); allocate_pan_automation_buffers (current_block_size, howmany.n_audio(), false); @@ -3871,12 +3950,13 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le boost::shared_ptr fsource; uint32_t x; char buf[PATH_MAX+1]; - string dir; ChanCount nchans(track.audio_diskstream()->n_channels()); nframes_t position; nframes_t this_chunk; nframes_t to_do; BufferSet buffers; + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + const string sound_dir = sdir.sound_path().to_string(); // any bigger than this seems to cause stack overflows in called functions const nframes_t chunk_size = (128 * 1024)/4; @@ -3894,13 +3974,11 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le if (track.has_external_redirects()) { goto out; } - - dir = discover_best_sound_dir (); for (uint32_t chan_n=0; chan_n < nchans.n_audio(); ++chan_n) { for (x = 0; x < 99999; ++x) { - snprintf (buf, sizeof(buf), "%s/%s-%d-bounce-%" PRIu32 ".wav", dir.c_str(), playlist->name().c_str(), chan_n, x+1); + snprintf (buf, sizeof(buf), "%s/%s-%d-bounce-%" PRIu32 ".wav", sound_dir.c_str(), playlist->name().c_str(), chan_n, x+1); if (access (buf, F_OK) != 0) { break; } @@ -4039,11 +4117,11 @@ Session::get_scratch_buffers (ChanCount count) } BufferSet& -Session::get_send_buffers (ChanCount count) +Session::get_mix_buffers (ChanCount count) { - assert(_send_buffers->available() >= count); - _send_buffers->set_count(count); - return *_send_buffers; + assert(_mix_buffers->available() >= count); + _mix_buffers->set_count(count); + return *_mix_buffers; } uint32_t @@ -4088,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); + } +} +