when the user changes devices, notify the backend
[ardour.git] / gtk2_ardour / engine_dialog.cc
index 437aea7d39aab2763a32ec9ea87b7151ce1b0ce1..a32ccf146e81a8486721af2e2ba9be1f14f879dd 100644 (file)
@@ -43,6 +43,7 @@
 #include "ardour/mididm.h"
 #include "ardour/rc_configuration.h"
 #include "ardour/types.h"
+#include "ardour/profile.h"
 
 #include "pbd/convert.h"
 #include "pbd/error.h"
@@ -67,6 +68,7 @@ static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1
 
 EngineControl::EngineControl ()
        : ArdourDialog (_("Audio/MIDI Setup"))
+       , engine_status ("")
        , basic_packer (9, 4)
        , input_latency_adjustment (0, 0, 99999, 1)
        , input_latency (input_latency_adjustment)
@@ -247,6 +249,9 @@ EngineControl::EngineControl ()
        get_vbox()->set_border_width (12);
        get_vbox()->pack_start (notebook);
 
+       get_action_area()->pack_start (engine_status);
+       engine_status.show();
+
        /* need a special function to print "all available channels" when the
         * channel counts hit zero.
         */
@@ -262,9 +267,9 @@ EngineControl::EngineControl ()
        control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
        manage_control_app_sensitivity ();
 
-       cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-       ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
+       cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
        apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
+       ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
 
        /* Pick up any existing audio setup configuration, if appropriate */
 
@@ -298,6 +303,18 @@ EngineControl::EngineControl ()
        output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
 
        notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
+
+       connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
+       connect_disconnect_button.set_no_show_all();
+
+}
+
+void
+EngineControl::on_show ()
+{
+       ArdourDialog::on_show ();
+       device_changed ();
+       ok_button->grab_focus();
 }
 
 void
@@ -357,16 +374,10 @@ EngineControl::build_notebook ()
 
        basic_vbox.pack_start (basic_hbox, false, false);
 
-       if (_have_control) {
-               Gtk::HBox* hpacker = manage (new HBox);
-               hpacker->set_border_width (12);
-               hpacker->pack_start (control_app_button, false, false);
-               hpacker->show ();
-               control_app_button.show();
-               basic_vbox.pack_start (*hpacker);
+       {
+               PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
+               basic_vbox.show_all ();
        }
-
-       basic_vbox.show_all ();
 }
 
 void
@@ -406,6 +417,10 @@ EngineControl::build_full_control_notebook ()
        basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
        buffer_size_duration_label.set_alignment (0.0); /* left-align */
        basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
+
+       /* button spans 2 rows */
+
+       basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
        row++;
 
        input_channels.set_name ("InputChannels");
@@ -414,22 +429,26 @@ EngineControl::build_full_control_notebook ()
        input_channels.set_wrap (false);
        output_channels.set_editable (true);
 
-       label = manage (left_aligned_label (_("Input Channels:")));
-       basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
-       basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
-       ++row;
-
+       if (!ARDOUR::Profile->get_mixbus()) {
+               label = manage (left_aligned_label (_("Input Channels:")));
+               basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+               basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
+               ++row;
+       }
+       
        output_channels.set_name ("OutputChannels");
        output_channels.set_flags (Gtk::CAN_FOCUS);
        output_channels.set_digits (0);
        output_channels.set_wrap (false);
        output_channels.set_editable (true);
 
-       label = manage (left_aligned_label (_("Output Channels:")));
-       basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
-       basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
-       ++row;
-
+       if (!ARDOUR::Profile->get_mixbus()) {
+               label = manage (left_aligned_label (_("Output Channels:")));
+               basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+               basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
+               ++row;
+       }
+       
        input_latency.set_name ("InputLatency");
        input_latency.set_flags (Gtk::CAN_FOCUS);
        input_latency.set_digits (0);
@@ -501,8 +520,6 @@ EngineControl::build_no_control_notebook ()
                row++;
        }
 
-       connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
-
        basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
        row++;
 }
@@ -548,10 +565,10 @@ EngineControl::enable_latency_tab ()
        lm_back_button_signal.disconnect();
        if (_measure_midi) {
                lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
-               lm_preamble.set_markup (_(""));
+               lm_preamble.hide ();
        } else {
                lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
-               lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
+               lm_preamble.show ();
        }
 
        set_popdown_strings (lm_output_channel_combo, outputs);
@@ -706,9 +723,20 @@ EngineControl::backend_changed ()
 
                if (!drivers.empty()) {
                        {
+                               string current_driver;
+                               current_driver = backend->driver_name ();
+
+                               // driver might not have been set yet
+                               if (current_driver == "") {
+                                       current_driver = driver_combo.get_active_text ();
+                                       if (current_driver == "")
+                                               // driver has never been set, make sure it's not blank
+                                               current_driver = drivers.front ();
+                               }
+
                                PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
                                set_popdown_strings (driver_combo, drivers);
-                               driver_combo.set_active_text (drivers.front());
+                               driver_combo.set_active_text (current_driver);
                        }
 
                        driver_changed ();
@@ -737,6 +765,8 @@ EngineControl::backend_changed ()
                }
        }
 
+       connect_disconnect_button.hide();
+
        midi_option_changed();
 
        started_at_least_once = false;
@@ -749,6 +779,11 @@ EngineControl::backend_changed ()
 bool
 EngineControl::print_channel_count (Gtk::SpinButton* sb)
 {
+       if (ARDOUR::Profile->get_mixbus()) {
+               cout << "Mixbus crash trap. sb->get_value(): " << sb->get_value();
+               return true;
+       }
+       
        uint32_t cnt = (uint32_t) sb->get_value();
        if (cnt == 0) {
                sb->set_text (_("all available channels"));
@@ -790,13 +825,29 @@ EngineControl::list_devices ()
                update_sensitivity ();
 
                {
+                       string current_device;
+                       current_device = backend->device_name ();
+                       if (current_device == "") {
+                               // device might not have been set yet
+                               current_device = device_combo.get_active_text ();
+                               if (current_device == "")
+                                       // device has never been set, make sure it's not blank
+                                       current_device = available_devices.front ();
+                       }
+
                        PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
                        set_popdown_strings (device_combo, available_devices);
-                       device_combo.set_active_text (available_devices.front());
+
+                       device_combo.set_active_text (current_device);
                }
 
                device_changed ();
 
+               input_latency.set_sensitive (true);
+               output_latency.set_sensitive (true);
+               input_channels.set_sensitive (true);
+               output_channels.set_sensitive (true);
+
                ok_button->set_sensitive (true);
                apply_button->set_sensitive (true);
 
@@ -814,6 +865,13 @@ EngineControl::list_devices ()
                } else {
                        ok_button->set_sensitive (true);
                        apply_button->set_sensitive (true);
+                       if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
+                               sample_rate_combo.set_sensitive (true);
+                       }
+                       if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
+                               buffer_size_combo.set_sensitive (true);
+                       }
+
                }
        }
 }
@@ -840,6 +898,9 @@ EngineControl::device_changed ()
        assert (backend);
        string device_name = device_combo.get_active_text ();
        vector<string> s;
+       
+       //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
+       backend->set_device_name(device_name);
 
        {
                PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
@@ -918,7 +979,11 @@ EngineControl::device_changed ()
                        buffer_size_combo.set_sensitive (true);
                        set_popdown_strings (buffer_size_combo, s);
 
-                       buffer_size_combo.set_active_text (bufsize_as_string (backend->default_buffer_size()));
+                       uint32_t period = backend->buffer_size();
+                       if (0 == period) {
+                               period = backend->default_buffer_size(device_name);
+                       }
+                       buffer_size_combo.set_active_text (bufsize_as_string (period));
                        show_buffer_duration ();
                } else {
                        buffer_size_combo.set_sensitive (false);
@@ -983,15 +1048,25 @@ EngineControl::show_buffer_duration ()
        uint32_t samples = atoi (bs_text); /* will ignore trailing text */
        uint32_t rate = get_rate();
 
-       /* Translators: "msecs" is ALWAYS plural here, so we do not
-          need singular form as well.
-        */
        /* Developers: note the hard-coding of a double buffered model
           in the (2 * samples) computation of latency. we always start
           the audiobackend in this configuration.
         */
+       /* note to jack1 developers: ardour also always starts the engine
+        * in async mode (no jack2 --sync option) which adds an extra cycle
+        * of latency with jack2 (and *3 would be correct)
+        * The value can also be wrong if jackd is started externally..
+        *
+        * At the time of writing the ALSA backend always uses double-buffering *2,
+        * The Dummy backend *1, and who knows what ASIO really does :)
+        *
+        * So just display the period size, that's also what
+        * ARDOUR_UI::update_sample_rate() does for the status bar.
+        * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
+        * but still, that's the buffer period, not [round-trip] latency)
+        */
        char buf[32];
-       snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
+       snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
        buffer_size_duration_label.set_text (buf);
 }
 
@@ -1692,12 +1767,22 @@ EngineControl::get_midi_option () const
 uint32_t
 EngineControl::get_input_channels() const
 {
+       if (ARDOUR::Profile->get_mixbus()) {
+               boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+               if (!backend) return 0;
+               return backend->input_channels();
+       }
        return (uint32_t) input_channels_adjustment.get_value();
 }
 
 uint32_t
 EngineControl::get_output_channels() const
 {
+       if (ARDOUR::Profile->get_mixbus()) {
+               boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+               if (!backend) return 0;
+               return backend->input_channels();
+       }
        return (uint32_t) output_channels_adjustment.get_value();
 }
 
@@ -1889,6 +1974,8 @@ EngineControl::check_audio_latency_measurement ()
                solid = false;
        }
 
+       lm_results.set_markup (string_compose (results_markup, buf));
+
        if (solid) {
                have_lm_results = true;
                end_latency_detection ();
@@ -1896,8 +1983,6 @@ EngineControl::check_audio_latency_measurement ()
                return false;
        }
 
-       lm_results.set_markup (string_compose (results_markup, buf));
-
        return true;
 }
 
@@ -1949,6 +2034,7 @@ EngineControl::check_midi_latency_measurement ()
                have_lm_results = true;
                end_latency_detection ();
                lm_use_button.set_sensitive (true);
+               lm_results.set_markup (string_compose (results_markup, buf));
                return false;
        } else if (mididm->processed () > 400) {
                have_lm_results = false;
@@ -2064,8 +2150,10 @@ EngineControl::engine_running ()
        sample_rate_combo.set_sensitive (true);
 
        connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
+       connect_disconnect_button.show();
 
        started_at_least_once = true;
+       engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
 }
 
 void
@@ -2076,9 +2164,11 @@ EngineControl::engine_stopped ()
 
        buffer_size_combo.set_sensitive (false);
        connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
+       connect_disconnect_button.show();
 
        sample_rate_combo.set_sensitive (true);
        buffer_size_combo.set_sensitive (true);
+       engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
 }
 
 void