fix merge errors with master
[ardour.git] / gtk2_ardour / ardour_ui.cc
index e764c50d4e85327dd8187f875594a539d3603eb8..6337b1919fed3ea6b2a5b5fef17fb3a68b85272c 100644 (file)
@@ -58,8 +58,6 @@
 #include "gtkmm2ext/popup.h"
 #include "gtkmm2ext/window_title.h"
 
-#include "midi++/manager.h"
-
 #include "ardour/ardour.h"
 #include "ardour/audio_backend.h"
 #include "ardour/audioengine.h"
@@ -103,6 +101,7 @@ typedef uint64_t microseconds_t;
 #include "missing_plugin_dialog.h"
 #include "mixer_ui.h"
 #include "mouse_cursors.h"
+#include "nsm.h"
 #include "opts.h"
 #include "pingback.h"
 #include "processor_box.h"
@@ -111,6 +110,7 @@ typedef uint64_t microseconds_t;
 #include "rc_option_editor.h"
 #include "route_time_axis.h"
 #include "route_params_ui.h"
+#include "session_dialog.h"
 #include "session_metadata_dialog.h"
 #include "session_option_editor.h"
 #include "shuttle_control.h"
@@ -158,11 +158,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
          /* start of private members */
 
-       , _startup (0)
-       , engine (0)
        , nsm (0)
        , _was_dirty (false)
        , _mixer_on_top (false)
+       , first_time_engine_run (true)
 
          /* transport */
 
@@ -182,6 +181,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , solo_alert_button (_("solo"))
        , feedback_alert_button (_("feedback"))
 
+       , editor_meter(0)
+       , editor_meter_peak_display()
+
        , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
        , theme_manager (X_("theme-manager"), _("Theme Manager"))
        , key_editor (X_("key-editor"), _("Key Bindings"))
@@ -190,6 +192,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , about (X_("about"), _("About"))
        , location_ui (X_("locations"), _("Locations"))
        , route_params (X_("inspector"), _("Tracks and Busses"))
+       , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
        , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
        , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
        , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
@@ -201,7 +204,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        , _status_bar_visibility (X_("status-bar"))
        , _feedback_exists (false)
-
 {
        Gtkmm2ext::init(localedir);
 
@@ -213,11 +215,14 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        ui_config = new UIConfiguration();
 
+       ui_config->ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
+       boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
+       ui_config->map_parameters (pc);
+
        editor = 0;
        mixer = 0;
        meterbridge = 0;
        editor = 0;
-       engine = 0;
        _session_is_new = false;
        session_selector_window = 0;
        last_key_press_time = 0;
@@ -265,6 +270,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
 
+       /* 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, _1));
+
        /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
 
        ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
@@ -288,21 +297,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        /* lets get this party started */
 
-       try {
-               if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) {
-                       throw failed_constructor ();
-               }
-
-               setup_gtk_ardour_enums ();
-               setup_profile ();
-
-               SessionEvent::create_per_thread_pool ("GUI", 512);
+       setup_gtk_ardour_enums ();
+       setup_profile ();
 
-       } catch (failed_constructor& err) {
-               error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
-               // pass it on up
-               throw;
-       }
+       SessionEvent::create_per_thread_pool ("GUI", 512);
 
        /* we like keyboards */
 
@@ -354,6 +352,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        WM::Manager::instance().register_window (&add_route_dialog);
        WM::Manager::instance().register_window (&add_video_dialog);
        WM::Manager::instance().register_window (&route_params);
+       WM::Manager::instance().register_window (&audio_midi_setup);
        WM::Manager::instance().register_window (&bundle_manager);
        WM::Manager::instance().register_window (&location_ui);
        WM::Manager::instance().register_window (&big_clock_window);
@@ -367,9 +366,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        
        (void) theme_manager.get (true);
        
-       starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
-       stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
-
        _process_thread = new ProcessThread ();
        _process_thread->init ();
 
@@ -390,27 +386,89 @@ ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
 void
 ARDOUR_UI::attach_to_engine ()
 {
-       engine = AudioEngine::instance();
+       AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
+       ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
+}
+
+void
+ARDOUR_UI::engine_stopped ()
+{
+       ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
+       ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
+       ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
+}
+
+void
+ARDOUR_UI::engine_running ()
+{
+       if (first_time_engine_run) {
+               post_engine();
+               first_time_engine_run = false;
+       } 
+       
+       update_disk_space ();
+       update_cpu_load ();
+       update_sample_rate (AudioEngine::instance()->sample_rate());
+       update_timecode_format ();
+}
 
-       engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
-       engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
-       engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
+void
+ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
+{
+       if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
+               /* we can't rely on the original string continuing to exist when we are called
+                  again in the GUI thread, so make a copy and note that we need to
+                  free it later.
+               */
+               char *copy = strdup (reason);
+               Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
+               return;
+       }
 
-       engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
-       engine->BackendAvailable.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::post_engine, this));
+       ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
+       ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
 
-       ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
+       update_sample_rate (0);
+
+       string msgstr;
+
+       /* if the reason is a non-empty string, it means that the backend was shutdown
+          rather than just Ardour.
+       */
+
+       if (strlen (reason)) {
+               msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
+       } else {
+               msgstr = string_compose (_("\
+The audio backend has either been shutdown or it\n\
+disconnected %1 because %1\n\
+was not fast enough. Try to restart\n\
+the audio backend and save the session."), PROGRAM_NAME);
+       }
+
+       MessageDialog msg (*editor, msgstr);
+       pop_back_splash (msg);
+       msg.set_keep_above (true);
+       msg.run ();
+       
+       if (free_reason) {
+               free (const_cast<char*> (reason));
+       }
 }
 
 void
 ARDOUR_UI::post_engine ()
 {
-       cerr << "Backend available!\n";
-
-       /* Things to be done once we have a backend running in the AudioEngine
+       /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
         */
 
        ARDOUR::init_post_engine ();
+       
+       /* connect to important signals */
+
+       AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
+       AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
+       AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
 
        _tooltips.enable();
 
@@ -473,29 +531,17 @@ ARDOUR_UI::post_engine ()
        Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
 #endif
 
-       update_disk_space ();
-       update_cpu_load ();
-       update_sample_rate (engine->sample_rate());
-       update_timecode_format ();
-
        Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
        boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
        Config->map_parameters (pc);
-
-       /* now start and maybe save state */
-
-       if (do_engine_start () == 0) {
-               if (_session && _session_is_new) {
-                       /* we need to retain initial visual
-                          settings for a new session
-                       */
-                       _session->save_state ("");
-               }
-       }
 }
 
 ARDOUR_UI::~ARDOUR_UI ()
 {
+       if (ui_config->dirty()) {
+               ui_config->save_state();
+       }
+
        delete keyboard;
        delete editor;
        delete mixer;
@@ -672,11 +718,12 @@ ARDOUR_UI::check_announcements ()
 #endif
 }
 
-void
-ARDOUR_UI::startup ()
+int
+ARDOUR_UI::starting ()
 {
        Application* app = Application::instance ();
-       char *nsm_url;
+       const char *nsm_url;
+       bool brand_new_user = ArdourStartup::required ();
 
        app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
        app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
@@ -687,9 +734,17 @@ ARDOUR_UI::startup ()
 
        app->ready ();
 
-       nsm_url = getenv ("NSM_URL");
+       /* we need to create this early because it may need to set the
+        *  audio backend end up.
+        */
+       
+       try {
+               audio_midi_setup.get (true);
+       } catch (...) {
+               return -1;
+       }
 
-       if (nsm_url) {
+       if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
                nsm = new NSM_Client;
                if (!nsm->init (nsm_url)) {
                        nsm->announce (PROGRAM_NAME, ":dirty:", "ardour3");
@@ -699,19 +754,33 @@ ARDOUR_UI::startup ()
                        for ( i = 0; i < 5000; ++i) {
                                nsm->check ();
                                usleep (i);
-                               if (nsm->is_active())
+                               if (nsm->is_active()) {
                                        break;
+                               }
+                       }
+                       if (i == 5000) {
+                               error << _("NSM server did not announce itself") << endmsg;
+                               return -1;
                        }
                        // wait for open command from nsm server
                        for ( i = 0; i < 5000; ++i) {
                                nsm->check ();
                                usleep (1000);
-                               if (nsm->client_id ())
+                               if (nsm->client_id ()) {
                                        break;
+                               }
+                       }
+
+                       if (i == 5000) {
+                               error << _("NSM: no client ID provided") << endmsg;
+                               return -1;
                        }
 
                        if (_session && nsm) {
                                _session->set_nsm_state( nsm->is_active() );
+                       } else {
+                               error << _("NSM: no session created") << endmsg;
+                               return -1;
                        }
 
                        // nsm requires these actions disabled
@@ -730,15 +799,35 @@ ARDOUR_UI::startup ()
                                }
                        }
 
-               }
-               else {
+               } else {
                        delete nsm;
                        nsm = 0;
+                       error << _("NSM: initialization failed") << endmsg;
+                       return -1;
                }
-       }
 
-       else if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
-               exit (1);
+       } else  {
+               
+               if (brand_new_user) {
+                       ArdourStartup s;
+                       s.present ();
+                       main().run();
+                       s.hide ();
+                       switch (s.response ()) {
+                       case Gtk::RESPONSE_OK:
+                               break;
+                       default:
+                               return -1;
+                       }
+               }
+
+               /* go get a session */
+
+               const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
+
+               if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
+                       return -1;
+               }
        }
 
        use_config ();
@@ -753,13 +842,7 @@ ARDOUR_UI::startup ()
        _status_bar_visibility.update ();
 
        BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
-}
-
-void
-ARDOUR_UI::no_memory_warning ()
-{
-       XMLNode node (X_("no-memory-warning"));
-       Config->add_instant_xml (node);
+       return 0;
 }
 
 void
@@ -772,7 +855,7 @@ ARDOUR_UI::check_memory_locking ()
 
        XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
 
-       if (engine->is_realtime() && memory_warning_node == 0) {
+       if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
 
                struct rlimit limits;
                int64_t ram;
@@ -818,9 +901,6 @@ ARDOUR_UI::check_memory_locking ()
                                VBox* vbox = msg.get_vbox();
                                HBox hbox;
                                CheckButton cb (_("Do not show this window again"));
-
-                               cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
-                               
                                hbox.pack_start (cb, true, false);
                                vbox->pack_start (hbox);
                                cb.show();
@@ -831,6 +911,11 @@ ARDOUR_UI::check_memory_locking ()
 
                                editor->ensure_float (msg);
                                msg.run ();
+
+                               if (cb.get_active()) {
+                                       XMLNode node (X_("no-memory-warning"));
+                                       Config->add_instant_xml (node);
+                               }
                        }
                }
        }
@@ -912,7 +997,8 @@ If you still wish to quit, please use the\n\n\
                _session = 0;
        }
 
-       engine->stop ();
+       halt_connection.disconnect ();
+       AudioEngine::instance()->stop ();
        quit ();
 }
 
@@ -1022,6 +1108,15 @@ ARDOUR_UI::every_point_zero_something_seconds ()
        // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
 
        SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
+       if (editor_meter && Config->get_show_editor_meter()) {
+               float mpeak = editor_meter->update_meters();
+               if (mpeak > editor_meter_max_peak) {
+                       if (mpeak >= Config->get_meter_peak()) {
+                               editor_meter_peak_display.set_name ("meterbridge peakindicator on");
+                               editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
+                       }
+               }
+       }
        return TRUE;
 }
 
@@ -1032,25 +1127,30 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
 
        ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
 
-       if (!engine->connected()) {
+       if (!AudioEngine::instance()->connected()) {
 
-               snprintf (buf, sizeof (buf), "%s", _("disconnected"));
+               snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
 
        } else {
 
-               framecnt_t rate = engine->sample_rate();
+               framecnt_t rate = AudioEngine::instance()->sample_rate();
 
-               if (fmod (rate, 1000.0) != 0.0) {
-                       snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
-                                 (float) rate / 1000.0f,
-                                 (engine->usecs_per_cycle() / 1000.0f));
+               if (rate == 0) {
+                       /* no sample rate available */
+                       snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
                } else {
-                       snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
-                                 rate/1000,
-                                 (engine->usecs_per_cycle() * 1000.0f));
+
+                       if (fmod (rate, 1000.0) != 0.0) {
+                               snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
+                                         (float) rate / 1000.0f,
+                                         (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
+                       } else {
+                               snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
+                                         rate/1000,
+                                         (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
+                       }
                }
        }
-
        sample_rate_label.set_markup (buf);
 }
 
@@ -1117,7 +1217,7 @@ ARDOUR_UI::update_cpu_load ()
           should also be changed.
        */
 
-       float const c = engine->get_cpu_load ();
+       float const c = AudioEngine::instance()->get_dsp_load ();
        snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
        cpu_load_label.set_markup (buf);
 }
@@ -1171,6 +1271,11 @@ ARDOUR_UI::update_disk_space()
        char buf[64];
        framecnt_t fr = _session->frame_rate();
 
+       if (fr == 0) {
+               /* skip update - no SR available */
+               return;
+       }
+
        if (!opt_frames) {
                /* Available space is unknown */
                snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
@@ -1433,20 +1538,16 @@ ARDOUR_UI::open_recent_session ()
 bool
 ARDOUR_UI::check_audioengine ()
 {
-       if (engine) {
-               if (!engine->connected()) {
-                       MessageDialog msg (string_compose (
-                                                  _("%1 is not connected to JACK\n"
-                                                    "You cannot open or close sessions in this condition"),
-                                                  PROGRAM_NAME));
-                       pop_back_splash (msg);
-                       msg.run ();
-                       return false;
-               }
-               return true;
-       } else {
+       if (!AudioEngine::instance()->connected()) {
+               MessageDialog msg (string_compose (
+                                          _("%1 is not connected to any audio backend.\n"
+                                            "You cannot open or close sessions in this condition"),
+                                          PROGRAM_NAME));
+               pop_back_splash (msg);
+               msg.run ();
                return false;
        }
+       return true;
 }
 
 void
@@ -1652,10 +1753,17 @@ ARDOUR_UI::transport_goto_wallclock ()
 
                time (&now);
                localtime_r (&now, &tmnow);
+               
+               int frame_rate = _session->frame_rate();
+               
+               if (frame_rate == 0) {
+                       /* no frame rate available */
+                       return;
+               }
 
-               frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
-               frames += tmnow.tm_min * (60 * _session->frame_rate());
-               frames += tmnow.tm_sec * _session->frame_rate();
+               frames = tmnow.tm_hour * (60 * 60 * frame_rate);
+               frames += tmnow.tm_min * (60 * frame_rate);
+               frames += tmnow.tm_sec * frame_rate;
 
                _session->request_locate (frames, _session->transport_rolling ());
 
@@ -1746,7 +1854,7 @@ ARDOUR_UI::transport_roll ()
 #if 0
        if (_session->config.get_external_sync()) {
                switch (Config->get_sync_source()) {
-               case JACK:
+               case Engine:
                        break;
                default:
                        /* transport controlled by the master */
@@ -1796,7 +1904,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
 
        if (_session->config.get_external_sync()) {
                switch (Config->get_sync_source()) {
-               case JACK:
+               case Engine:
                        break;
                default:
                        /* transport controlled by the master */
@@ -2015,127 +2123,6 @@ ARDOUR_UI::map_transport_state ()
        }
 }
 
-void
-ARDOUR_UI::engine_stopped ()
-{
-       ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
-       ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
-       ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
-}
-
-void
-ARDOUR_UI::engine_running ()
-{
-       ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
-       ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
-       ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
-
-       Glib::RefPtr<Action> action;
-       const char* action_name = 0;
-
-       switch (engine->samples_per_cycle()) {
-       case 32:
-               action_name = X_("JACKLatency32");
-               break;
-       case 64:
-               action_name = X_("JACKLatency64");
-               break;
-       case 128:
-               action_name = X_("JACKLatency128");
-               break;
-       case 512:
-               action_name = X_("JACKLatency512");
-               break;
-       case 1024:
-               action_name = X_("JACKLatency1024");
-               break;
-       case 2048:
-               action_name = X_("JACKLatency2048");
-               break;
-       case 4096:
-               action_name = X_("JACKLatency4096");
-               break;
-       case 8192:
-               action_name = X_("JACKLatency8192");
-               break;
-       default:
-               /* XXX can we do anything useful ? */
-               break;
-       }
-
-       if (action_name) {
-
-               action = ActionManager::get_action (X_("JACK"), action_name);
-
-               if (action) {
-                       Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
-                       ract->set_active ();
-               }
-       }
-}
-
-void
-ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
-{
-       if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
-               /* we can't rely on the original string continuing to exist when we are called
-                  again in the GUI thread, so make a copy and note that we need to
-                  free it later.
-               */
-               char *copy = strdup (reason);
-               Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
-               return;
-       }
-
-       ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
-       ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
-
-       update_sample_rate (0);
-
-       string msgstr;
-
-       /* if the reason is a non-empty string, it means that the backend was shutdown
-          rather than just Ardour.
-       */
-
-       if (strlen (reason)) {
-               msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
-       } else {
-               msgstr = string_compose (_("\
-JACK has either been shutdown or it\n\
-disconnected %1 because %1\n\
-was not fast enough. Try to restart\n\
-JACK, reconnect and save the session."), PROGRAM_NAME);
-       }
-
-       MessageDialog msg (*editor, msgstr);
-       pop_back_splash (msg);
-       msg.set_keep_above (true);
-       msg.run ();
-       
-       if (free_reason) {
-               free (const_cast<char*> (reason));
-       }
-}
-
-int32_t
-ARDOUR_UI::do_engine_start ()
-{
-       try {
-               engine->start();
-       }
-
-       catch (...) {
-               engine->stop ();
-               error << _("Unable to start the session running")
-                     << endmsg;
-               unload_session ();
-               return -2;
-       }
-
-       return 0;
-}
-
 void
 ARDOUR_UI::update_clocks ()
 {
@@ -2207,8 +2194,13 @@ ARDOUR_UI::snapshot_session (bool switch_to_it)
 
        prompter.set_name ("Prompter");
        prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
-       prompter.set_title (_("Take Snapshot"));
-       prompter.set_prompt (_("Name of new snapshot"));
+       if (switch_to_it) {
+               prompter.set_title (_("Save as..."));
+               prompter.set_prompt (_("New session name"));
+       } else {
+               prompter.set_title (_("Take Snapshot"));
+               prompter.set_prompt (_("Name of new snapshot"));
+       }
 
        if (!switch_to_it) {
                char timebuf[128];
@@ -2489,7 +2481,7 @@ ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
 }
 
 int
-ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
+ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
 {
        BusProfile bus_profile;
 
@@ -2505,13 +2497,13 @@ ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::s
 
                /* get settings from advanced section of NSD */
 
-               if (_startup->create_master_bus()) {
-                       bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
+               if (sd.create_master_bus()) {
+                       bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
                } else {
                        bus_profile.master_out_channels = 0;
                }
 
-               if (_startup->connect_inputs()) {
+               if (sd.connect_inputs()) {
                        bus_profile.input_ac = AutoConnectPhysical;
                } else {
                        bus_profile.input_ac = AutoConnectOption (0);
@@ -2519,16 +2511,16 @@ ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::s
 
                bus_profile.output_ac = AutoConnectOption (0);
 
-               if (_startup->connect_outputs ()) {
-                       if (_startup->connect_outs_to_master()) {
+               if (sd.connect_outputs ()) {
+                       if (sd.connect_outs_to_master()) {
                                bus_profile.output_ac = AutoConnectMaster;
-                       } else if (_startup->connect_outs_to_physical()) {
+                       } else if (sd.connect_outs_to_physical()) {
                                bus_profile.output_ac = AutoConnectPhysical;
                        }
                }
 
-               bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
-               bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
+               bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
+               bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
        }
 
        if (build_session (session_path, session_name, bus_profile)) {
@@ -2564,17 +2556,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
        string template_name;
        int ret = -1;
        bool likely_new = false;
-
-       /* if the audio/midi backend does not require setup, get our use of it underway
-        * right here
-        */
-
-       if (!EngineControl::need_setup()) {
-               vector<const AudioBackendInfo*> backends = AudioEngine::instance()->available_backends();
-               cerr << "Setting up backend " << backends.front()->name;
-               AudioEngine::instance()->set_backend (backends.front()->name, ARDOUR_COMMAND_LINE::backend_client_name, ARDOUR_COMMAND_LINE::backend_session_uuid);
-               AudioEngine::instance()->start ();
-       }
+       bool cancel_not_quit;
 
        /* deal with any existing DIRTY session now, rather than later. don't
         * treat a non-dirty session this way, so that it stays visible 
@@ -2585,6 +2567,11 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                ARDOUR_UI::instance()->video_timeline->sync_session_state();
        }
 
+       /* if there is already a session, relabel the button
+          on the SessionDialog so that we don't Quit directly
+       */
+       cancel_not_quit = (_session != 0);
+
        if (_session && _session->dirty()) {
                if (unload_session (false)) {
                        /* unload cancelled by user */
@@ -2598,6 +2585,20 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                template_name = load_template;
        }
 
+       session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
+       session_path = ARDOUR_COMMAND_LINE::session_name;
+       
+       if (!session_path.empty()) {
+               if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
+                       if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
+                               /* session/snapshot file, change path to be dir */
+                               session_path = Glib::path_get_dirname (session_path);
+                       }
+               }
+       }
+
+       SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
+
        while (ret != 0) {
 
                if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
@@ -2620,34 +2621,35 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                } else {
                        session_path = "";
                        session_name = "";
-               }
-
-               delete _startup;
-               _startup = new ArdourStartup (should_be_new, session_name, session_path, load_template);
-               
-               if (!_startup->ready_without_display()) {
-                       _startup->present ();
-                       main().run();
-                       _startup->hide ();
+                       session_dialog.clear_given ();
                }
                
-               switch (_startup->response()) {
-               case RESPONSE_OK:
-                       break;
-               default:
-                       if (quit_on_cancel) {
-                               exit (1);
-                       } else {
-                               return ret;
+               if (should_be_new || session_name.empty()) {
+                       /* need the dialog to get info from user */
+
+                       cerr << "run dialog\n";
+
+                       switch (session_dialog.run()) {
+                       case RESPONSE_ACCEPT:
+                               break;
+                       default:
+                               if (quit_on_cancel) {
+                                       exit (1);
+                               } else {
+                                       return ret;
+                               }
                        }
+
+                       session_dialog.hide ();
                }
 
                /* if we run the startup dialog again, offer more than just "new session" */
                
                should_be_new = false;
                
-               session_name = _startup->session_name (likely_new);
-               
+               session_name = session_dialog.session_name (likely_new);
+               session_path = session_dialog.session_folder ();
+
                if (nsm) {
                        likely_new = true;
                }
@@ -2664,8 +2666,8 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                        continue;
                }
                
-               if (_startup->use_session_template()) {
-                       template_name = _startup->session_template_name();
+               if (session_dialog.use_session_template()) {
+                       template_name = session_dialog.session_template_name();
                        _session_is_new = true;
                }
                
@@ -2682,12 +2684,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                        
                } else {
 
-                       session_path = _startup->session_folder();
+                       session_path = session_dialog.session_folder();
                        
                        char illegal = Session::session_name_is_legal (session_name);
                        
                        if (illegal) {
-                               MessageDialog msg (*_startup,
+                               MessageDialog msg (session_dialog,
                                                   string_compose (_("To ensure compatibility with various systems\n"
                                                                     "session names may not contain a '%1' character"),
                                                                   illegal));
@@ -2699,6 +2701,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
        
                if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
 
+
                        if (likely_new && !nsm) {
 
                                std::string existing = Glib::build_filename (session_path, session_name);
@@ -2714,12 +2717,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                } else {
 
                        if (!likely_new) {
-                               if (_startup) {
-                                       pop_back_splash (*_startup);
-                               } else {
-                                       hide_splash ();
-                               }
-
+                               pop_back_splash (session_dialog);
                                MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
                                msg.run ();
                                ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
@@ -2727,10 +2725,11 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                        }
 
                        char illegal = Session::session_name_is_legal(session_name);
+
                        if (illegal) {
-                               pop_back_splash (*_startup);
-                               MessageDialog msg (*_startup, string_compose(_("To ensure compatibility with various systems\n"
-                                                    "session names may not contain a '%1' character"), illegal));
+                               pop_back_splash (session_dialog);
+                               MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
+                                                                                   "session names may not contain a '%1' character"), illegal));
                                msg.run ();
                                ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
                                continue;
@@ -2741,7 +2740,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
 
                if (likely_new && template_name.empty()) {
 
-                       ret = build_session_from_nsd (session_path, session_name);
+                       ret = build_session_from_dialog (session_dialog, session_path, session_name);
 
                } else {
 
@@ -2756,6 +2755,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                                _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
                                exit (1);
                        }
+
+                       /* clear this to avoid endless attempts to load the
+                          same session.
+                       */
+
+                       ARDOUR_COMMAND_LINE::session_name = "";
                }
        }
 
@@ -2792,25 +2797,23 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
        int unload_status;
        int retval = -1;
 
-       session_loaded = false;
-
-       if (!check_audioengine()) {
-               return -2;
+       if (_session) {
+               unload_status = unload_session ();
+               
+               if (unload_status < 0) {
+                       goto out;
+               } else if (unload_status > 0) {
+                       retval = 0;
+                       goto out;
+               }
        }
 
-       unload_status = unload_session ();
-
-       if (unload_status < 0) {
-               goto out;
-       } else if (unload_status > 0) {
-               retval = 0;
-               goto out;
-       }
+       session_loaded = false;
 
        loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
 
        try {
-               new_session = new Session (*engine, path, snap_name, 0, mix_template);
+               new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
        }
 
        /* this one is special */
@@ -2850,22 +2853,12 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
                                   Gtk::MESSAGE_INFO,
                                   BUTTONS_OK);
 
+               msg.set_keep_above (true);
                msg.set_title (_("Loading Error"));
-               msg.set_secondary_text (_("Click the Refresh button to try again."));
-               msg.add_button (Stock::REFRESH, 1);
                msg.set_position (Gtk::WIN_POS_CENTER);
                pop_back_splash (msg);
                msg.present ();
-
-               int response = msg.run ();
-
-               switch (response) {
-               case 1:
-                       break;
-               default:
-                       exit (1);
-               }
-
+               (void) msg.run ();
                msg.hide ();
 
                goto out;
@@ -2879,6 +2872,22 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
                }
        }
 
+       if (!new_session->writable()) {
+               MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
+                                  true,
+                                  Gtk::MESSAGE_INFO,
+                                  BUTTONS_OK);
+               
+               msg.set_keep_above (true);
+               msg.set_title (_("Read-only Session"));
+               msg.set_position (Gtk::WIN_POS_CENTER);
+               pop_back_splash (msg);
+               msg.present ();
+               (void) msg.run ();
+               msg.hide ();
+       }
+       
+
        /* Now the session been created, add the transport controls */
        new_session->add_controllable(roll_controllable);
        new_session->add_controllable(stop_controllable);
@@ -2911,12 +2920,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
        Session *new_session;
        int x;
 
-       if (!check_audioengine()) {
-               return -1;
-       }
-
        session_loaded = false;
-
        x = unload_session ();
 
        if (x < 0) {
@@ -2928,7 +2932,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
        _session_is_new = true;
 
        try {
-               new_session = new Session (*engine, path, snap_name, &bus_profile);
+               new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
        }
 
        catch (...) {
@@ -3240,6 +3244,57 @@ ARDOUR_UI::flush_trash ()
        display_cleanup_results (rep, _("deleted file"), true);
 }
 
+void
+ARDOUR_UI::setup_order_hint ()
+{
+       uint32_t order_hint = 0;
+
+       /*
+         we want the new routes to have their order keys set starting from 
+         the highest order key in the selection + 1 (if available).
+       */
+       if (add_route_dialog->get_transient_for () == mixer->get_toplevel()) {
+               for (RouteUISelection::iterator s = mixer->selection().routes.begin(); s != mixer->selection().routes.end(); ++s) {
+                       if ((*s)->route()->order_key() > order_hint) {
+                               order_hint = (*s)->route()->order_key();
+                       }
+               }
+
+               if (!mixer->selection().routes.empty()) {
+                       order_hint++;
+               }
+
+       } else {
+               for (TrackSelection::iterator s = editor->get_selection().tracks.begin(); s != editor->get_selection().tracks.end(); ++s) {
+                       RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (*s);
+                       if (tav->route()->order_key() > order_hint) {
+                               order_hint = tav->route()->order_key();
+                       }
+               }
+
+               if (!editor->get_selection().tracks.empty()) {
+                       order_hint++;
+               }
+       }
+
+       _session->set_order_hint (order_hint);
+
+       /* create a gap in the existing route order keys to accomodate new routes.*/
+
+       boost::shared_ptr <RouteList> rd = _session->get_routes();
+       for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
+               boost::shared_ptr<Route> rt (*ri);
+                       
+               if (rt->is_monitor()) {
+                       continue;
+               }
+
+               if (rt->order_key () >= order_hint) {
+                       rt->set_order_key (rt->order_key () + add_route_dialog->count());
+               }
+       }
+}
+
 void
 ARDOUR_UI::add_route (Gtk::Window* float_window)
 {
@@ -3255,6 +3310,7 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
        }
 
        if (float_window) {
+               add_route_dialog->unset_transient_for ();
                add_route_dialog->set_transient_for (*float_window);
        }
 
@@ -3274,6 +3330,8 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
                return;
        }
 
+       setup_order_hint();
+
        PBD::ScopedConnection idle_connection;
 
        if (count > 8) {
@@ -3509,7 +3567,11 @@ ARDOUR_UI::add_video (Gtk::Window* float_window)
                                        return;
                                }
                                if (!transcode_video_dialog->get_audiofile().empty()) {
-                                       editor->embed_audio_from_video(transcode_video_dialog->get_audiofile());
+                                       editor->embed_audio_from_video(
+                                                       transcode_video_dialog->get_audiofile(),
+                                                       video_timeline->get_offset(),
+                                                       (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
+                                                       );
                                }
                                switch (transcode_video_dialog->import_option()) {
                                        case VTL_IMPORT_TRANSCODED:
@@ -3573,6 +3635,10 @@ ARDOUR_UI::remove_video ()
        video_timeline->close_session();
        editor->toggle_ruler_video(false);
 
+       /* reset state */
+       video_timeline->set_offset_locked(false);
+       video_timeline->set_offset(0);
+
        /* delete session state */
        XMLNode* node = new XMLNode(X_("Videotimeline"));
        _session->add_extra_xml(*node);
@@ -3744,8 +3810,8 @@ ARDOUR_UI::session_dialog (std::string msg)
 int
 ARDOUR_UI::pending_state_dialog ()
 {
-       HBox* hbox = new HBox();
-       Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
+       HBox* hbox = manage (new HBox());
+       Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
        ArdourDialog dialog (_("Crash Recovery"), true);
        Label  message (string_compose (_("\
 This session appears to have been in the\n\
@@ -3808,31 +3874,43 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual
         return 1;
 }
 
-
-void
-ARDOUR_UI::disconnect_from_jack ()
+int
+ARDOUR_UI::disconnect_from_engine ()
 {
-       if (engine) {
-               if (engine->pause ()) {
-                       MessageDialog msg (*editor, _("Could not disconnect from JACK"));
-                       msg.run ();
-               }
+       /* drop connection to AudioEngine::Halted so that we don't act
+        *  as if the engine unexpectedly shut down
+        */
 
-               update_sample_rate (0);
+       halt_connection.disconnect ();
+       
+       if (AudioEngine::instance()->stop ()) {
+               MessageDialog msg (*editor, _("Could not disconnect from Audio/MIDI engine"));
+               msg.run ();
+               return -1;
+       } else {
+               AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
        }
+       
+       update_sample_rate (0);
+       return 0;
 }
 
-void
-ARDOUR_UI::reconnect_to_jack ()
+int
+ARDOUR_UI::reconnect_to_engine ()
 {
-       if (engine) {
-               if (engine->start ()) {
-                       MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
+       if (AudioEngine::instance()->start ()) {
+               if (editor) {
+                       MessageDialog msg (*editor,  _("Could not reconnect to the Audio/MIDI engine"));
+                       msg.run ();
+               } else {
+                       MessageDialog msg (_("Could not reconnect to the Audio/MIDI engine"));
                        msg.run ();
                }
-
-               update_sample_rate (0);
+               return -1;
        }
+       
+       update_sample_rate (0);
+       return 0;
 }
 
 void
@@ -4110,3 +4188,50 @@ ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_pat
 
        msg.run ();
 }
+
+
+void
+ARDOUR_UI::reset_peak_display ()
+{
+       if (!_session || !_session->master_out() || !editor_meter) return;
+       editor_meter->clear_meters();
+       editor_meter_max_peak = -INFINITY;
+       editor_meter_peak_display.set_name ("meterbridge peakindicator");
+       editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
+}
+
+void
+ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
+{
+       if (!_session || !_session->master_out()) return;
+       if (group == _session->master_out()->route_group()) {
+               reset_peak_display ();
+       }
+}
+
+void
+ARDOUR_UI::reset_route_peak_display (Route* route)
+{
+       if (!_session || !_session->master_out()) return;
+       if (_session->master_out().get() == route) {
+               reset_peak_display ();
+       }
+}
+
+int
+ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
+{
+       audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
+       audio_midi_setup->set_position (WIN_POS_CENTER);
+
+       switch (audio_midi_setup->run()) {
+       case Gtk::RESPONSE_OK:
+               return 0;
+       case Gtk::RESPONSE_APPLY:
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+