many changes relating to session construction and audioengine interaction
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 10 Sep 2013 19:41:19 +0000 (15:41 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 10 Sep 2013 19:41:19 +0000 (15:41 -0400)
every session member is now initialized using C++ constructor syntax

session construction reordered to clarify the split(s) between work
where the engine is not relevant and work where is it is. this
split is still not 100% obvious, but is enormously clearer than
previously.

if engine/backend are not running as session is created, and the SR
of the sample rate is known, attempt to force backend to that value.

gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/engine_dialog.cc
gtk2_ardour/engine_dialog.h
libs/ardour/ardour/session.h
libs/ardour/port.cc
libs/ardour/session.cc
libs/ardour/session_state.cc

index d6c6863b147ac4429d04b1650ca8f99cc3ec544b..4992e0a14b5df87d860a407a940b1f1611fcdb0d 100644 (file)
@@ -268,7 +268,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        /* handle Audio/MIDI setup when session requires it */
 
-       ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this));
+       ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
 
        /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
 
@@ -4159,10 +4159,12 @@ ARDOUR_UI::launch_audio_midi_setup ()
 }
                                                
 int
-ARDOUR_UI::do_audio_midi_setup ()
+ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
 {
        launch_audio_midi_setup ();
 
+       _audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
+
        int r = _audio_midi_setup->run ();
 
        switch (r) {
index 77e81fd23a3135f0584e15137900afacd79dc028..fa8eb18f01a48f816150317b9dc0dbeda6b95947 100644 (file)
@@ -750,7 +750,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
 
         EngineControl* _audio_midi_setup;
         void launch_audio_midi_setup ();
-        int do_audio_midi_setup ();
+        int do_audio_midi_setup (uint32_t);
 };
 
 #endif /* __ardour_gui_h__ */
index b03dc9a304cc7d9a1bfc414ac5dbd21ea10298fb..b97a7133e69883dfcb5fcd5e7edfc05acc9b379c 100644 (file)
@@ -65,6 +65,7 @@ EngineControl::EngineControl ()
        , control_app_button (_("Launch Control App"))
        , basic_packer (9, 3)
        , ignore_changes (0)
+       , _desired_sample_rate (0)
 {
        build_notebook ();
 
@@ -340,6 +341,8 @@ EngineControl::device_changed ()
        ignore_changes++;
 
        /* sample rates */
+       
+       string desired;
 
        vector<float> sr = backend->available_sample_rates (device_name);
        for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
@@ -350,11 +353,17 @@ EngineControl::device_changed ()
                        snprintf (buf, sizeof (buf), "%.0f kHz", (*x)/1000.0);
                }
                s.push_back (buf);
+               if (*x == _desired_sample_rate) {
+                       desired = buf;
+               }
        }
 
        set_popdown_strings (sample_rate_combo, s);
-       sample_rate_combo.set_active_text (s.front());
-
+       if (desired.empty()) {
+               sample_rate_combo.set_active_text (s.front());
+       } else {
+               sample_rate_combo.set_active_text (desired);
+       }
 
        vector<uint32_t> bs = backend->available_buffer_sizes(device_name);
        s.clear ();
@@ -514,7 +523,9 @@ EngineControl::maybe_display_saved_state ()
 
        if (state) {
                ignore_changes++;
-               sample_rate_combo.set_active_text (state->sample_rate);
+               if (!_desired_sample_rate) {
+                       sample_rate_combo.set_active_text (state->sample_rate);
+               }
                buffer_size_combo.set_active_text (state->buffer_size);
                input_latency.set_value (state->input_latency);
                output_latency.set_value (state->output_latency);
@@ -843,3 +854,10 @@ EngineControl::manage_control_app_sensitivity ()
                control_app_button.set_sensitive (true);
        }
 }
+
+void
+EngineControl::set_desired_sample_rate (uint32_t sr)
+{
+       _desired_sample_rate = sr;
+       device_changed ();
+}
index cdeb18a2c721c0e82ae2dab97cc11732091425b9..a92d0629f29852dd420b63652c15c7660b15ec90 100644 (file)
 
 class EngineControl : public ArdourDialog {
   public:
-       EngineControl ();
-       ~EngineControl ();
-
-       static bool need_setup ();
-
-       XMLNode& get_state ();
-       void set_state (const XMLNode&);
-
+    EngineControl ();
+    ~EngineControl ();
+    
+    static bool need_setup ();
+    
+    XMLNode& get_state ();
+    void set_state (const XMLNode&);
+    
+    void set_desired_sample_rate (uint32_t);
+    
   private:
     Gtk::Notebook notebook;
 
@@ -153,6 +155,7 @@ class EngineControl : public ArdourDialog {
     void control_app_button_clicked ();
     void manage_control_app_sensitivity ();
     int push_state_to_backend (bool start);
+    uint32_t _desired_sample_rate;
 };
 
 #endif /* __gtk2_ardour_engine_dialog_h__ */
index 7ef7fde07ae9ee480d1b3a5ad7b7ae84fc97b80d..09bf75276d1f7854a2851d6fd0c904e47f24051c 100644 (file)
@@ -558,7 +558,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
         /** handlers should return 0 for "everything OK", and any other value for
         * "cannot setup audioengine".
         */
-        static PBD::Signal0<int> AudioEngineSetupRequired;
+        static PBD::Signal1<int,uint32_t> AudioEngineSetupRequired;
 
        /** handlers should return -1 for "stop cleanup",
            0 for "yes, delete this playlist",
@@ -1071,7 +1071,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        boost::scoped_ptr<SessionDirectory> _session_dir;
 
        void hookup_io ();
-       void when_engine_running ();
+        int when_engine_running ();
        void graph_reordered ();
 
        /** current snapshot name, without the .ardour suffix */
@@ -1137,8 +1137,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        void             auto_loop_changed (Location *);
        void             auto_loop_declick_range (Location *, framepos_t &, framepos_t &);
 
-       void first_stage_init (std::string path, std::string snapshot_name);
-       int  second_stage_init ();
+       void pre_engine_init (std::string path);
+       int  post_engine_init ();
        void remove_empty_sounds ();
 
        void setup_midi_control ();
@@ -1620,6 +1620,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
     /* persistent, non-track related MIDI ports */
     MidiPortManager* _midi_ports;
     MIDI::MachineControl* _mmc;
+
+    void setup_ltc ();
+    void setup_click ();
+    void setup_bundles ();
 };
 
 } // namespace ARDOUR
index 8fadad4fcc91f81e340b039da540db0278c6e5cc..e8629cbf14b2417d1d594a75df526449e070c272 100644 (file)
@@ -153,8 +153,10 @@ Port::connect (std::string const & other)
        }
 
        if (sends_output ()) {
+               DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
                r = port_engine.connect (our_name, other_name);
        } else {
+               DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
                r = port_engine.connect (other_name, our_name);
        }
 
@@ -420,6 +422,8 @@ Port::reconnect ()
 {
        /* caller must hold process lock; intended to be used only after reestablish() */
 
+       DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
+
        for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
                if (connect (*i)) {
                        return -1;
index 687469e5a577783732758153074f2ef268e30fb1..9934d5a095f38366f9f09909c0eebdb5645fad18 100644 (file)
@@ -107,7 +107,7 @@ using namespace PBD;
 
 bool Session::_disable_all_loaded_plugins = false;
 
-PBD::Signal0<int> Session::AudioEngineSetupRequired;
+PBD::Signal1<int,uint32_t> Session::AudioEngineSetupRequired;
 PBD::Signal1<void,std::string> Session::Dialog;
 PBD::Signal0<int> Session::AskAboutPendingState;
 PBD::Signal2<int, framecnt_t, framecnt_t> Session::AskAboutSampleRateMismatch;
@@ -132,106 +132,137 @@ Session::Session (AudioEngine &eng,
                   const string& snapshot_name,
                   BusProfile* bus_profile,
                   string mix_template)
-       : _engine (eng)
+       : playlists (new SessionPlaylists)
+       , _engine (eng)
+       , process_function (&Session::process_with_events)
+       , waiting_for_sync_offset (false)
+       , _base_frame_rate (0)
+       , _current_frame_rate (0)
+       , _nominal_frame_rate (0)
+       , transport_sub_state (0)
+       , _record_status (Disabled)
+       , _transport_frame (0)
+       , _session_range_location (0)
+       , _slave (0)
+       , _silent (false)
+       , _transport_speed (0)
+       , _default_transport_speed (1.0)
+       , _last_transport_speed (0)
        , _target_transport_speed (0.0)
+       , auto_play_legal (false)
+       , _last_slave_transport_frame (0)
+       , maximum_output_latency (0)
        , _requested_return_frame (-1)
+       , current_block_size (0)
+       , _worst_output_latency (0)
+       , _worst_input_latency (0)
+       , _worst_track_latency (0)
+       , _have_captured (false)
+       , _meter_hold (0)
+       , _meter_falloff (0)
+       , _non_soloed_outs_muted (false)
+       , _listen_cnt (0)
+       , _solo_isolated_cnt (0)
+       , _writable (false)
+       , _was_seamless (Config->get_seamless_loop ())
        , _under_nsm_control (false)
+       , delta_accumulator_cnt (0)
+       , average_slave_delta (1800) // !!! why 1800 ???
+       , average_dir (0)
+       , have_first_delta_accumulator (false)
+       , _slave_state (Stopped)
+       , post_export_sync (false)
+       , post_export_position (0)
+       , _exporting (false)
+       , _export_started (false)
+       , _export_rolling (false)
+       , _pre_export_mmc_enabled (false)
+       , _name (snapshot_name)
+       , _is_new (true)
+       , _send_qf_mtc (false)
+       , _pframes_since_last_mtc (0)
+       , session_midi_feedback (0)
+       , play_loop (false)
+       , loop_changing (false)
+       , last_loopend (0)
        , _session_dir (new SessionDirectory (fullpath))
+       , _current_snapshot_name (snapshot_name)          
        , state_tree (0)
+       , state_was_pending (false)
        , _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading))
+       , _last_roll_location (0)
+       , _last_roll_or_reversal_location (0)
+       , _last_record_location (0)
+       , pending_locate_roll (false)
+       , pending_locate_frame (0)
+       , pending_locate_flush (false)
+       , pending_abort (false)
+       , pending_auto_loop (false)
        , _butler (new Butler (*this))
        , _post_transport_work (0)
+       ,  cumulative_rf_motion (0)
+       , rf_scale (1.0)
+       , _locations (new Locations (*this))
+       , step_speed (0)
+       , outbound_mtc_timecode_frame (0)
+       , next_quarter_frame_to_send (-1)
+       , _frames_per_timecode_frame (0)
+       , _frames_per_hour (0)
+       , _timecode_frames_per_hour (0)
+       , last_timecode_valid (false)
+       , last_timecode_when (0)
        , _send_timecode_update (false)
+       , ltc_encoder (0)
        , ltc_enc_buf(0)
+       , ltc_buf_off (0)
+       , ltc_buf_len (0)
+       , ltc_speed (0)
+       , ltc_enc_byte (0)
+       , ltc_enc_pos (0)
+       , ltc_enc_cnt (0)
+       , ltc_enc_off (0)
+       , restarting (false)
+       , ltc_prev_cycle (0)
+       , ltc_timecode_offset (0)
+       , ltc_timecode_negative_offset (false)
+       , midi_control_ui (0)
+       , _tempo_map (0)
        , _all_route_group (new RouteGroup (*this, "all"))
        , routes (new RouteList)
+       , _adding_routes_in_progress (false)
+       , destructive_index (0)
+       , solo_update_disabled (false)
+       , default_fade_steepness (0)
+       , default_fade_msecs (0)
        , _total_free_4k_blocks (0)
        , _total_free_4k_blocks_uncertain (false)
+       , no_questions_about_missing_files (false)
+       , _playback_load (0)
+       , _capture_load (0)
        , _bundles (new BundleList)
        , _bundle_xml_node (0)
        , _current_trans (0)
+       , _clicking (false)
        , click_data (0)
        , click_emphasis_data (0)
-       , main_outs (0)
-       , _have_rec_enabled_track (false)
-       , _suspend_timecode_transmission (0)
-       , _non_soloed_outs_muted (false)
-       , _listen_cnt (0)
-       , _solo_isolated_cnt (0)
-       , _transport_speed (0)
-       , _default_transport_speed (1.0)
-       , _last_transport_speed (0)
-       , auto_play_legal (false)
-       , transport_sub_state (0)
-       , _transport_frame (0)
-       , _session_range_location (0)
-       , loop_changing (false)
-       , play_loop (false)
-       , have_looped (false)
-       , _last_roll_location (0)
-       , _last_roll_or_reversal_location (0)
-       , _last_record_location (0)
-       , pending_locate_frame (0)
-       , pending_locate_roll (false)
-       , pending_locate_flush (false)
-       , state_was_pending (false)
-       , outbound_mtc_timecode_frame (0)
-       , next_quarter_frame_to_send (-1)
-       , current_block_size (0)
-       , solo_update_disabled (false)
-       , _have_captured (false)
-       , _worst_output_latency (0)
-       , _worst_input_latency (0)
-       , _worst_track_latency (0)
-       , _was_seamless (Config->get_seamless_loop ())
-       , _slave (0)
-       , _send_qf_mtc (false)
-       , _pframes_since_last_mtc (0)
+       , click_length (0)
+       , click_emphasis_length (0)
+       , _clicks_cleared (0)
        , _play_range (false)
-       , _exporting (false)
-       , pending_abort (false)
-       , _adding_routes_in_progress (false)
-       , destructive_index (0)
+       , main_outs (0)
        , first_file_data_format_reset (true)
        , first_file_header_format_reset (true)
-       , post_export_sync (false)
-       , midi_control_ui (0)
+       , have_looped (false)
+       , _have_rec_enabled_track (false)
        , _step_editors (0)
-       , no_questions_about_missing_files (false)
+       , _suspend_timecode_transmission (0)
        ,  _speakers (new Speakers)
-       , _clicks_cleared (0)
        , ignore_route_processor_changes (false)
-       , _pre_export_mmc_enabled (false)
-       , _locations (new Locations (*this))
-       , ltc_encoder (0)
-       , playlists (new SessionPlaylists)
-       , _name (snapshot_name)
-       , _current_snapshot_name (snapshot_name)
-       , step_speed (0.0)
-       , click_length (0)
-       , click_emphasis_length (0)
-       , _clicking (false)
-       , process_function (&Session::process_with_events)
-       , last_timecode_when (0)
-       , last_timecode_valid (false)
-       , average_slave_delta (1800) // !!! why 1800 ???
-       , have_first_delta_accumulator (false)
-       , delta_accumulator_cnt (0)
-       , _slave_state (Stopped)
 {
-       if (_engine.current_backend() == 0 || _engine.setup_required()) {
-               boost::optional<int> r = AudioEngineSetupRequired ();
-               if (r.get_value_or (-1) != 0) {
-                       throw failed_constructor();
-               }
-       }
-
-       if (!_engine.connected()) {
-               throw failed_constructor();
-       }
-
-       first_stage_init (fullpath, snapshot_name);
+       uint32_t sr = 0;
 
+       pre_engine_init (fullpath);
+       
        if (_is_new) {
                if (create (mix_template, bus_profile)) {
                        destroy ();
@@ -241,14 +272,44 @@ Session::Session (AudioEngine &eng,
                if (load_state (_current_snapshot_name)) {
                        throw failed_constructor ();
                }
+       
+               /* try to get sample rate from XML state so that we
+                * can influence the SR if we set up the audio
+                * engine.
+                */
+
+               if (state_tree) {
+                       const XMLProperty* prop;
+                       if ((prop = state_tree->root()->property (X_("sample-rate"))) != 0) {           
+                               sr = atoi (prop->value());
+                       }
+               }
+       }
+       
+       if (_engine.current_backend() == 0 || _engine.setup_required()) {
+               boost::optional<int> r = AudioEngineSetupRequired (sr);
+               if (r.get_value_or (-1) != 0) {
+                       destroy ();
+                       throw failed_constructor();
+               }
        }
 
-       if (second_stage_init ()) {
+       /* at this point the engine should be connected (i.e. interacting
+          with a backend device (or psuedo-device) and available to us
+          for determinining sample rates and other settings.
+       */
+
+       if (!_engine.connected()) {
+               destroy ();
+               throw failed_constructor();
+       }
+
+       if (post_engine_init ()) {
                destroy ();
                throw failed_constructor ();
        }
 
-       store_recent_sessions(_name, _path);
+       store_recent_sessions (_name, _path);
 
        bool was_dirty = dirty();
 
@@ -397,135 +458,103 @@ Session::destroy ()
 }
 
 void
-Session::when_engine_running ()
+Session::setup_ltc ()
 {
-       string first_physical_output;
-
-       BootMessage (_("Set block size and sample rate"));
-
-       set_block_size (_engine.samples_per_cycle());
-       set_frame_rate (_engine.sample_rate());
-
-       BootMessage (_("Using configuration"));
-
-       boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
-       boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
-
-       Config->map_parameters (ff);
-       config.map_parameters (ft);
-
-       /* every time we reconnect, recompute worst case output latencies */
-
-       _engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
-
-       if (synced_to_jack()) {
-               _engine.transport_stop ();
+       XMLNode* child = 0;
+       
+       _ltc_input.reset (new IO (*this, _("LTC In"), IO::Input));
+       _ltc_output.reset (new IO (*this, _("LTC Out"), IO::Output));
+       
+       if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-In")) != 0) {
+               _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
+       } else {
+               {
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       _ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
+               }
+               reconnect_ltc_input ();
        }
-
-       if (config.get_jack_time_master()) {
-               _engine.transport_locate (_transport_frame);
+       
+       if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) {
+               _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
+       } else {
+               {
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       _ltc_output->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
+               }
+               reconnect_ltc_output ();
        }
+       
+       /* fix up names of LTC ports because we don't want the normal
+        * IO style of NAME/TYPE-{in,out}N
+        */
+       
+       _ltc_input->nth (0)->set_name (_("LTC-in"));
+       _ltc_output->nth (0)->set_name (_("LTC-out"));
+}
 
-       _clicking = false;
+void
+Session::setup_click ()
+{
+       XMLNode* child = 0;
 
-       try {
-               XMLNode* child = 0;
+       _clicking = false;
+       _click_io.reset (new ClickIO (*this, "click"));
+       _click_gain.reset (new Amp (*this));
+       _click_gain->activate ();
+       
+       if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
                
-               _ltc_input.reset (new IO (*this, _("LTC In"), IO::Input));
-               _ltc_output.reset (new IO (*this, _("LTC Out"), IO::Output));
+               /* existing state for Click */
+               int c = 0;
 
-               if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-In")) != 0) {
-                       _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
+               if (Stateful::loading_state_version < 3000) {
+                       c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
                } else {
-                       {
-                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                               _ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
-                       }
-                       reconnect_ltc_input ();
-               }
-
-               if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) {
-                       _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
-               } else {
-                       {
-                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                               _ltc_output->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
-                       }
-                       reconnect_ltc_output ();
-               }
-                                               
-               /* fix up names of LTC ports because we don't want the normal
-                * IO style of NAME/TYPE-{in,out}N
-                */
-               
-               _ltc_input->nth (0)->set_name (_("LTC-in"));
-               _ltc_output->nth (0)->set_name (_("LTC-out"));
-
-               _click_io.reset (new ClickIO (*this, "click"));
-               _click_gain.reset (new Amp (*this));
-               _click_gain->activate ();
-
-               if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
-
-                       /* existing state for Click */
-                       int c = 0;
-
-                       if (Stateful::loading_state_version < 3000) {
-                               c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
-                       } else {
-                               const XMLNodeList& children (child->children());
-                               XMLNodeList::const_iterator i = children.begin();
-                               if ((c = _click_io->set_state (**i, Stateful::loading_state_version)) == 0) {
-                                       ++i;
-                                       if (i != children.end()) {
-                                               c = _click_gain->set_state (**i, Stateful::loading_state_version);
-                                       }
+                       const XMLNodeList& children (child->children());
+                       XMLNodeList::const_iterator i = children.begin();
+                       if ((c = _click_io->set_state (**i, Stateful::loading_state_version)) == 0) {
+                               ++i;
+                               if (i != children.end()) {
+                                       c = _click_gain->set_state (**i, Stateful::loading_state_version);
                                }
                        }
+               }
                        
-                       if (c == 0) {
-                               _clicking = Config->get_clicking ();
+               if (c == 0) {
+                       _clicking = Config->get_clicking ();
 
-                       } else {
+               } else {
 
-                               error << _("could not setup Click I/O") << endmsg;
-                               _clicking = false;
-                       }
+                       error << _("could not setup Click I/O") << endmsg;
+                       _clicking = false;
+               }
 
 
-               } else {
+       } else {
 
-                       /* default state for Click: dual-mono to first 2 physical outputs */
+               /* default state for Click: dual-mono to first 2 physical outputs */
 
-                       vector<string> outs;
-                       _engine.get_physical_outputs (DataType::AUDIO, outs);
+               vector<string> outs;
+               _engine.get_physical_outputs (DataType::AUDIO, outs);
 
-                       for (uint32_t physport = 0; physport < 2; ++physport) {
-                               if (outs.size() > physport) {
-                                       if (_click_io->add_port (outs[physport], this)) {
-                                               // relax, even though its an error
-                                       }
+               for (uint32_t physport = 0; physport < 2; ++physport) {
+                       if (outs.size() > physport) {
+                               if (_click_io->add_port (outs[physport], this)) {
+                                       // relax, even though its an error
                                }
                        }
-
-                       if (_click_io->n_ports () > ChanCount::ZERO) {
-                               _clicking = Config->get_clicking ();
-                       }
                }
-       }
 
-       catch (failed_constructor& err) {
-               error << _("cannot setup Click I/O") << endmsg;
-       }
-
-       BootMessage (_("Compute I/O Latencies"));
-
-       if (_clicking) {
-               // XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO?
+               if (_click_io->n_ports () > ChanCount::ZERO) {
+                       _clicking = Config->get_clicking ();
+               }
        }
+}
 
-       BootMessage (_("Set up standard connections"));
-
+void
+Session::setup_bundles ()
+{
        vector<string> inputs[DataType::num_types];
        vector<string> outputs[DataType::num_types];
        for (uint32_t i = 0; i < DataType::num_types; ++i) {
@@ -624,6 +653,37 @@ Session::when_engine_running ()
                add_bundle (c);
        }
 
+}
+
+int
+Session::when_engine_running ()
+{
+       /* every time we reconnect, recompute worst case output latencies */
+
+       _engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
+
+       if (synced_to_jack()) {
+               _engine.transport_stop ();
+       }
+
+       if (config.get_jack_time_master()) {
+               _engine.transport_locate (_transport_frame);
+       }
+
+
+       try {
+               BootMessage (_("Set up LTC"));
+               setup_ltc ();
+               BootMessage (_("Set up Click"));
+               setup_click ();
+               BootMessage (_("Set up standard connections"));
+               setup_bundles ();
+       }
+
+       catch (failed_constructor& err) {
+               return -1;
+       }
+
        BootMessage (_("Setup signal flow and plugins"));
 
        /* Reset all panners */
@@ -672,6 +732,8 @@ Session::when_engine_running ()
        BootMessage (_("Connect to engine"));
        _engine.set_session (this);
        _engine.reset_timebase ();
+
+       return 0;
 }
 
 void
index 2491712c495c8d8c0c22d504962510d7cb4f772f..b4364f4c139b385c40872af3000b2a4835ab2eaa 100644 (file)
@@ -125,10 +125,35 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-/** @param snapshot_name Snapshot name, without the .ardour prefix */
 void
-Session::first_stage_init (string fullpath, string /*snapshot_name*/)
+Session::pre_engine_init (string fullpath)
 {
+       if (fullpath.empty()) {
+               destroy ();
+               throw failed_constructor();
+       }
+
+       /* discover canonical fullpath */
+
+       char buf[PATH_MAX+1];
+       if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
+               error << string_compose(_("Could not use path %1 (%2)"), buf, strerror(errno)) << endmsg;
+               destroy ();
+               throw failed_constructor();
+       }
+
+       _path = string(buf);
+       
+       /* we require _path to end with a dir separator */
+
+       if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
+               _path += G_DIR_SEPARATOR;
+       }
+
+       /* is it new ? */
+
+       _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+
        /* finish initialization that can't be done in a normal C++ constructor
           definition.
        */
@@ -168,32 +193,6 @@ Session::first_stage_init (string fullpath, string /*snapshot_name*/)
                                                         boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
         add_controllable (_solo_cut_control);
 
-       /* discover canonical fullpath */
-
-       if (fullpath.length() == 0) {
-               destroy ();
-               throw failed_constructor();
-       }
-
-       char buf[PATH_MAX+1];
-       if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
-               error << string_compose(_("Could not use path %1 (%2)"), buf, strerror(errno)) << endmsg;
-               destroy ();
-               throw failed_constructor();
-       }
-
-       _path = string(buf);
-       
-       /* we require _path to end with a dir separator */
-
-       if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
-               _path += G_DIR_SEPARATOR;
-       }
-
-       /* is it new ? */
-
-       _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
-
        /* These are all static "per-class" signals */
 
        SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
@@ -207,95 +206,90 @@ Session::first_stage_init (string fullpath, string /*snapshot_name*/)
        Delivery::disable_panners ();
        IO::disable_connecting ();
 
-       /* ENGINE */
+       AudioFileSource::set_peak_dir (_session_dir->peak_path());
+}
+
+int
+Session::post_engine_init ()
+{
+       BootMessage (_("Set block size and sample rate"));
+
+       set_block_size (_engine.samples_per_cycle());
+       set_frame_rate (_engine.sample_rate());
 
        n_physical_outputs = _engine.n_physical_outputs ();
        n_physical_inputs =  _engine.n_physical_inputs ();
 
-       _current_frame_rate = _engine.sample_rate ();
-       _nominal_frame_rate = _current_frame_rate;
-       _base_frame_rate = _current_frame_rate;
+       BootMessage (_("Using configuration"));
 
        _midi_ports = new MidiPortManager;
-       _mmc = new MIDI::MachineControl;
-       
-       _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
+       setup_midi_machine_control ();
        
-       _tempo_map = new TempoMap (_current_frame_rate);
-       _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
-
-       AudioDiskstream::allocate_working_buffers();
-
-       SndFileSource::setup_standard_crossfades (*this, frame_rate());
-       _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
-
-       refresh_disk_space ();
-       sync_time_vars ();
-}
-
-int
-Session::second_stage_init ()
-{
-       AudioFileSource::set_peak_dir (_session_dir->peak_path());
-
        if (_butler->start_thread()) {
                return -1;
        }
-
+       
        if (start_midi_thread ()) {
                return -1;
        }
+       
+       setup_click_sounds (0);
+       setup_midi_control ();
 
-       setup_midi_machine_control ();
-
-       // set_state() will call setup_raid_path(), but if it's a new session we need
-       // to call setup_raid_path() here.
-
-       if (state_tree) {
-               if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
-                       return -1;
-               }
-       } else {
-               setup_raid_path(_path);
-       }
+       _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
+       _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
 
-       /* we can't save till after ::when_engine_running() is called,
-          because otherwise we save state with no connections made.
-          therefore, we reset _state_of_the_state because ::set_state()
-          will have cleared it.
+       try {
+               /* tempo map requires sample rate knowledge */
 
-          we also have to include Loading so that any events that get
-          generated between here and the end of ::when_engine_running()
-          will be processed directly rather than queued.
-       */
+               _tempo_map = new TempoMap (_current_frame_rate);
+               _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
+               
+               /* MidiClock requires a tempo map */
 
-       _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading);
+               midi_clock = new MidiClockTicker ();
+               midi_clock->set_session (this);
 
-       _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
-       _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
-       setup_click_sounds (0);
-       setup_midi_control ();
+               /* crossfades require sample rate knowledge */
 
-       /* Pay attention ... */
+               SndFileSource::setup_standard_crossfades (*this, frame_rate());
+               _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
+               
+               AudioDiskstream::allocate_working_buffers();
+               refresh_disk_space ();
+               
+               /* we're finally ready to call set_state() ... all objects have
+                * been created, the engine is running.
+                */
+               
+               if (state_tree) {
+                       if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
+                               return -1;
+                       }
+               } else {
+                       // set_state() will call setup_raid_path(), but if it's a new session we need
+                       // to call setup_raid_path() here.
+                       setup_raid_path (_path);
+               }
 
-       _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
-       _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
+               /* ENGINE */
 
-       midi_clock = new MidiClockTicker ();
-       midi_clock->set_session (this);
+               boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
+               boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
+               
+               Config->map_parameters (ff);
+               config.map_parameters (ft);
 
-       try {
                when_engine_running ();
-       }
-
-       /* handle this one in a different way than all others, so that its clear what happened */
 
-       catch (AudioEngine::PortRegistrationFailure& err) {
+               _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
+               _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
+               
+       } catch (AudioEngine::PortRegistrationFailure& err) {
+               /* handle this one in a different way than all others, so that its clear what happened */
                error << err.what() << endmsg;
                return -1;
-       }
-
-       catch (...) {
+       } catch (...) {
                return -1;
        }
 
@@ -3516,6 +3510,9 @@ Session::load_diskstreams_2X (XMLNode const & node, int)
 void
 Session::setup_midi_machine_control ()
 {
+       _mmc = new MIDI::MachineControl;
+       _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
+
        _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
        _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
        _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));