more loop/transport fixups; make visible PH track transport frame as an experiment...
[ardour.git] / libs / ardour / session.cc
index 0a58a7da25834edf7f1dffc4333e3539f1fe86f4..c2141e62e630f39a64a39c4ba18220c4a069aa39 100644 (file)
@@ -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> route (XMLRouteFactory (node_copy));
+           
+                       if (route == 0) {
+                               error << _("Session: cannot create track/bus from template description") << endmsg;
+                               goto out;
+                       }
+
+                       if (boost::dynamic_pointer_cast<Track>(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<Route>
+Session::new_video_track (string name)
+{
+       uint32_t control_id = ntracks() + nbusses() + 1;
+       shared_ptr<Route> 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<RouteList> writer (routes);
+               shared_ptr<RouteList> 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<Route> wpr)
                        
                        /* don't mess with busses */
                        
-                       if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*i) == 0) {
                                continue;
                        }
                        
@@ -2237,7 +2339,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
                        
                        /* don't mess with tracks */
                        
-                       if (dynamic_cast<AudioTrack*>((*i).get()) != 0) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*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<AudioTrack*>((*i).get())) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*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<AudioTrack*>((*i).get())) {
+                       if (boost::dynamic_pointer_cast<AudioTrack>(*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<AudioTrack*>((*i).get())) {
+                       
+                       if (!boost::dynamic_pointer_cast<AudioTrack>(*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<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               (*i)->catch_up_on_solo_mute_override ();
+       }
+}      
+
 shared_ptr<Route>
 Session::route_by_name (string name)
 {
@@ -3476,7 +3593,7 @@ void
 Session::set_all_solo (bool yn)
 {
        shared_ptr<RouteList> 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<Region>
 Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t end,     
-                              bool overwrite, vector<boost::shared_ptr<AudioSource> >& srcs, InterThreadInfo& itt)
+                              bool overwrite, vector<boost::shared_ptr<AudioSource> >& srcs, InterThreadInfo& itt, bool enable_processing)
 {
        boost::shared_ptr<Region> result;
        boost::shared_ptr<Playlist> 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;