show a different audio/MIDI option screen if JACK is already running. try to fix...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 19 Sep 2013 19:03:20 +0000 (15:03 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 19 Sep 2013 19:03:20 +0000 (15:03 -0400)
gtk2_ardour/ardour_ui.cc
gtk2_ardour/engine_dialog.cc
gtk2_ardour/engine_dialog.h
libs/backends/jack/jack_audiobackend.cc

index 74e2768b41068e2cb08a53d03c4067b28168f1d9..f22b48bd3a8842bbc10a8c98540dd0954c310aac 100644 (file)
@@ -399,14 +399,10 @@ ARDOUR_UI::engine_stopped ()
 void
 ARDOUR_UI::engine_running ()
 {
-       cerr << "ENGINE RUNNING\n";
-
        if (first_time_engine_run) {
                post_engine();
                first_time_engine_run = false;
-       } else {
-               cerr << "AGAIN...\n";
-       }
+       } 
        
        update_disk_space ();
        update_cpu_load ();
@@ -1084,8 +1080,6 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
 {
        char buf[64];
 
-       cerr << "USR\n";
-
        ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
 
        if (!AudioEngine::instance()->connected()) {
@@ -1112,8 +1106,6 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
                        }
                }
        }
-       cerr << "SRL = " << buf << endl;
-
        sample_rate_label.set_markup (buf);
 }
 
index 65fa7227a78eb3fe717ed98946ced7704cbdf441..135e2869ee6e3a5ff3116e2ebab7797fecc4fecc 100644 (file)
@@ -78,20 +78,146 @@ EngineControl::EngineControl ()
        , aj_button (_("Start MIDI ALSA/JACK bridge"))
        , ignore_changes (0)
        , _desired_sample_rate (0)
+       , no_push (true)
 {
-       if (!ARDOUR::AudioEngine::instance()->setup_required()) {
-               _have_control = false;
-       } else {
-               _have_control = true;
-       }
+       using namespace Notebook_Helpers;
+       vector<string> strings;
+       Label* label;
+       AttachOptions xopt = AttachOptions (FILL|EXPAND);
+       int row;
 
        set_name (X_("AudioMIDISetup"));
 
-       build_notebook ();
+       /* the backend combo is the one thing that is ALWAYS visible 
+        */
+
+       vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
+       for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
+               strings.push_back ((*b)->name);
+       }
+
+       set_popdown_strings (backend_combo, strings);
+       backend_combo.set_active_text (strings.front());
+       backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
+
+       /* setup basic packing characteristics for the table used on the main
+        * tab of the notebook
+        */
+
+       basic_packer.set_spacings (6);
+       basic_packer.set_border_width (12);
+       basic_packer.set_homogeneous (true);
+
+       /* pack it in */
+
+       basic_hbox.pack_start (basic_packer, false, false);
+
+       /* latency tab */
+
+       /* latency measurement tab */
+       
+       lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
+       
+       row = 0;
+       lm_table.set_row_spacings (12);
+
+       lm_table.attach (lm_title, 0, 2, row, row+1, xopt, (AttachOptions) 0);
+       row++;
+
+       Gtk::Label* preamble;
+
+       preamble = manage (new Label);
+       preamble->set_width_chars (60);
+       preamble->set_line_wrap (true);
+       preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your hardware to a very low level.</span>"));
+
+       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       row++;
+
+       preamble = manage (new Label);
+       preamble->set_width_chars (60);
+       preamble->set_line_wrap (true);
+       preamble->set_markup (_("Select two channels below and connect them using a cable or (less ideally) a speaker and microphone."));
+
+       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       row++;
+
+       label = manage (new Label (_("Output channel")));
+       lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+
+       Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
+       misc_align->add (lm_output_channel_combo);
+       lm_table.attach (*misc_align, 1, 2, row, row+1, xopt, (AttachOptions) 0);
+       ++row;
+
+       label = manage (new Label (_("Input channel")));
+       lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+
+       misc_align = manage (new Alignment (0.0, 0.5));
+       misc_align->add (lm_input_channel_combo);
+       lm_table.attach (*misc_align, 1, 2, row, row+1, FILL, (AttachOptions) 0);
+       ++row;
+
+       xopt = AttachOptions(0);
+
+       lm_measure_button.add (lm_start_stop_label);
+       
+       lm_measure_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::latency_button_toggled));
+       lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
+       lm_use_button.set_sensitive (false);
+
+       preamble = manage (new Label);
+       preamble->set_width_chars (60);
+       preamble->set_line_wrap (true);
+       preamble->set_markup (_("Once the channels are connected, click the \"Measure latency\" button."));
+       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       row++;
+
+       lm_table.attach (lm_measure_button, 0, 2, row, row+1, xopt, (AttachOptions) 0);
+       ++row;
+       lm_table.attach (lm_results, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       ++row;
+
+
+       preamble = manage (new Label);
+       preamble->set_width_chars (60);
+       preamble->set_line_wrap (true);
+       preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
+       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       row++;
+
+       lm_table.attach (lm_use_button, 0, 2, row, row+1, xopt, (AttachOptions) 0);
+       ++row;
+
+       lm_results.set_markup ("<i>No measurement results yet</i>");
+
+       lm_vbox.set_border_width (12);
+       lm_vbox.pack_start (lm_table, false, false);
+
+       /* pack it all up */
+
+       notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
+       notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
+       notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
+       notebook.set_border_width (12);
+
+       notebook.set_tab_pos (POS_RIGHT);
+       notebook.show_all ();
+
+       notebook.set_name ("SettingsNotebook");
+
+       /* packup the notebook */
 
        get_vbox()->set_border_width (12);
        get_vbox()->pack_start (notebook);
 
+       /* need a special function to print "all available channels" when the
+        * channel counts hit zero.
+        */
+
+       input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
+       output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
+
        control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
        manage_control_app_sensitivity ();
 
@@ -103,12 +229,31 @@ EngineControl::EngineControl ()
 
        XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
        
-       /* push a change as if we altered the backend */
+       ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
+       ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
+       ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
+
        backend_changed ();
 
        if (audio_setup) {
                set_state (*audio_setup);
-       } 
+       }
+
+       /* Connect to signals */
+
+       driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
+       sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
+       buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
+       device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
+
+       input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
+       output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
+       input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
+       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));
+
+       no_push = false;
 }
 
 void
@@ -139,36 +284,58 @@ EngineControl::on_response (int response_id)
 void
 EngineControl::build_notebook ()
 {
-       using namespace Notebook_Helpers;
        Label* label;
-       vector<string> strings;
-       int row = 0;
+       AttachOptions xopt = AttachOptions (FILL|EXPAND);
 
-       vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
-       for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
-               strings.push_back ((*b)->name);
+       /* clear the table */
+
+       Gtkmm2ext::container_clear (basic_vbox);
+       Gtkmm2ext::container_clear (basic_packer);
+
+       label = manage (left_aligned_label (_("Audio System:")));
+       basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
+       basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
+       
+       if (_have_control) {
+               build_full_control_notebook ();
+       } else {
+               build_no_control_notebook ();
        }
 
-       set_popdown_strings (backend_combo, strings);
-       backend_combo.set_active_text (strings.front());
+       basic_vbox.pack_start (basic_hbox, false, false);
 
-       basic_packer.set_spacings (6);
-       basic_packer.set_border_width (12);
-       basic_packer.set_homogeneous (true);
+       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);
+       }
 
-       row = 0;
+       basic_vbox.show_all ();
+}
+
+void
+EngineControl::build_full_control_notebook ()
+{
+       boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+       assert (backend);
 
+       using namespace Notebook_Helpers;
+       Label* label;
+       vector<string> strings;
        AttachOptions xopt = AttachOptions (FILL|EXPAND);
+       int row = 1; // row zero == backend combo
 
-       label = manage (left_aligned_label (_("Audio System:")));
-       basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
-       basic_packer.attach (backend_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
-       row++;
+       /* start packing it up */
 
-       label = manage (left_aligned_label (_("Driver:")));
-       basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
-       basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
-       row++;
+       if (backend->requires_driver_selection()) {
+               label = manage (left_aligned_label (_("Driver:")));
+               basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
+               basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
+               row++;
+       }
 
        label = manage (left_aligned_label (_("Device:")));
        basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
@@ -236,126 +403,46 @@ EngineControl::build_notebook ()
        basic_packer.attach (*label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
        ++row;
 
-       basic_hbox.pack_start (basic_packer, false, false);
-       basic_vbox.pack_start (basic_hbox, false, false);
-
-       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);
-
-       /* latency measurement tab */
-       
-       lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
-       
-       row = 0;
-       lm_table.set_row_spacings (12);
-
-       lm_table.attach (lm_title, 0, 2, row, row+1, xopt, (AttachOptions) 0);
-       row++;
-
-       Gtk::Label* preamble;
-
-       preamble = manage (new Label);
-       preamble->set_width_chars (60);
-       preamble->set_line_wrap (true);
-       preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your hardware to a very low level.</span>"));
+}
 
-       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
-       row++;
+void
+EngineControl::build_no_control_notebook ()
+{
+       boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+       assert (backend);
 
-       preamble = manage (new Label);
-       preamble->set_width_chars (60);
-       preamble->set_line_wrap (true);
-       preamble->set_markup (_("Select two channels below and connect them using a cable or (less ideally) a speaker and microphone."));
+       using namespace Notebook_Helpers;
+       Label* label;
+       vector<string> strings;
+       AttachOptions xopt = AttachOptions (FILL|EXPAND);
+       int row = 1; // row zero == backend combo
+       const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
 
-       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       label = manage (new Label);
+       label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
+       basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
        row++;
 
-       label = manage (new Label (_("Output channel")));
-       lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
-
-       Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
-       misc_align->add (lm_output_channel_combo);
-       lm_table.attach (*misc_align, 1, 2, row, row+1, xopt, (AttachOptions) 0);
-       ++row;
-
-       label = manage (new Label (_("Input channel")));
-       lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
-
-       misc_align = manage (new Alignment (0.0, 0.5));
-       misc_align->add (lm_input_channel_combo);
-       lm_table.attach (*misc_align, 1, 2, row, row+1, FILL, (AttachOptions) 0);
-       ++row;
-
-       xopt = AttachOptions(0);
-
-       lm_measure_button.add (lm_start_stop_label);
-       
-       lm_measure_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::latency_button_toggled));
-       lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
-       lm_use_button.set_sensitive (false);
-               
-
-       preamble = manage (new Label);
-       preamble->set_width_chars (60);
-       preamble->set_line_wrap (true);
-       preamble->set_markup (_("Once the channels are connected, click the \"Measure latency\" button."));
-       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
-       row++;
+       if (backend->can_change_sample_rate_when_running()) {
+               label = manage (left_aligned_label (_("Sample rate:")));
+               basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
+               basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
+               row++;
+       }
 
-       lm_table.attach (lm_measure_button, 0, 2, row, row+1, xopt, (AttachOptions) 0);
-       ++row;
-       lm_table.attach (lm_results, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
-       ++row;
+       if (backend->can_change_buffer_size_when_running()) {
+               label = manage (left_aligned_label (_("Buffer size:")));
+               basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
+               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, xopt, (AttachOptions) 0);
+               row++;
+       }
 
+       connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
 
-       preamble = manage (new Label);
-       preamble->set_width_chars (60);
-       preamble->set_line_wrap (true);
-       preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
-       lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
        row++;
-
-       lm_table.attach (lm_use_button, 0, 2, row, row+1, xopt, (AttachOptions) 0);
-       ++row;
-
-       lm_results.set_markup ("<i>No measurement results yet</i>");
-
-       lm_vbox.set_border_width (12);
-       lm_vbox.pack_start (lm_table, false, false);
-
-       /* pack it all up */
-
-       notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
-       notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
-       notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
-       notebook.set_border_width (12);
-
-       notebook.set_tab_pos (POS_RIGHT);
-       notebook.show_all ();
-
-       notebook.set_name ("SettingsNotebook");
-
-       /* Connect to signals */
-
-       backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
-       driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
-       sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
-       buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
-       device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
-
-       input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
-       output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
-       input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
-       output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
-
-       input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
-       output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
-
-       notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
 }
 
 EngineControl::~EngineControl ()
@@ -470,6 +557,11 @@ EngineControl::refresh_midi_display ()
        }
 }
 
+void
+EngineControl::update_sensitivity ()
+{
+}
+
 void
 EngineControl::backend_changed ()
 {
@@ -485,16 +577,29 @@ EngineControl::backend_changed ()
                return;
        }
 
+       _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
+
+       build_notebook ();
        setup_midi_tab_for_backend ();
 
        if (backend->requires_driver_selection()) {
                vector<string> drivers = backend->enumerate_drivers();
-               driver_combo.set_sensitive (true);
-               set_popdown_strings (driver_combo, drivers);
-               driver_combo.set_active_text (drivers.front());
-               driver_changed ();
+               
+               if (!drivers.empty()) {
+                       {
+                               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_changed ();
+               }
+               
        } else {
                driver_combo.set_sensitive (false);
+               /* this will change the device text which will cause a call to
+                * device changed which will set up parameters
+                */
                list_devices ();
        }
        
@@ -540,33 +645,33 @@ EngineControl::list_devices ()
                available_devices.push_back (i->name);
        }
 
-       ignore_changes++;
-       set_popdown_strings (device_combo, available_devices);
-       ignore_changes--;
-
        if (!available_devices.empty()) {
-               sample_rate_combo.set_sensitive (true);
-               buffer_size_combo.set_sensitive (true);
-               input_latency.set_sensitive (true);
-               output_latency.set_sensitive (true);
-               input_channels.set_sensitive (true);
-               output_channels.set_sensitive (true);
+
+               update_sensitivity ();
                                                
-               /* changing the text in the combo will trigger device_changed()
-                  which should populate the parameter controls
-               */
-               
-               device_combo.set_active_text (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_changed ();
+
+               ok_button->set_sensitive (true);
+               apply_button->set_sensitive (true);
+
        } else {
-               sample_rate_combo.set_sensitive (true);
-               buffer_size_combo.set_sensitive (true);
-               input_latency.set_sensitive (true);
-               output_latency.set_sensitive (true);
-               input_channels.set_sensitive (true);
-               output_channels.set_sensitive (true);
+               sample_rate_combo.set_sensitive (false);
+               buffer_size_combo.set_sensitive (false);
+               input_latency.set_sensitive (false);
+               output_latency.set_sensitive (false);
+               input_channels.set_sensitive (false);
+               output_channels.set_sensitive (false);
+               ok_button->set_sensitive (false);
+               apply_button->set_sensitive (false);
        }
 }
-       
+
 void
 EngineControl::driver_changed ()
 {
@@ -595,59 +700,95 @@ EngineControl::device_changed ()
        string device_name = device_combo.get_active_text ();
        vector<string> s;
 
-       /* don't allow programmatic change to sample_rate_combo to cause a
-          recursive call to this method.
-       */
-          
-       ignore_changes++;
+       {
+               PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
 
-       /* sample rates */
-       
-       string desired;
+               /* don't allow programmatic change to combos to cause a
+                  recursive call to this method.
+               */
+               
+               /* sample rates */
+               
+               string desired;
+               
+               vector<float> sr;
 
-       vector<float> sr = backend->available_sample_rates (device_name);
-       for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
-               s.push_back (rate_as_string (*x));
-               if (*x == _desired_sample_rate) {
-                       desired = s.back();
+               if (_have_control) {
+                       sr = backend->available_sample_rates (device_name);
+               } else {
+
+                       sr.push_back (8000.0f);
+                       sr.push_back (16000.0f);
+                       sr.push_back (32000.0f);
+                       sr.push_back (44100.0f);
+                       sr.push_back (48000.0f);
+                       sr.push_back (88200.0f);
+                       sr.push_back (96000.0f);
+                       sr.push_back (192000.0f);
+                       sr.push_back (384000.0f);
                }
-       }
 
-       if (!s.empty()) {
-               set_popdown_strings (sample_rate_combo, s);
-       
-               if (desired.empty()) {
-                       sample_rate_combo.set_active_text (s.front());
+               for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
+                       s.push_back (rate_as_string (*x));
+                       if (*x == _desired_sample_rate) {
+                               desired = s.back();
+                       }
+               }
+               
+               if (!s.empty()) {
+                       sample_rate_combo.set_sensitive (true);
+                       set_popdown_strings (sample_rate_combo, s);
+
+                       if (desired.empty()) {
+                               sample_rate_combo.set_active_text (s.front());
+                       } else {
+                               sample_rate_combo.set_active_text (desired);
+                       }
+
                } else {
-                       sample_rate_combo.set_active_text (desired);
+                       sample_rate_combo.set_sensitive (false);
                }
-       } else {
-               /* hmm ... how to tell the user about the fact that we have no
-                * available sample rates.
-                */
-       }
-                
 
-       vector<uint32_t> bs = backend->available_buffer_sizes(device_name);
-       s.clear ();
-       for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
-               s.push_back (bufsize_as_string (*x));
-       }
+               /* buffer sizes */
+               
+               vector<uint32_t> bs;
+               
+               if (_have_control) {
+                       bs = backend->available_buffer_sizes(device_name);
+               } else if (backend->can_change_buffer_size_when_running()) {
+                       bs.push_back (8);
+                       bs.push_back (16);
+                       bs.push_back (32);
+                       bs.push_back (64);
+                       bs.push_back (128);
+                       bs.push_back (256);
+                       bs.push_back (512);
+                       bs.push_back (1024);
+                       bs.push_back (2048);
+                       bs.push_back (4096);
+                       bs.push_back (8192);
+               }
+               s.clear ();
+               for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
+                       s.push_back (bufsize_as_string (*x));
+               }
+               
+               if (!s.empty()) {
+                       buffer_size_combo.set_sensitive (true);
+                       set_popdown_strings (buffer_size_combo, s);
+                       
+                       buffer_size_combo.set_active_text (s.front());
+                       show_buffer_duration ();
+               } else {
+                       buffer_size_combo.set_sensitive (false);
+               }
 
-       if (!s.empty()) {
-               set_popdown_strings (buffer_size_combo, s);
-               buffer_size_combo.set_active_text (s.front());
-               show_buffer_duration ();
-       } else {
-               /* hmm ... how to tell the user about the fact that we have no
-                * available buffer sizes.
+               /* XXX theoretically need to set min + max channel counts here
                 */
+               
+               manage_control_app_sensitivity ();
        }
 
-       manage_control_app_sensitivity ();
-
-       ignore_changes--;
-
        /* pick up any saved state for this device */
 
        maybe_display_saved_state ();
@@ -774,6 +915,10 @@ EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
 EngineControl::State*
 EngineControl::save_state ()
 {
+       if (!_have_control) {
+               return 0;
+       }
+
        bool existing = true;
        State* state = get_saved_state_for_currently_displayed_backend_and_device ();
 
@@ -808,10 +953,15 @@ EngineControl::store_state (State& state)
 void
 EngineControl::maybe_display_saved_state ()
 {
+       if (!_have_control) {
+               return;
+       }
+
        State* state = get_saved_state_for_currently_displayed_backend_and_device ();
 
        if (state) {
-               ignore_changes++;
+               PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
+
                if (!_desired_sample_rate) {
                        sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
                }
@@ -822,7 +972,6 @@ EngineControl::maybe_display_saved_state ()
                show_buffer_duration ();
                input_latency.set_value (state->input_latency);
                output_latency.set_value (state->output_latency);
-               ignore_changes--;
        }
 }
        
@@ -952,6 +1101,7 @@ EngineControl::set_state (const XMLNode& root)
        /* now see if there was an active state and switch the setup to it */
        
        for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
+
                if ((*i).active) {
                        ignore_changes++;
                        backend_combo.set_active_text ((*i).backend);
@@ -971,6 +1121,10 @@ EngineControl::set_state (const XMLNode& root)
 int
 EngineControl::push_state_to_backend (bool start)
 {
+       if (no_push) {
+               return 0;
+       }
+
        boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
 
        if (!backend) {
@@ -992,47 +1146,60 @@ EngineControl::push_state_to_backend (bool start)
        uint32_t ichan = get_input_channels ();
 
        if (_have_control) {
-               
-               /* we can control the backend */
 
-               if (backend->requires_driver_selection()) {
-                       if (get_driver() != backend->driver_name()) {
-                               change_driver = true;
+               if (started_at_least_once) {
+                       
+                       /* we can control the backend */
+                       
+                       if (backend->requires_driver_selection()) {
+                               if (get_driver() != backend->driver_name()) {
+                                       change_driver = true;
+                               }
                        }
-               }
+                       
+                       if (get_device_name() != backend->device_name()) {
+                               change_device = true;
+                       }
+                       
+                       if (get_rate() != backend->sample_rate()) {
+                               change_rate = true;
+                       }
+                       
+                       if (get_buffer_size() != backend->buffer_size()) {
+                               change_bufsize = true;
+                       }
+                       
+                       /* zero-requested channels means "all available" */
 
-               if (get_device_name() != backend->device_name()) {
-                       change_device = true;
-               }
+                       if (ichan == 0) {
+                               ichan = backend->input_channels();
+                       }
+                       
+                       if (ochan == 0) {
+                               ochan = backend->output_channels();
+                       }
+                       
+                       if (ichan != backend->input_channels()) {
+                               change_channels = true;
+                       }
+                       
+                       if (ochan != backend->output_channels()) {
+                               change_channels = true;
+                       }
 
-               if (get_rate() != backend->sample_rate()) {
+                       if (get_input_latency() != backend->systemic_input_latency() ||
+                           get_output_latency() != backend->systemic_output_latency()) {
+                               change_latency = true;
+                       }
+               } else {
+                       /* backend never started, so we have to force a group
+                          of settings.
+                       */
+                       change_driver = true;
+                       change_device = true;
                        change_rate = true;
-               }
-
-               if (get_buffer_size() != backend->buffer_size()) {
                        change_bufsize = true;
-               }
-
-               /* zero-requested channels means "all available" */
-
-               if (ichan == 0) {
-                       ichan = backend->input_channels();
-               }
-
-               if (ochan == 0) {
-                       ochan = backend->output_channels();
-               }
-
-               if (ichan != backend->input_channels()) {
-                       change_channels = true;
-               }
-
-               if (ochan != backend->output_channels()) {
                        change_channels = true;
-               }
-
-               if (get_input_latency() != backend->systemic_input_latency() ||
-                   get_output_latency() != backend->systemic_output_latency()) {
                        change_latency = true;
                }
 
@@ -1175,26 +1342,28 @@ EngineControl::post_push ()
         * necessary
         */
        
-       State* state = get_saved_state_for_currently_displayed_backend_and_device ();
-       
-       if (!state) {
-               state = save_state ();
-               assert (state);
-       }
-       
-       /* all off */
-       
-       for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
-               (*i).active = false;
+       if (_have_control) {
+               State* state = get_saved_state_for_currently_displayed_backend_and_device ();
+               
+               if (!state) {
+                       state = save_state ();
+                       assert (state);
+               }
+               
+               /* all off */
+               
+               for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
+                       (*i).active = false;
+               }
+               
+               /* mark this one active (to be used next time the dialog is
+                * shown)
+                */
+               
+               state->active = true;
+               
+               manage_control_app_sensitivity ();
        }
-       
-       /* mark this one active (to be used next time the dialog is
-        * shown)
-        */
-       
-       state->active = true;
-
-       manage_control_app_sensitivity ();
 
        /* schedule a redisplay of MIDI ports */
        
@@ -1482,3 +1651,51 @@ EngineControl::on_delete_event (GdkEventAny* ev)
        return ArdourDialog::on_delete_event (ev);
 }
 
+void
+EngineControl::engine_running ()
+{
+       boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+       assert (backend);
+
+       buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size()));
+       sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
+
+       if (backend->can_change_buffer_size_when_running()) {
+               buffer_size_combo.set_sensitive (true);
+       } else {
+               buffer_size_combo.set_sensitive (false);
+       }
+
+       if (backend->can_change_sample_rate_when_running()) {
+               sample_rate_combo.set_sensitive (true);
+       } else {
+               sample_rate_combo.set_sensitive (false);
+       }
+
+       connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
+
+       started_at_least_once = true;
+}
+
+void
+EngineControl::engine_stopped ()
+{
+       boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+       assert (backend);
+
+       buffer_size_combo.set_sensitive (false);
+       connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
+
+       sample_rate_combo.set_sensitive (true);
+       buffer_size_combo.set_sensitive (true);
+}
+       
+void
+EngineControl::connect_disconnect_click() 
+{
+       if (ARDOUR::AudioEngine::instance()->running()) {
+               ARDOUR_UI::instance()->disconnect_from_engine ();
+       } else {
+               ARDOUR_UI::instance()->reconnect_to_engine ();
+       }
+}
index fcbdfe4cb8e0dff70e43b6803d0d70b73e6c593e..59924e0f0aaacf5449f02c70c4e070dfc7721103 100644 (file)
@@ -75,8 +75,11 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
     Gtk::Adjustment ports_adjustment;
     Gtk::SpinButton ports_spinner;
 
+    Gtk::Label      have_control_text;
     Gtk::Button     control_app_button;
 
+    Gtk::Button     connect_disconnect_button;
+
     /* latency measurement */
 
     Gtk::ComboBoxText lm_output_channel_combo;
@@ -106,9 +109,9 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
     
     uint32_t ignore_changes;
     uint32_t _desired_sample_rate;
-    
-    static bool engine_running ();
-    
+    bool     no_push;
+    bool     started_at_least_once;
+
     void driver_changed ();
     void backend_changed ();
     void sample_rate_changed ();
@@ -174,6 +177,8 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
     static bool print_channel_count (Gtk::SpinButton*);
 
     void build_notebook ();
+    void build_full_control_notebook ();
+    void build_no_control_notebook ();
 
     void on_response (int);
     void control_app_button_clicked ();
@@ -181,6 +186,7 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
     void manage_control_app_sensitivity ();
     int push_state_to_backend (bool start);
     void post_push ();
+    void update_sensitivity ();
 
     /* latency measurement */
     void latency_button_toggled ();
@@ -190,9 +196,16 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
     void disable_latency_tab ();
     void start_latency_detection ();
     void end_latency_detection ();
-
+    
     void on_switch_page (GtkNotebookPage*, guint page_num);
     bool on_delete_event (GdkEventAny*);
+
+    void engine_running ();
+    void engine_stopped ();
+    PBD::ScopedConnection running_connection;
+    PBD::ScopedConnection stopped_connection;
+
+    void connect_disconnect_click ();
 };
 
 #endif /* __gtk2_ardour_engine_dialog_h__ */
index 1e7cb9d8d5f283b01dd27a81421adf477c54c36a..d4e2f310d3e78478d7e5135a1e034ca1cfdff277 100644 (file)
@@ -960,6 +960,7 @@ JACKAudioBackend::disconnected (const char* why)
                engine.halted_callback (why); /* EMIT SIGNAL */
         }
 }
+
 float 
 JACKAudioBackend::cpu_load() const 
 {