X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fardour%2Fsession.cc;h=c2141e62e630f39a64a39c4ba18220c4a069aa39;hb=b2c5b3b518479a35ba87764d1150b7bdac073cdc;hp=0a58a7da25834edf7f1dffc4333e3539f1fe86f4;hpb=a02c4dadf19a4c131f86b3c7d66eccbeb63716e0;p=ardour.git diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 0a58a7da25..c2141e62e6 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -276,16 +276,22 @@ Session::Session (AudioEngine &eng, string mix_template) : _engine (eng), + mmc (0), _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), pending_events (2048), + state_tree (0), + _send_smpte_update (false), + midi_thread (pthread_t (0)), midi_requests (128), // the size of this should match the midi request pool size diskstreams (new DiskstreamList), routes (new RouteList), auditioner ((Auditioner*) 0), _total_free_4k_blocks (0), _click_io ((IO*) 0), + click_data (0), + click_emphasis_data (0), main_outs (0) { bool new_session; @@ -294,7 +300,7 @@ Session::Session (AudioEngine &eng, throw failed_constructor(); } - cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl; + info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl; n_physical_audio_outputs = _engine.n_physical_audio_outputs(); n_physical_audio_inputs = _engine.n_physical_audio_inputs(); @@ -340,14 +346,22 @@ Session::Session (AudioEngine &eng, nframes_t initial_length) : _engine (eng), + mmc (0), _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), pending_events (2048), + state_tree (0), + _send_smpte_update (false), + midi_thread (pthread_t (0)), midi_requests (16), diskstreams (new DiskstreamList), routes (new RouteList), + auditioner ((Auditioner *) 0), _total_free_4k_blocks (0), + _click_io ((IO *) 0), + click_data (0), + click_emphasis_data (0), main_outs (0) { @@ -357,7 +371,7 @@ Session::Session (AudioEngine &eng, throw failed_constructor(); } - cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl; + info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl; n_physical_audio_outputs = _engine.n_physical_audio_outputs(); n_physical_audio_inputs = _engine.n_physical_audio_inputs(); @@ -455,19 +469,16 @@ Session::destroy () _history.clear (); /* clear state tree so that no references to objects are held any more */ - - if (state_tree) { - delete state_tree; - } + delete state_tree; terminate_butler_thread (); terminate_midi_thread (); - if (click_data && click_data != default_click) { + if (click_data != default_click) { delete [] click_data; } - if (click_emphasis_data && click_emphasis_data != default_click_emphasis) { + if (click_emphasis_data != default_click_emphasis) { delete [] click_emphasis_data; } @@ -635,19 +646,9 @@ Session::destroy () i = tmp; } - if (butler_mixdown_buffer) { - delete [] butler_mixdown_buffer; - } - - if (butler_gain_buffer) { - delete [] butler_gain_buffer; - } - Crossfade::set_buffer_size (0); - if (mmc) { - delete mmc; - } + delete mmc; } void @@ -671,8 +672,6 @@ Session::set_worst_io_latencies () void Session::when_engine_running () { - string first_physical_output; - /* we don't want to run execute this again */ BootMessage (_("Set block size and sample rate")); @@ -719,17 +718,21 @@ Session::when_engine_running () } else { - /* default state for Click */ - - first_physical_output = _engine.get_nth_physical_audio_output (0); + /* default state for Click: dual-mono to first 2 physical outputs */ - if (first_physical_output.length()) { - if (_click_io->add_output_port (first_physical_output, this)) { - // relax, even though its an error - } else { - _clicking = Config->get_clicking (); + for (int physport = 0; physport < 2; ++physport) { + string physical_output = _engine.get_nth_physical_audio_output (physport); + + if (physical_output.length()) { + if (_click_io->add_output_port (physical_output, this)) { + // relax, even though its an error + } } } + + if (_click_io->n_outputs() > 0) { + _clicking = Config->get_clicking (); + } } } @@ -1105,9 +1108,9 @@ Session::auto_loop_changed (Location* location) if (transport_rolling() && play_loop) { - //if (_transport_frame < location->start() || _transport_frame > location->end()) { + // if (_transport_frame > location->end()) { - if (_transport_frame > location->end()) { + if (_transport_frame < location->start() || _transport_frame > location->end()) { // relocate to beginning of loop clear_events (Event::LocateRoll); @@ -1378,6 +1381,10 @@ Session::audible_frame () const nframes_t offset; nframes_t tf; + if (_transport_speed == 0.0f && non_realtime_work_pending()) { + return last_stop_frame; + } + /* the first of these two possible settings for "offset" mean that the audible frame is stationary until audio emerges from the latency compensation @@ -1406,57 +1413,44 @@ Session::audible_frame () const } else { tf = _transport_frame; } - - if (_transport_speed == 0) { - ret = tf; - goto block_retrograde; - } - - if (tf < offset) { - ret = 0; - goto block_retrograde; - } - + ret = tf; if (!non_realtime_work_pending()) { /* MOVING */ - /* take latency into account */ - - if (_transport_speed > 0.0) { - /* forwards */ - ret -= offset; - } else { - /* backwards */ - ret += offset; - } + /* check to see if we have passed the first guaranteed + audible frame past our last stopping position. if not, + the return that last stopping point because in terms + of audible frames, we have not moved yet. + */ - } + if (_transport_speed > 0.0f) { - /* do not allow retrograde motion near startup or a direction change - caused by latency correction. we detect this by the asking if the present - and previously-noted transport speed (and thus direction) are the same. - */ + if (!play_loop || !have_looped) { + if (tf < last_stop_frame + offset) { + return last_stop_frame; + + } + } + - block_retrograde: - if ((af_last_transport_speed >= 0.0) == (_transport_speed >= 0.0)) { + /* forwards */ + ret -= offset; - if (_transport_speed > 0.0) { - if (ret < af_last_frame) { - ret = af_last_frame; - } + } else if (_transport_speed < 0.0f) { + + /* XXX wot? no backward looping? */ - } else if (_transport_speed < 0.0) { - if (ret > af_last_frame) { - ret = af_last_frame; + if (tf > last_stop_frame - offset) { + return last_stop_frame; + } else { + /* backwards */ + ret += offset; } - } - } - - af_last_frame = ret; - af_last_transport_speed = _transport_speed; + } + } return ret; } @@ -1874,7 +1868,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod 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; + error << pfe.what() << endmsg; if (track) { /* we need to get rid of this, since the track failed to be created */ @@ -1975,20 +1969,20 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ << endmsg; goto failure; } - + /* for (uint32_t x = 0; n_physical_audio_inputs && x < bus->n_inputs(); ++x) { - + port = ""; - + if (Config->get_input_auto_connect() & AutoConnectPhysical) { - port = physinputs[((n+x)%n_physical_audio_inputs)]; + port = physinputs[((n+x)%n_physical_audio_inputs)]; } if (port.length() && bus->connect_input (bus->input (x), port, this)) { break; } } - + */ for (uint32_t x = 0; n_physical_audio_outputs && x < bus->n_outputs(); ++x) { port = ""; @@ -2019,7 +2013,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ } 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; + error << pfe.what() << endmsg; goto failure; } @@ -2036,6 +2030,114 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ } +Session::RouteList +Session::new_route_from_template (uint32_t how_many, const std::string& template_path) +{ + char name[32]; + RouteList ret; + uint32_t control_id; + XMLTree tree; + uint32_t number = 1; + + if (!tree.read (template_path.c_str())) { + return ret; + } + + XMLNode* node = tree.root(); + + control_id = ntracks() + nbusses() + 1; + + while (how_many) { + + XMLNode node_copy (*node); // make a copy so we can change the name if we need to + + std::string node_name = IO::name_from_state (*node_copy.children().front()); + + /* generate a new name by adding a number to the end of the template name */ + + do { + snprintf (name, sizeof (name), "%s %" PRIu32, node_name.c_str(), number); + + number++; + + if (route_by_name (name) == 0) { + break; + } + + } while (number < UINT_MAX); + + if (number == UINT_MAX) { + fatal << _("Session: UINT_MAX routes? impossible!") << endmsg; + /*NOTREACHED*/ + } + + IO::set_name_in_state (*node_copy.children().front(), name); + + Track::zero_diskstream_id_in_xml (node_copy); + + try { + shared_ptr route (XMLRouteFactory (node_copy)); + + if (route == 0) { + error << _("Session: cannot create track/bus from template description") << endmsg; + goto out; + } + + if (boost::dynamic_pointer_cast(route)) { + /* force input/output change signals so that the new diskstream + picks up the configuration of the route. During session + loading this normally happens in a different way. + */ + route->input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); + route->output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); + } + + route->set_remote_control_id (control_id); + ++control_id; + + ret.push_back (route); + } + + catch (failed_constructor &err) { + error << _("Session: could not create new route from template") << endmsg; + goto out; + } + + catch (AudioEngine::PortRegistrationFailure& pfe) { + error << pfe.what() << endmsg; + goto out; + } + + --how_many; + } + + out: + if (!ret.empty()) { + add_routes (ret, true); + } + + return ret; +} + +boost::shared_ptr +Session::new_video_track (string name) +{ + uint32_t control_id = ntracks() + nbusses() + 1; + shared_ptr new_route ( + new Route ( *this, name, -1, -1, -1, -1, Route::Flag(0), ARDOUR::DataType::NIL)); + new_route->set_remote_control_id (control_id); + + RouteList rl; + rl.push_back (new_route); + { + RCUWriter writer (routes); + shared_ptr r = writer.get_copy (); + r->insert (r->end(), rl.begin(), rl.end()); + resort_routes_using (r); + } + return new_route; +} + void Session::add_routes (RouteList& new_routes, bool save) { @@ -2229,7 +2331,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr wpr) /* don't mess with busses */ - if (dynamic_cast((*i).get()) == 0) { + if (boost::dynamic_pointer_cast(*i) == 0) { continue; } @@ -2237,7 +2339,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr wpr) /* don't mess with tracks */ - if (dynamic_cast((*i).get()) != 0) { + if (boost::dynamic_pointer_cast(*i) != 0) { continue; } } @@ -2311,8 +2413,6 @@ Session::update_route_solo_state () bool is_track = false; bool signal = false; - /* caller must hold RouteLock */ - /* this is where we actually implement solo by changing the solo mute setting of each track. */ @@ -2322,7 +2422,7 @@ Session::update_route_solo_state () for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->soloed()) { mute = true; - if (dynamic_cast((*i).get())) { + if (boost::dynamic_pointer_cast(*i)) { is_track = true; } break; @@ -2367,7 +2467,7 @@ Session::modify_solo_mute (bool is_track, bool mute) /* only alter track solo mute */ - if (dynamic_cast((*i).get())) { + if (boost::dynamic_pointer_cast(*i)) { if ((*i)->soloed()) { (*i)->set_solo_mute (!mute); } else { @@ -2378,8 +2478,8 @@ Session::modify_solo_mute (bool is_track, bool mute) } else { /* only alter bus solo mute */ - - if (!dynamic_cast((*i).get())) { + + if (!boost::dynamic_pointer_cast(*i)) { if ((*i)->soloed()) { @@ -2413,7 +2513,24 @@ Session::catch_up_on_solo () */ update_route_solo_state(); } - + +void +Session::catch_up_on_solo_mute_override () +{ + if (Config->get_solo_model() != InverseMute) { + return; + } + + /* this is called whenever the param solo-mute-override is + changed. + */ + shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + (*i)->catch_up_on_solo_mute_override (); + } +} + shared_ptr Session::route_by_name (string name) { @@ -3476,7 +3593,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)->hidden()) { (*i)->set_solo (yn, this); @@ -3985,7 +4102,7 @@ Session::freeze (InterThreadInfo& itt) boost::shared_ptr Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t end, - bool overwrite, vector >& srcs, InterThreadInfo& itt) + bool overwrite, vector >& srcs, InterThreadInfo& itt, bool enable_processing) { boost::shared_ptr result; boost::shared_ptr playlist; @@ -4009,7 +4126,9 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t en // 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); + // block all process callback handling + + block_processing (); /* call tree *MUST* hold route_lock */ @@ -4078,7 +4197,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t en this_chunk = min (to_do, chunk_size); - if (track.export_stuff (buffers, nchans, start, this_chunk)) { + if (track.export_stuff (buffers, nchans, start, this_chunk, enable_processing)) { goto out; } @@ -4144,7 +4263,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t en free (*i); } - g_atomic_int_set (&processing_prohibited, 0); + unblock_processing (); itt.done = true;