X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fardour%2Fsession.cc;h=14ef0e1ac5b346a5b6a48e40ea33569265c957da;hb=f8480d6392e6d0e61aa39e564904ba67822f711e;hp=e7f2c542e65eaed272b5100d3fd90b34cb0e3886;hpb=f7f9d6fdc40248b190ec9c6e1a886261d55777ae;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index e7f2c542e6..14ef0e1ac5 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2004 Paul Davis + Copyright (C) 1999-2004 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 @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +64,7 @@ #include #include #include -#include +#include #include #include #include @@ -79,6 +81,7 @@ #include #include #include +#include #ifdef HAVE_LIBLO #include @@ -97,17 +100,24 @@ 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; + +sigc::signal Session::Dialog; sigc::signal Session::AskAboutPendingState; +sigc::signal Session::AskAboutSampleRateMismatch; sigc::signal Session::SendFeedback; sigc::signal Session::SMPTEOffsetChanged; sigc::signal Session::StartTimeChanged; sigc::signal Session::EndTimeChanged; +sigc::signal Session::AutoBindingOn; +sigc::signal Session::AutoBindingOff; +sigc::signal Session::Exported; 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()), @@ -116,78 +126,50 @@ Session::Session (AudioEngine &eng, _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), + _midi_clock_port (default_midi_clock_port), _session_dir (new SessionDirectory(fullpath)), pending_events (2048), - //midi_requests (128), // the size of this should match the midi request pool size + post_transport_work((PostTransportWork)0), _send_smpte_update (false), + midi_requests (128), diskstreams (new DiskstreamList), routes (new RouteList), auditioner ((Auditioner*) 0), + _total_free_4k_blocks (0), + _bundle_xml_node (0), _click_io ((IO*) 0), - main_outs (0) + main_outs (0), + _metadata (new SessionMetadata()) { + bool new_session; + if (!eng.connected()) { throw failed_constructor(); } - n_physical_outputs = _engine.n_physical_outputs(); - n_physical_inputs = _engine.n_physical_inputs(); + cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl; - first_stage_init (fullpath, snapshot_name); + n_physical_outputs = _engine.n_physical_outputs(DataType::AUDIO); + n_physical_inputs = _engine.n_physical_inputs(DataType::AUDIO); - initialize_start_and_end_locations(0, compute_initial_length ()); + first_stage_init (fullpath, snapshot_name); - 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 (); - } + new_session = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)); - if(!create_session_file_from_template (*mix_template)) { + 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 (); } - + store_recent_sessions(_name, _path); - + bool was_dirty = dirty(); _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); @@ -217,23 +199,29 @@ Session::Session (AudioEngine &eng, _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), + _midi_clock_port (default_midi_clock_port), _session_dir ( new SessionDirectory(fullpath)), pending_events (2048), - //midi_requests (16), + post_transport_work((PostTransportWork)0), _send_smpte_update (false), + midi_requests (16), diskstreams (new DiskstreamList), routes (new RouteList), + _total_free_4k_blocks (0), + _bundle_xml_node (0), main_outs (0) { + bool new_session; + if (!eng.connected()) { throw failed_constructor(); } cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl; - n_physical_outputs = _engine.n_physical_outputs(); - n_physical_inputs = _engine.n_physical_inputs(); + n_physical_outputs = _engine.n_physical_outputs (DataType::AUDIO); + n_physical_inputs = _engine.n_physical_inputs (DataType::AUDIO); if (n_physical_inputs) { n_physical_inputs = max (requested_physical_in, n_physical_inputs); @@ -245,61 +233,57 @@ 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 (); + } } { /* set up Master Out and Control Out if necessary */ - + RouteList rl; int control_id = 1; - + if (control_out_channels) { shared_ptr r (new Route (*this, _("monitor"), -1, control_out_channels, -1, control_out_channels, Route::ControlOut)); r->set_remote_control_id (control_id++); - + rl.push_back (r); } - + if (master_out_channels) { shared_ptr r (new Route (*this, _("master"), -1, master_out_channels, -1, master_out_channels, Route::MasterOut)); r->set_remote_control_id (control_id); - + rl.push_back (r); } else { /* prohibit auto-connect to master, because there isn't one */ output_ac = AutoConnectOption (output_ac & ~AutoConnectMaster); } - + if (!rl.empty()) { - add_routes (rl); + add_routes (rl, false); } - + } 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); - - bool was_dirty = dirty (); + + store_recent_sessions (_name, _path); _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 () @@ -317,10 +301,11 @@ Session::destroy () remove_pending_capture_state (); _state_of_the_state = StateOfTheState (CannotSave|Deletion); + _engine.remove_session (); GoingAway (); /* EMIT SIGNAL */ - + /* do this */ notify_callbacks (); @@ -330,14 +315,14 @@ Session::destroy () _history.clear (); /* clear state tree so that no references to objects are held any more */ - + if (state_tree) { delete state_tree; } terminate_butler_thread (); //terminate_midi_thread (); - + if (click_data && click_data != default_click) { delete [] click_data; } @@ -353,7 +338,9 @@ Session::destroy () delete _mix_buffers; AudioDiskstream::free_working_buffers(); - + + Route::SyncOrderKeys.clear(); + #undef TRACK_DESTRUCTION #ifdef TRACK_DESTRUCTION cerr << "delete named selections\n"; @@ -378,10 +365,10 @@ Session::destroy () ++tmp; (*i)->drop_references (); - + i = tmp; } - + for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ) { PlaylistList::iterator tmp; @@ -389,17 +376,17 @@ Session::destroy () ++tmp; (*i)->drop_references (); - + i = tmp; } - + playlists.clear (); unused_playlists.clear (); #ifdef TRACK_DESTRUCTION cerr << "delete regions\n"; #endif /* TRACK_DESTRUCTION */ - + for (RegionList::iterator i = regions.begin(); i != regions.end(); ) { RegionList::iterator tmp; @@ -416,7 +403,7 @@ Session::destroy () #ifdef TRACK_DESTRUCTION cerr << "delete routes\n"; #endif /* TRACK_DESTRUCTION */ - { + { RCUWriter writer (routes); boost::shared_ptr r = writer.get_copy (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { @@ -454,7 +441,6 @@ Session::destroy () i = tmp; } - sources.clear (); #ifdef TRACK_DESTRUCTION @@ -476,7 +462,7 @@ Session::destroy () #endif /* TRACK_DESTRUCTION */ for (list::iterator i = edit_groups.begin(); i != edit_groups.end(); ) { list::iterator tmp; - + tmp = i; ++tmp; @@ -484,7 +470,7 @@ Session::destroy () i = tmp; } - + if (butler_mixdown_buffer) { delete [] butler_mixdown_buffer; } @@ -511,7 +497,7 @@ Session::set_worst_io_latencies () } boost::shared_ptr r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { _worst_output_latency = max (_worst_output_latency, (*i)->output_latency()); _worst_input_latency = max (_worst_input_latency, (*i)->input_latency()); @@ -525,9 +511,13 @@ Session::when_engine_running () /* we don't want to run execute this again */ + BootMessage (_("Set block size and sample rate")); + set_block_size (_engine.frames_per_cycle()); set_frame_rate (_engine.frame_rate()); + BootMessage (_("Using configuration")); + Config->map_parameters (mem_fun (*this, &Session::config_changed)); /* every time we reconnect, recompute worst case output latencies */ @@ -546,15 +536,15 @@ Session::when_engine_running () try { XMLNode* child = 0; - + _click_io.reset (new ClickIO (*this, "click", 0, 0, -1, -1)); if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) { /* existing state for Click */ - + if (_click_io->set_state (*child->children().front()) == 0) { - + _clicking = Config->get_clicking (); } else { @@ -564,7 +554,7 @@ Session::when_engine_running () } } else { - + /* default state for Click */ first_physical_output = _engine.get_nth_physical_output (DataType::AUDIO, 0); @@ -583,6 +573,8 @@ Session::when_engine_running () error << _("cannot setup Click I/O") << endmsg; } + BootMessage (_("Compute I/O Latencies")); + set_worst_io_latencies (); if (_clicking) { @@ -593,28 +585,30 @@ Session::when_engine_running () to the physical outputs currently available */ + BootMessage (_("Set up standard connections")); + /* ONE: MONO */ for (uint32_t np = 0; np < n_physical_outputs; ++np) { char buf[32]; snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1); - shared_ptr 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); - shared_ptr 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 */ @@ -623,24 +617,24 @@ Session::when_engine_running () char buf[32]; snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2); - shared_ptr 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); - shared_ptr 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 */ @@ -648,24 +642,24 @@ Session::when_engine_running () if (_master_out) { /* create master/control ports */ - + if (_master_out) { uint32_t n; /* force the master to ignore any later call to this */ - + if (_master_out->pending_state_node) { _master_out->ports_became_legal(); } /* no panner resets till we are through */ - + _master_out->defer_pan_reset (); - + while (_master_out->n_inputs().n_audio() < _master_out->input_maximum().n_audio()) { if (_master_out->add_input_port ("", this, DataType::AUDIO)) { - error << _("cannot setup master inputs") + error << _("cannot setup master inputs") << endmsg; break; } @@ -682,24 +676,28 @@ Session::when_engine_running () } _master_out->allow_pan_reset (); - + } - shared_ptr 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); + } + + BootMessage (_("Setup signal flow and plugins")); hookup_io (); /* catch up on send+insert cnts */ + BootMessage (_("Catch up with send/insert state")); + insert_cnt = 0; - + for (list::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) { uint32_t id; @@ -714,7 +712,7 @@ Session::when_engine_running () for (list::iterator i = _sends.begin(); i != _sends.end(); ++i) { uint32_t id; - + if (sscanf ((*i)->name().c_str(), "%*s %u", &id) == 1) { if (id > send_cnt) { send_cnt = id; @@ -722,22 +720,23 @@ Session::when_engine_running () } } - + _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty)); /* hook us up to the engine */ + BootMessage (_("Connect to engine")); + _engine.set_session (this); #ifdef HAVE_LIBLO /* and to OSC */ + BootMessage (_("OSC startup")); + osc->set_session (*this); #endif - _state_of_the_state = Clean; - - DirtyChanged (); /* EMIT SIGNAL */ } void @@ -749,17 +748,18 @@ Session::hookup_io () _state_of_the_state = StateOfTheState (_state_of_the_state | InitialConnecting); + if (auditioner == 0) { - + /* we delay creating the auditioner till now because it makes its own connections to ports. the engine has to be running for this to work. */ - + try { auditioner.reset (new Auditioner (*this)); } - + catch (failed_constructor& err) { warning << _("cannot create Auditioner: no auditioning of regions possible") << endmsg; } @@ -797,12 +797,18 @@ Session::hookup_io () cports.push_back (_control_out->input(n)->name()); } - boost::shared_ptr r = routes.reader (); + boost::shared_ptr r = routes.reader (); 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 */ @@ -818,6 +824,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. */ @@ -832,10 +839,10 @@ Session::hookup_io () void Session::playlist_length_changed () { - /* we can't just increase end_location->end() if pl->get_maximum_extent() + /* we can't just increase end_location->end() if pl->get_maximum_extent() if larger. if the playlist used to be the longest playlist, and its now shorter, we have to decrease end_location->end(). hence, - we have to iterate over all diskstreams and check the + we have to iterate over all diskstreams and check the playlists currently in use. */ find_current_end (); @@ -849,7 +856,7 @@ Session::diskstream_playlist_changed (boost::shared_ptr dstream) if ((playlist = dstream->playlist()) != 0) { playlist->LengthChanged.connect (mem_fun (this, &Session::playlist_length_changed)); } - + /* see comment in playlist_length_changed () */ find_current_end (); } @@ -902,7 +909,7 @@ Session::auto_punch_start_changed (Location* location) /* capture start has been changed, so save new pending state */ save_state ("", true); } -} +} void Session::auto_punch_end_changed (Location* location) @@ -910,7 +917,7 @@ Session::auto_punch_end_changed (Location* location) nframes_t when_to_stop = location->end(); // when_to_stop += _worst_output_latency + _worst_input_latency; replace_event (Event::PunchOut, when_to_stop); -} +} void Session::auto_punch_changed (Location* location) @@ -920,7 +927,7 @@ Session::auto_punch_changed (Location* location) replace_event (Event::PunchIn, location->start()); //when_to_stop += _worst_output_latency + _worst_input_latency; replace_event (Event::PunchOut, when_to_stop); -} +} void Session::auto_loop_changed (Location* location) @@ -934,12 +941,12 @@ Session::auto_loop_changed (Location* location) if (_transport_frame > location->end()) { // relocate to beginning of loop clear_events (Event::LocateRoll); - + request_locate (location->start(), true); } else if (Config->get_seamless_loop() && !loop_changing) { - + // schedule a locate-roll to refill the diskstreams at the // previous loop end loop_changing = true; @@ -951,10 +958,9 @@ Session::auto_loop_changed (Location* location) } } - } + } last_loopend = location->end(); - } void @@ -977,7 +983,7 @@ Session::set_auto_punch_location (Location* location) if (location == 0) { return; } - + if (location->end() <= location->start()) { error << _("Session: you can't use that location for auto punch (start <= end)") << endmsg; return; @@ -986,12 +992,16 @@ Session::set_auto_punch_location (Location* location) auto_punch_start_changed_connection.disconnect(); auto_punch_end_changed_connection.disconnect(); auto_punch_changed_connection.disconnect(); - + auto_punch_start_changed_connection = location->start_changed.connect (mem_fun (this, &Session::auto_punch_start_changed)); auto_punch_end_changed_connection = location->end_changed.connect (mem_fun (this, &Session::auto_punch_end_changed)); auto_punch_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_punch_changed)); location->set_auto_punch (true, this); + + + auto_punch_changed (location); + auto_punch_location_changed (location); } @@ -1008,7 +1018,7 @@ Session::set_auto_loop_location (Location* location) remove_event (existing->end(), Event::AutoLoop); auto_loop_location_changed (0); } - + set_dirty(); if (location == 0) { @@ -1021,16 +1031,23 @@ Session::set_auto_loop_location (Location* location) } last_loopend = location->end(); - + auto_loop_start_changed_connection.disconnect(); auto_loop_end_changed_connection.disconnect(); auto_loop_changed_connection.disconnect(); - + auto_loop_start_changed_connection = location->start_changed.connect (mem_fun (this, &Session::auto_loop_changed)); auto_loop_end_changed_connection = location->end_changed.connect (mem_fun (this, &Session::auto_loop_changed)); auto_loop_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_loop_changed)); location->set_auto_loop (true, this); + + /* take care of our stuff first */ + + auto_loop_changed (location); + + /* now tell everyone else */ + auto_loop_location_changed (location); } @@ -1066,7 +1083,13 @@ Session::handle_locations_changed (Locations::LocationList& locations) set_auto_loop_location (location); set_loop = true; } - + + if (location->is_start()) { + start_location = location; + } + if (location->is_end()) { + end_location = location; + } } if (!set_loop) { @@ -1077,7 +1100,7 @@ Session::handle_locations_changed (Locations::LocationList& locations) } set_dirty(); -} +} void Session::enable_record () @@ -1092,7 +1115,7 @@ Session::enable_record () boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { - (*i)->monitor_input (true); + (*i)->monitor_input (true); } } } @@ -1124,14 +1147,14 @@ Session::disable_record (bool rt_context, bool force) if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) { boost::shared_ptr dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { - (*i)->monitor_input (false); + (*i)->monitor_input (false); } } } - + RecordStateChanged (); /* emit signal */ if (!rt_context) { @@ -1147,13 +1170,13 @@ Session::step_back_from_record () if (g_atomic_int_get (&_record_status) == Recording) { g_atomic_int_set (&_record_status, Enabled); - if (Config->get_monitoring_model() == HardwareMonitoring) { + if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) { boost::shared_ptr dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { - if (Config->get_auto_input() && (*i)->record_enabled ()) { + if ((*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (false); + (*i)->monitor_input (false); } } } @@ -1174,7 +1197,7 @@ Session::maybe_enable_record () if (_transport_speed) { if (!Config->get_punch_in()) { enable_record (); - } + } } else { deliver_mmc (MIDI::MachineControl::cmdRecordPause, _transport_frame); RecordStateChanged (); /* EMIT SIGNAL */ @@ -1191,7 +1214,7 @@ Session::audible_frame () const nframes_t tf; /* the first of these two possible settings for "offset" - mean that the audible frame is stationary until + mean that the audible frame is stationary until audio emerges from the latency compensation "pseudo-pipeline". @@ -1204,7 +1227,7 @@ Session::audible_frame () const if (offset > current_block_size) { offset -= current_block_size; - } else { + } else { /* XXX is this correct? if we have no external physical connections and everything is internal then surely this is zero? still, how @@ -1234,7 +1257,7 @@ Session::audible_frame () const /* MOVING */ /* take latency into account */ - + ret -= offset; } @@ -1245,7 +1268,7 @@ void Session::set_frame_rate (nframes_t frames_per_second) { /** \fn void Session::set_frame_size(nframes_t) - the AudioEngine object that calls this guarantees + the AudioEngine object that calls this guarantees that it will not be called while we are also in ::process(). Its fine to do things that block here. @@ -1258,7 +1281,7 @@ Session::set_frame_rate (nframes_t frames_per_second) 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); @@ -1270,14 +1293,14 @@ Session::set_frame_rate (nframes_t frames_per_second) void Session::set_block_size (nframes_t nframes) { - /* the AudioEngine guarantees + /* the AudioEngine guarantees that it will not be called while we are also in ::process(). It is therefore fine to do things that block here. */ - { - + { + current_block_size = nframes; ensure_buffers(_scratch_buffers->available()); @@ -1294,7 +1317,7 @@ Session::set_block_size (nframes_t nframes) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_block_size (nframes); } - + boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { (*i)->set_block_size (nframes); @@ -1309,18 +1332,18 @@ Session::set_default_fade (float steepness, float fade_msecs) { #if 0 nframes_t fade_frames; - + /* Don't allow fade of less 1 frame */ - + if (fade_msecs < (1000.0 * (1.0/_current_frame_rate))) { fade_msecs = 0; fade_frames = 0; } else { - + fade_frames = (nframes_t) floor (fade_msecs * _current_frame_rate * 0.001); - + } default_fade_msecs = fade_msecs; @@ -1335,7 +1358,7 @@ Session::set_default_fade (float steepness, float fade_msecs) set_dirty(); /* XXX have to do this at some point */ - /* foreach region using default fade, reset, then + /* foreach region using default fade, reset, then refill_all_diskstream_buffers (); */ #endif @@ -1371,7 +1394,7 @@ trace_terminal (shared_ptr r1, shared_ptr rbase) if ((r1->fed_by.find (rbase) != r1->fed_by.end()) && (rbase->fed_by.find (r1) != rbase->fed_by.end())) { info << string_compose(_("feedback loop setup between %1 and %2"), r1->name(), rbase->name()) << endmsg; return; - } + } /* make a copy of the existing list of routes that feed r1 */ @@ -1435,45 +1458,45 @@ void Session::resort_routes_using (shared_ptr r) { RouteList::iterator i, j; - + for (i = r->begin(); i != r->end(); ++i) { - + (*i)->fed_by.clear (); - + for (j = r->begin(); j != r->end(); ++j) { - + /* although routes can feed themselves, it will cause an endless recursive descent if we detect it. so don't bother checking for self-feeding. */ - + if (*j == *i) { continue; } - + if ((*j)->feeds (*i)) { (*i)->fed_by.insert (*j); - } + } } } - + for (i = r->begin(); i != r->end(); ++i) { trace_terminal (*i, *i); } - + RouteSorter cmp; r->sort (cmp); - + #if 0 cerr << "finished route resort\n"; - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { cerr << " " << (*i)->name() << " signal order = " << (*i)->order_key ("signal") << endl; } cerr << endl; #endif - + } list > @@ -1482,10 +1505,12 @@ 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 */ @@ -1496,20 +1521,28 @@ 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; + + _engine.get_physical_outputs (DataType::MIDI, physoutputs); + _engine.get_physical_inputs (DataType::MIDI, physinputs); + + // control_id = ntracks() + nbusses(); + 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) */ - + do { ++track_id; @@ -1519,20 +1552,60 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) if (route_by_name (track_name) == 0) { break; } - + } while (track_id < (UINT_MAX-1)); + shared_ptr track; + try { - shared_ptr track (new MidiTrack (*this, track_name, Route::Flag (0), mode)); - - if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::MIDI, 1), false, this)) { + track = boost::shared_ptr((new MidiTrack (*this, track_name, Route::Flag (0), mode))); + + 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); @@ -1540,14 +1613,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); @@ -1585,11 +1687,10 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod vector physinputs; vector physoutputs; - uint32_t nphysical_in; - uint32_t nphysical_out; - _engine.get_physical_outputs (physoutputs); - _engine.get_physical_inputs (physinputs); + _engine.get_physical_outputs (DataType::AUDIO, physoutputs); + _engine.get_physical_inputs (DataType::AUDIO, physinputs); + control_id = ntracks() + nbusses() + 1; while (how_many) { @@ -1599,7 +1700,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod save, close,restart,add new route - first named route is now Audio2) */ - + do { ++track_id; @@ -1609,26 +1710,14 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod if (route_by_name (track_name) == 0) { break; } - - } 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; - } + } while (track_id < (UINT_MAX-1)); shared_ptr track; - + try { track = boost::shared_ptr((new AudioTrack (*this, track_name, Route::Flag (0), mode))); - + if (track->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), input_channels, output_channels) @@ -1636,42 +1725,48 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod goto failed; } - if (nphysical_in) { + if (!physinputs.empty()) { + uint32_t nphysical_in = physinputs.size(); + for (uint32_t x = 0; x < track->n_inputs().n_audio() && 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_audio())->name(); + + if (!physoutputs.empty()) { + uint32_t nphysical_out = physoutputs.size(); + + for (uint32_t x = 0; x < track->n_outputs().n_audio(); ++x) { + + port = ""; + + if (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_audio())->name(); + } + } + + if (port.length() && track->connect_output (track->output (x), port, this)) { + break; } - } - - if (port.length() && track->connect_output (track->output (x), port, this)) { - break; } } - + channels_used += track->n_inputs ().n_audio(); track->audio_diskstream()->non_realtime_input_change(); - + track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes)); track->set_remote_control_id (control_id); ++control_id; @@ -1687,7 +1782,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod /* 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->audio_diskstream()); @@ -1705,7 +1800,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod /* 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->audio_diskstream()); @@ -1720,8 +1815,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; @@ -1735,14 +1829,14 @@ Session::set_remote_control_ids () shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if ( MixerOrdered == m) { + if ( MixerOrdered == m) { long order = (*i)->order_key(N_("signal")); (*i)->set_remote_control_id( order+1 ); } else if ( EditorOrdered == m) { long order = (*i)->order_key(N_("editor")); (*i)->set_remote_control_id( order+1 ); } else if ( UserOrdered == m) { - //do nothing ... only changes to remote id's are initiated by user + //do nothing ... only changes to remote id's are initiated by user } } } @@ -1754,6 +1848,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ char bus_name[32]; uint32_t bus_id = 1; uint32_t n = 0; + uint32_t channels_used = 0; string port; RouteList ret; uint32_t control_id; @@ -1764,9 +1859,12 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (dynamic_cast((*i).get()) == 0) { + if (boost::dynamic_pointer_cast(*i) == 0) { + /* its a bus ? */ if (!(*i)->is_hidden() && (*i)->name() != _("master")) { bus_id++; + n++; + channels_used += (*i)->n_inputs().n_audio(); } } } @@ -1775,8 +1873,8 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ vector physinputs; vector physoutputs; - _engine.get_physical_outputs (physoutputs); - _engine.get_physical_inputs (physinputs); + _engine.get_physical_outputs (DataType::AUDIO, physoutputs); + _engine.get_physical_inputs (DataType::AUDIO, physinputs); control_id = ntracks() + nbusses() + 1; while (how_many) { @@ -1794,31 +1892,31 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ try { shared_ptr bus (new Route (*this, bus_name, -1, -1, -1, -1, Route::Flag(0), DataType::AUDIO)); - + if (bus->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), input_channels, output_channels) << endmsg; goto failure; } - + for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().n_audio(); ++x) { - + port = ""; if (Config->get_input_auto_connect() & AutoConnectPhysical) { port = physinputs[((n+x)%n_physical_inputs)]; - } - + } + if (port.length() && bus->connect_input (bus->input (x), port, this)) { break; } } - - for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs().n_audio(); ++x) { - + + for (uint32_t x = 0; x < bus->n_outputs().n_audio(); ++x) { + port = ""; - + if (Config->get_output_auto_connect() & AutoConnectPhysical) { port = physoutputs[((n+x)%n_physical_outputs)]; } else if (Config->get_output_auto_connect() & AutoConnectMaster) { @@ -1826,18 +1924,20 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ port = _master_out->input (x%_master_out->n_inputs().n_audio())->name(); } } - + if (port.length() && bus->connect_output (bus->output (x), port, this)) { break; } } - + + channels_used += bus->n_inputs ().n_audio(); + bus->set_remote_control_id (control_id); ++control_id; ret.push_back (bus); } - + catch (failed_constructor &err) { error << _("Session: could not create new audio route.") << endmsg; @@ -1855,8 +1955,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; @@ -1866,7 +1965,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ void Session::add_routes (RouteList& new_routes, bool save) { - { + { RCUWriter writer (routes); shared_ptr r = writer.get_copy (); r->insert (r->end(), new_routes.begin(), new_routes.end()); @@ -1874,24 +1973,28 @@ Session::add_routes (RouteList& new_routes, bool save) } for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { - + boost::weak_ptr wpr (*x); (*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)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false)); - + if ((*x)->is_master()) { _master_out = (*x); } - + if ((*x)->is_control()) { _control_out = (*x); } - add_bundle ((*x)->bundle_for_inputs()); - add_bundle ((*x)->bundle_for_outputs()); + /* only busses get automatic bundles formed */ + + if (!boost::dynamic_pointer_cast (*x)) { + add_bundle ((*x)->bundle_for_inputs()); + add_bundle ((*x)->bundle_for_outputs()); + } } if (_control_out && IO::connecting_legal) { @@ -1906,7 +2009,7 @@ Session::add_routes (RouteList& new_routes, bool save) for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { (*x)->set_control_outs (cports); } - } + } set_dirty(); @@ -1922,7 +2025,7 @@ Session::add_diskstream (boost::shared_ptr dstream) { /* need to do this in case we're rolling at the time, to prevent false underruns */ dstream->do_refill_with_alloc (); - + dstream->set_block_size (current_block_size); { @@ -1930,7 +2033,7 @@ Session::add_diskstream (boost::shared_ptr dstream) boost::shared_ptr ds = writer.get_copy(); ds->push_back (dstream); /* writer goes out of scope, copies ds back to main */ - } + } dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), dstream)); /* this will connect to future changes, and check the current length */ @@ -1943,10 +2046,10 @@ Session::add_diskstream (boost::shared_ptr dstream) void Session::remove_route (shared_ptr route) { - { + { RCUWriter writer (routes); shared_ptr rs = writer.get_copy (); - + rs->remove (route); /* deleting the master out seems like a dumb @@ -1971,17 +2074,17 @@ Session::remove_route (shared_ptr route) } update_route_solo_state (); - + /* writer goes out of scope, forces route list update */ } Track* t; boost::shared_ptr ds; - + if ((t = dynamic_cast(route.get())) != 0) { ds = t->diskstream(); } - + if (ds) { { @@ -1992,14 +2095,15 @@ 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) */ @@ -2010,12 +2114,14 @@ Session::remove_route (shared_ptr route) route->drop_references (); + sync_order_keys (N_("session")); + /* save the new state of the world */ if (save_state (_current_snapshot_name)) { save_history (_current_snapshot_name); } -} +} void Session::route_mute_changed (void* src) @@ -2025,12 +2131,12 @@ Session::route_mute_changed (void* src) void Session::route_solo_changed (void* src, boost::weak_ptr wpr) -{ +{ if (solo_update_disabled) { // We know already return; } - + bool is_track; boost::shared_ptr route = wpr.lock (); @@ -2041,46 +2147,46 @@ Session::route_solo_changed (void* src, boost::weak_ptr wpr) } is_track = (boost::dynamic_pointer_cast(route) != 0); - + shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - + /* soloing a track mutes all other tracks, soloing a bus mutes all other busses */ - + if (is_track) { - + /* don't mess with busses */ - + if (dynamic_cast((*i).get()) == 0) { continue; } - + } else { - + /* don't mess with tracks */ - + if (dynamic_cast((*i).get()) != 0) { continue; } } - + if ((*i) != route && ((*i)->mix_group () == 0 || (*i)->mix_group () != route->mix_group () || !route->mix_group ()->is_active())) { - + if ((*i)->soloed()) { - + /* if its already soloed, and solo latching is enabled, then leave it as it is. */ - + if (Config->get_solo_latched()) { continue; - } + } } - + /* do it */ solo_update_disabled = true; @@ -2088,7 +2194,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr wpr) solo_update_disabled = false; } } - + bool something_soloed = false; bool same_thing_soloed = false; bool signal = false; @@ -2110,12 +2216,12 @@ Session::route_solo_changed (void* src, boost::weak_ptr wpr) break; } } - + if (something_soloed != currently_soloing) { signal = true; currently_soloing = something_soloed; } - + modify_solo_mute (is_track, same_thing_soloed); if (signal) { @@ -2139,7 +2245,7 @@ Session::update_route_solo_state () /* this is where we actually implement solo by changing the solo mute setting of each track. */ - + shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { @@ -2164,7 +2270,7 @@ Session::update_route_solo_state () for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_solo_mute (false); } - + if (signal) { SoloActive (false); } @@ -2185,11 +2291,11 @@ Session::modify_solo_mute (bool is_track, bool mute) shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - + if (is_track) { - + /* only alter track solo mute */ - + if (dynamic_cast((*i).get())) { if ((*i)->soloed()) { (*i)->set_solo_mute (!mute); @@ -2213,7 +2319,7 @@ Session::modify_solo_mute (bool is_track, bool mute) /* don't mute master or control outs in response to another bus solo */ - + if ((*i) != _master_out && (*i) != _control_out) { (*i)->set_solo_mute (mute); @@ -2223,7 +2329,7 @@ Session::modify_solo_mute (bool is_track, bool mute) } } -} +} void @@ -2235,8 +2341,8 @@ Session::catch_up_on_solo () has. */ update_route_solo_state(); -} - +} + shared_ptr Session::route_by_name (string name) { @@ -2299,11 +2405,13 @@ nframes_t Session::get_maximum_extent () const { nframes_t max = 0; - nframes_t me; + nframes_t me; boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::const_iterator i = dsl->begin(); i != dsl->end(); ++i) { + if ((*i)->destructive()) //ignore tape tracks when getting max extents + continue; boost::shared_ptr pl = (*i)->playlist(); if ((me = pl->get_maximum_extent()) > max) { max = me; @@ -2352,7 +2460,7 @@ Session::new_region_name (string old) char buf[len]; if ((last_period = old.find_last_of ('.')) == string::npos) { - + /* no period present - add one explicitly */ old += '.'; @@ -2380,7 +2488,7 @@ Session::new_region_name (string old) break; } } - + if (i == regions.end()) { break; } @@ -2388,14 +2496,14 @@ Session::new_region_name (string old) if (number != (UINT_MAX-1)) { return buf; - } + } error << string_compose (_("cannot create new name for region \"%1\""), old) << endmsg; return old; } int -Session::region_name (string& result, string base, bool newlevel) const +Session::region_name (string& result, string base, bool newlevel) { char buf[16]; string subbase; @@ -2403,19 +2511,15 @@ Session::region_name (string& result, string base, bool newlevel) const assert(base.find("/") == string::npos); if (base == "") { - + Glib::Mutex::Lock lm (region_lock); snprintf (buf, sizeof (buf), "%d", (int)regions.size() + 1); - - result = "region."; result += buf; } else { - /* XXX this is going to be slow. optimize me later */ - if (newlevel) { subbase = base; } else { @@ -2429,89 +2533,137 @@ Session::region_name (string& result, string base, bool newlevel) const } - bool name_taken = true; - { Glib::Mutex::Lock lm (region_lock); - - for (int n = 1; n < 5000; ++n) { - - result = subbase; - snprintf (buf, sizeof (buf), ".%d", n); + + map::iterator x; + + result = subbase; + + if ((x = region_name_map.find (subbase)) == region_name_map.end()) { + result += ".1"; + region_name_map[subbase] = 1; + } else { + x->second++; + snprintf (buf, sizeof (buf), ".%d", x->second); + result += buf; - - name_taken = false; - - for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { - if (i->second->name() == result) { - name_taken = true; - break; - } - } - - if (!name_taken) { - break; - } } } - - if (name_taken) { - fatal << string_compose(_("too many regions with names like %1"), base) << endmsg; - /*NOTREACHED*/ - } } + return 0; -} +} void Session::add_region (boost::shared_ptr region) { - boost::shared_ptr other; + vector > v; + v.push_back (region); + add_regions (v); +} + +void +Session::add_regions (vector >& new_regions) +{ bool added = false; - { + { Glib::Mutex::Lock lm (region_lock); - RegionList::iterator x; + for (vector >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) { + + boost::shared_ptr region = *ii; + + if (region == 0) { + + error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg; + + } else { + + RegionList::iterator x; + + for (x = regions.begin(); x != regions.end(); ++x) { + + if (region->region_list_equivalent (x->second)) { + break; + } + } + + if (x == regions.end()) { + + pair entry; + + entry.first = region->id(); + entry.second = region; - for (x = regions.begin(); x != regions.end(); ++x) { + pair x = regions.insert (entry); - other = x->second; + if (!x.second) { + return; + } - if (region->region_list_equivalent (other)) { - break; + added = true; + } } } + } + + /* mark dirty because something has changed even if we didn't + add the region to the region list. + */ - if (x == regions.end()) { + set_dirty (); + + if (added) { + + vector > v; + boost::shared_ptr first_r; - pair entry; + for (vector >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) { - entry.first = region->id(); - entry.second = region; + boost::shared_ptr region = *ii; - pair x = regions.insert (entry); + if (region == 0) { + error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg; - if (!x.second) { - return; + } else { + v.push_back (region); + + if (!first_r) { + first_r = region; + } } - added = true; - } + region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr(region))); + region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr(region))); + + update_region_name_map (region); + } + if (!v.empty()) { + RegionsAdded (v); /* EMIT SIGNAL */ + } } +} - /* mark dirty because something has changed even if we didn't - add the region to the region list. - */ - - set_dirty(); +void +Session::update_region_name_map (boost::shared_ptr region) +{ + string::size_type last_period = region->name().find_last_of ('.'); - if (added) { - region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr(region))); - region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr(region))); - RegionAdded (region); /* EMIT SIGNAL */ + if (last_period != string::npos && last_period < region->name().length() - 1) { + + string base = region->name().substr (0, last_period); + string number = region->name().substr (last_period+1); + map::iterator x; + + /* note that if there is no number, we get zero from atoi, + which is just fine + */ + + region_name_map[base] = atoi (number); } } @@ -2528,6 +2680,10 @@ Session::region_changed (Change what_changed, boost::weak_ptr weak_regio /* relay hidden changes */ RegionHiddenChange (region); } + + if (what_changed & NameChanged) { + update_region_name_map (region); + } } void @@ -2542,7 +2698,7 @@ Session::remove_region (boost::weak_ptr weak_region) bool removed = false; - { + { Glib::Mutex::Lock lm (region_lock); if ((i = regions.find (region->id())) != regions.end()) { @@ -2567,7 +2723,7 @@ Session::find_whole_file_parent (boost::shared_ptr child) { RegionList::iterator i; boost::shared_ptr region; - + Glib::Mutex::Lock lm (region_lock); for (i = regions.begin(); i != regions.end(); ++i) { @@ -2580,10 +2736,10 @@ Session::find_whole_file_parent (boost::shared_ptr child) return region; } } - } + } return boost::shared_ptr (); -} +} void Session::find_equivalent_playlist_regions (boost::shared_ptr region, vector >& result) @@ -2596,20 +2752,14 @@ int Session::destroy_region (boost::shared_ptr region) { vector > srcs; - + { - boost::shared_ptr aregion; - - if ((aregion = boost::dynamic_pointer_cast (region)) == 0) { - return 0; - } - - if (aregion->playlist()) { - aregion->playlist()->destroy_region (region); + if (region->playlist()) { + region->playlist()->destroy_region (region); } - - for (uint32_t n = 0; n < aregion->n_channels(); ++n) { - srcs.push_back (aregion->source (n)); + + for (uint32_t n = 0; n < region->n_channels(); ++n) { + srcs.push_back (region->source (n)); } } @@ -2617,17 +2767,10 @@ Session::destroy_region (boost::shared_ptr region) for (vector >::iterator i = srcs.begin(); i != srcs.end(); ++i) { - if (!(*i)->used()) { - boost::shared_ptr afs = boost::dynamic_pointer_cast(*i); - - if (afs) { - (afs)->mark_for_remove (); - } - + (*i)->mark_for_remove (); (*i)->drop_references (); - + cerr << "source was not used by any playlist\n"; - } } return 0; @@ -2646,12 +2789,12 @@ int Session::remove_last_capture () { list > r; - + boost::shared_ptr dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { list >& l = (*i)->last_capture_regions(); - + if (!l.empty()) { r.insert (r.end(), l.begin(), l.end()); l.clear (); @@ -2681,7 +2824,7 @@ Session::add_source (boost::shared_ptr source) entry.first = source->id(); entry.second = source; - + { Glib::Mutex::Lock lm (source_lock); result = sources.insert (entry); @@ -2691,6 +2834,14 @@ Session::add_source (boost::shared_ptr source) source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr (source))); set_dirty(); } + + boost::shared_ptr afs; + + if ((afs = boost::dynamic_pointer_cast(source)) != 0) { + if (Config->get_auto_analyse_audio()) { + Analyser::queue_source_for_analysis (source, false); + } + } } void @@ -2701,22 +2852,22 @@ Session::remove_source (boost::weak_ptr src) if (!source) { return; - } + } - { + { Glib::Mutex::Lock lm (source_lock); if ((i = sources.find (source->id())) != sources.end()) { sources.erase (i); - } + } } - + if (!_state_of_the_state & InCleanup) { - + /* save state so we don't end up with a session file referring to non-existent sources. */ - + save_state (_current_snapshot_name); } } @@ -2732,8 +2883,6 @@ Session::source_by_id (const PBD::ID& id) source = i->second; } - /* XXX search MIDI or other searches here */ - return source; } @@ -2749,8 +2898,8 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn) if (afs && afs->path() == path && chn == afs->channel()) { return afs; - } - + } + } return boost::shared_ptr(); } @@ -2773,14 +2922,14 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, /* note: we know (or assume) the old path is already valid */ if (destructive) { - + /* destructive file sources have a name of the form: /path/to/Tnnnn-NAME(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + /* find last slash */ string dir; @@ -2807,16 +2956,16 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, path += '-'; path += new_legalized; path += ".wav"; /* XXX gag me with a spoon */ - + } else { - + /* non-destructive file sources have a name of the form: /path/to/NAME-nnnnn(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + string dir; string suffix; string::size_type slash; @@ -2838,7 +2987,7 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, } suffix = path.substr (dash+1); - + // Suffix is now everything after the dash. Now we need to eliminate // the nnnnn part, which is done by either finding a '%' or a '.' @@ -2941,7 +3090,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool if (sys::exists(buf)) { existing++; - } + } } @@ -2968,7 +3117,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool spath += '/'; string::size_type pos = foo.find_last_of ('/'); - + if (pos == string::npos) { spath += foo; } else { @@ -2997,14 +3146,14 @@ Session::change_midi_path_by_name (string path, string oldname, string newname, /* note: we know (or assume) the old path is already valid */ if (destructive) { - + /* destructive file sources have a name of the form: /path/to/Tnnnn-NAME(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + /* find last slash */ string dir; @@ -3031,16 +3180,16 @@ Session::change_midi_path_by_name (string path, string oldname, string newname, path += '-'; path += new_legalized; path += ".mid"; /* XXX gag me with a spoon */ - + } else { - + /* non-destructive file sources have a name of the form: /path/to/NAME-nnnnn(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + string dir; string suffix; string::size_type slash; @@ -3062,7 +3211,7 @@ Session::change_midi_path_by_name (string path, string oldname, string newname, } suffix = path.substr (dash+1); - + // Suffix is now everything after the dash. Now we need to eliminate // the nnnnn part, which is done by either finding a '%' or a '.' @@ -3125,7 +3274,7 @@ Session::midi_path_from_name (string name) for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { SessionDirectory sdir((*i).path); - + sys::path p = sdir.midi_path(); p /= legalized; @@ -3136,7 +3285,7 @@ Session::midi_path_from_name (string name) if (sys::exists (buf)) { existing++; - } + } } if (existing == 0) { @@ -3161,7 +3310,7 @@ Session::midi_path_from_name (string name) spath += '/'; string::size_type pos = foo.find_last_of ('/'); - + if (pos == string::npos) { spath += foo; } else { @@ -3175,7 +3324,7 @@ boost::shared_ptr Session::create_midi_source_for_session (MidiDiskstream& ds) { string mpath = midi_path_from_name (ds.name()); - + return boost::dynamic_pointer_cast (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate())); } @@ -3201,13 +3350,29 @@ Session::playlist_by_name (string name) } void -Session::add_playlist (boost::shared_ptr playlist) +Session::unassigned_playlists (std::list > & list) +{ + Glib::Mutex::Lock lm (playlist_lock); + for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { + if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) { + list.push_back (*i); + } + } + for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) { + if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) { + list.push_back (*i); + } + } +} + +void +Session::add_playlist (boost::shared_ptr playlist, bool unused) { if (playlist->hidden()) { return; } - { + { Glib::Mutex::Lock lm (playlist_lock); if (find (playlists.begin(), playlists.end(), playlist) == playlists.end()) { playlists.insert (playlists.begin(), playlist); @@ -3216,6 +3381,10 @@ Session::add_playlist (boost::shared_ptr playlist) } } + if (unused) { + playlist->release(); + } + set_dirty(); PlaylistAdded (playlist); /* EMIT SIGNAL */ @@ -3224,7 +3393,7 @@ Session::add_playlist (boost::shared_ptr playlist) void Session::get_playlists (vector >& s) { - { + { Glib::Mutex::Lock lm (playlist_lock); for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { s.push_back (*i); @@ -3251,22 +3420,22 @@ Session::track_playlist (bool inuse, boost::weak_ptr wpl) return; } - { + { Glib::Mutex::Lock lm (playlist_lock); if (!inuse) { unused_playlists.insert (pl); - + if ((x = playlists.find (pl)) != playlists.end()) { playlists.erase (x); } - + } else { playlists.insert (pl); - + if ((x = unused_playlists.find (pl)) != unused_playlists.end()) { unused_playlists.erase (x); } @@ -3287,7 +3456,7 @@ Session::remove_playlist (boost::weak_ptr weak_playlist) return; } - { + { Glib::Mutex::Lock lm (playlist_lock); PlaylistList::iterator i; @@ -3301,7 +3470,7 @@ Session::remove_playlist (boost::weak_ptr weak_playlist) if (i != unused_playlists.end()) { unused_playlists.erase (i); } - + } set_dirty(); @@ -3309,7 +3478,7 @@ Session::remove_playlist (boost::weak_ptr weak_playlist) PlaylistRemoved (playlist); /* EMIT SIGNAL */ } -void +void Session::set_audition (boost::shared_ptr r) { pending_audition_region = r; @@ -3366,7 +3535,7 @@ Session::remove_empty_sounds () vector audio_filenames; get_files_in_directory (_session_dir->sound_path(), audio_filenames); - + Glib::Mutex::Lock lm (source_lock); TapeFileMatcher tape_file_matcher; @@ -3379,7 +3548,7 @@ Session::remove_empty_sounds () sys::path audio_file_path (_session_dir->sound_path()); audio_file_path /= *i; - + if (AudioFileSource::is_empty (*this, audio_file_path.to_string())) { try @@ -3390,7 +3559,7 @@ Session::remove_empty_sounds () } catch (const sys::filesystem_error& err) { - error << err.what() << endmsg; + error << err.what() << endmsg; } } } @@ -3411,7 +3580,7 @@ void Session::set_all_solo (bool yn) { shared_ptr r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->is_hidden()) { (*i)->set_solo (yn, this); @@ -3420,12 +3589,12 @@ Session::set_all_solo (bool yn) set_dirty(); } - + void Session::set_all_mute (bool yn) { shared_ptr r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->is_hidden()) { (*i)->set_mute (yn, this); @@ -3434,7 +3603,7 @@ Session::set_all_mute (bool yn) set_dirty(); } - + uint32_t Session::n_diskstreams () const { @@ -3460,7 +3629,7 @@ Session::graph_reordered () if (_state_of_the_state & InitialConnecting) { return; } - + /* every track/bus asked for this to be handled but it was deferred because we were connecting. do it now. */ @@ -3469,10 +3638,10 @@ Session::graph_reordered () resort_routes (); - /* force all diskstreams to update their capture offset values to + /* force all diskstreams to update their capture offset values to reflect any changes in latencies within the graph. */ - + boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { @@ -3496,7 +3665,7 @@ void Session::record_enable_change_all (bool yn) { shared_ptr r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { Track* at; @@ -3504,7 +3673,7 @@ Session::record_enable_change_all (bool yn) at->set_record_enable (yn, this); } } - + /* since we don't keep rec-enable state, don't mark session dirty */ } @@ -3537,7 +3706,7 @@ Session::remove_processor (Processor* processor) Send* send; PortInsert* port_insert; PluginInsert* plugin_insert; - + if ((port_insert = dynamic_cast (processor)) != 0) { list::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert); if (x != _port_inserts.end()) { @@ -3578,7 +3747,7 @@ Session::available_capture_duration () sample_bytes_on_disk = 2.0; break; - default: + default: /* impossible, but keep some gcc versions happy */ fatal << string_compose (_("programming error: %1"), X_("illegal native file data format")) @@ -3591,7 +3760,7 @@ Session::available_capture_duration () if (_total_free_4k_blocks * scale > (double) max_frames) { return max_frames; } - + return (nframes_t) floor (_total_free_4k_blocks * scale); } @@ -3602,7 +3771,7 @@ Session::add_bundle (shared_ptr bundle) Glib::Mutex::Lock guard (bundle_lock); _bundles.push_back (bundle); } - + BundleAdded (bundle); /* EMIT SIGNAL */ set_dirty(); @@ -3616,7 +3785,7 @@ Session::remove_bundle (shared_ptr bundle) { Glib::Mutex::Lock guard (bundle_lock); BundleList::iterator i = find (_bundles.begin(), _bundles.end(), bundle); - + if (i != _bundles.end()) { _bundles.erase (i); removed = true; @@ -3644,39 +3813,19 @@ Session::bundle_by_name (string name) const return boost::shared_ptr (); } -boost::shared_ptr -Session::bundle_by_ports (std::vector const & wanted_ports) const +void +Session::tempo_map_changed (Change ignored) { - Glib::Mutex::Lock lm (bundle_lock); - - for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) { - if ((*i)->nchannels() != wanted_ports.size()) { - continue; - } - - bool match = true; - for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { - Bundle::PortList const p = (*i)->channel_ports (j); - if (p.empty() || p[0] != wanted_ports[j]) { - /* not this bundle */ - match = false; - break; - } - } + clear_clicks (); - if (match) { - /* matched bundle */ - return *i; - } + for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { + (*i)->update_after_tempo_map_change (); } - return boost::shared_ptr (); -} + for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) { + (*i)->update_after_tempo_map_change (); + } -void -Session::tempo_map_changed (Change ignored) -{ - clear_clicks (); set_dirty (); } @@ -3698,7 +3847,7 @@ Session::ensure_buffers (ChanCount howmany) _scratch_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); } @@ -3712,10 +3861,10 @@ Session::next_insert_id () if (!insert_bitset[n]) { insert_bitset[n] = true; return n; - + } } - + /* none available, so resize and try again */ insert_bitset.resize (insert_bitset.size() + 16, false); @@ -3732,10 +3881,10 @@ Session::next_send_id () if (!send_bitset[n]) { send_bitset[n] = true; return n; - + } } - + /* none available, so resize and try again */ send_bitset.resize (send_bitset.size() + 16, false); @@ -3783,7 +3932,7 @@ Session::named_selection_by_name (string name) void Session::add_named_selection (NamedSelection* named_selection) { - { + { Glib::Mutex::Lock lm (named_selection_lock); named_selections.insert (named_selections.begin(), named_selection); } @@ -3802,7 +3951,7 @@ Session::remove_named_selection (NamedSelection* named_selection) { bool removed = false; - { + { Glib::Mutex::Lock lm (named_selection_lock); NamedSelectionList::iterator i = find (named_selections.begin(), named_selections.end(), named_selection); @@ -3834,13 +3983,13 @@ bool Session::route_name_unique (string n) const { shared_ptr r = routes.reader (); - + for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->name() == n) { return false; } } - + return true; } @@ -3868,7 +4017,7 @@ Session::allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, b } _pan_automation_buffer = new pan_t*[howmany]; - + for (uint32_t i = 0; i < howmany; ++i) { _pan_automation_buffer[i] = new pan_t[nframes]; } @@ -3896,11 +4045,11 @@ Session::freeze (InterThreadInfo& itt) return 0; } -int -Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len, - bool overwrite, vector >& srcs, InterThreadInfo& itt) +boost::shared_ptr +Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end, + bool overwrite, vector >& srcs, InterThreadInfo& itt) { - int ret = -1; + boost::shared_ptr result; boost::shared_ptr playlist; boost::shared_ptr fsource; uint32_t x; @@ -3912,14 +4061,21 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le BufferSet buffers; SessionDirectory sdir(get_best_session_directory_for_new_source ()); const string sound_dir = sdir.sound_path().to_string(); + nframes_t len = end - start; + + if (end <= start) { + error << string_compose (_("Cannot write a range where end <= start (e.g. %1 <= %2)"), + end, start) << endmsg; + return result; + } // any bigger than this seems to cause stack overflows in called functions const nframes_t chunk_size = (128 * 1024)/4; g_atomic_int_set (&processing_prohibited, 1); - + /* call tree *MUST* hold route_lock */ - + if ((playlist = track.diskstream()->playlist()) == 0) { goto out; } @@ -3938,17 +4094,17 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le break; } } - + if (x == 99999) { error << string_compose (_("too many bounced versions of playlist \"%1\""), playlist->name()) << endmsg; goto out; } - + try { fsource = boost::dynamic_pointer_cast ( SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate())); } - + catch (failed_constructor& err) { error << string_compose (_("cannot create new audio file \"%1\" for %2"), buf, track.name()) << endmsg; goto out; @@ -3958,7 +4114,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le } /* XXX need to flush all redirects */ - + position = start; to_do = len; @@ -3971,11 +4127,11 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le if (afs) afs->prepare_for_peakfile_writes (); } - + while (to_do && !itt.cancel) { - + this_chunk = min (to_do, chunk_size); - + if (track.export_stuff (buffers, start, this_chunk)) { goto out; } @@ -3983,61 +4139,59 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le uint32_t n = 0; for (vector >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { boost::shared_ptr afs = boost::dynamic_pointer_cast(*src); - + if (afs) { if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) { goto out; } } } - + start += this_chunk; to_do -= this_chunk; - + itt.progress = (float) (1.0 - ((double) to_do / len)); } if (!itt.cancel) { - + time_t now; struct tm* xnow; time (&now); xnow = localtime (&now); - + for (vector >::iterator src=srcs.begin(); src != srcs.end(); ++src) { boost::shared_ptr afs = boost::dynamic_pointer_cast(*src); - + if (afs) { afs->update_header (position, *xnow, now); afs->flush_header (); } } - - /* construct a region to represent the bounced material */ - boost::shared_ptr aregion = RegionFactory::create (srcs, 0, srcs.front()->length(), - region_name_from_path (srcs.front()->name(), true)); + /* construct a region to represent the bounced material */ - ret = 0; + result = RegionFactory::create (srcs, 0, srcs.front()->length(), + region_name_from_path (srcs.front()->name(), true)); } - + out: - if (ret) { + if (!result) { for (vector >::iterator src = srcs.begin(); src != srcs.end(); ++src) { boost::shared_ptr afs = boost::dynamic_pointer_cast(*src); if (afs) { afs->mark_for_remove (); } - + (*src)->drop_references (); } } else { for (vector >::iterator src = srcs.begin(); src != srcs.end(); ++src) { boost::shared_ptr afs = boost::dynamic_pointer_cast(*src); - + if (afs) afs->done_with_peakfile_writes (); } @@ -4045,7 +4199,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le g_atomic_int_set (&processing_prohibited, 0); - return ret; + return result; } BufferSet& @@ -4055,11 +4209,11 @@ Session::get_silent_buffers (ChanCount count) _silent_buffers->set_count(count); for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - for (size_t i=0; i < count.get(*t); ++i) { + for (size_t i= 0; i < count.get(*t); ++i) { _silent_buffers->get(*t, i).clear(); } } - + return *_silent_buffers; } @@ -4079,7 +4233,7 @@ Session::get_mix_buffers (ChanCount count) return *_mix_buffers; } -uint32_t +uint32_t Session::ntracks () const { uint32_t n = 0; @@ -4094,7 +4248,7 @@ Session::ntracks () const return n; } -uint32_t +uint32_t Session::nbusses () const { uint32_t n = 0; @@ -4122,7 +4276,7 @@ Session::compute_initial_length () } void -Session::sync_order_keys () +Session::sync_order_keys (const char* base) { if (!Config->get_sync_all_route_ordering()) { /* leave order keys as they are */ @@ -4132,10 +4286,10 @@ Session::sync_order_keys () boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->sync_order_keys (); + (*i)->sync_order_keys (base); } - Route::SyncOrderKeys (); // EMIT SIGNAL + Route::SyncOrderKeys (base); // EMIT SIGNAL } void @@ -4146,3 +4300,4 @@ Session::foreach_bundle (sigc::slot > sl) sl (*i); } } +