fix MTDM test
[ardour.git] / gtk2_ardour / engine_dialog.cc
index b50b24e899133d4917271cc5249ffb7565abbf0b..f3dba387abbb5109e035decff1738eaf17bc5841 100644 (file)
@@ -58,11 +58,12 @@ using namespace Gtk;
 using namespace Gtkmm2ext;
 using namespace PBD;
 using namespace Glib;
+using namespace ARDOUR_UI_UTILS;
 
 static const unsigned int midi_tab = 2;
 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
 
-static const char* results_markup = X_("<span foreground=\"red\" style=\"italic\" size=\"larger\">%1</span>");
+static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
 
 EngineControl::EngineControl ()
        : ArdourDialog (_("Audio/MIDI Setup"))
@@ -141,16 +142,14 @@ EngineControl::EngineControl ()
        lm_table.attach (lm_title, 0, 3, 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 audio equipment to a very low level.</span>"));
+       lm_preamble.set_width_chars (60);
+       lm_preamble.set_line_wrap (true);
+       lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
 
-       lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+       lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
        row++;
 
+       Gtk::Label* preamble;
        preamble = manage (new Label);
        preamble->set_width_chars (60);
        preamble->set_line_wrap (true);
@@ -275,7 +274,15 @@ EngineControl::EngineControl ()
        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);
+       }
+       {
+               /* ignore: don't save state */
+               PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
+               backend_changed ();
+       }
 
        /* Connect to signals */
 
@@ -290,13 +297,16 @@ EngineControl::EngineControl ()
        input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
        output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
 
-       if (audio_setup) {
-               set_state (*audio_setup);
-       }
-
        notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
 }
 
+void
+EngineControl::on_show ()
+{
+       ArdourDialog::on_show ();
+       ok_button->grab_focus();
+}
+
 void
 EngineControl::on_response (int response_id)
 {
@@ -363,7 +373,10 @@ EngineControl::build_notebook ()
                basic_vbox.pack_start (*hpacker);
        }
 
-       basic_vbox.show_all ();
+       {
+               PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
+               basic_vbox.show_all ();
+       }
 }
 
 void
@@ -529,29 +542,35 @@ EngineControl::enable_latency_tab ()
        ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
        ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
 
-       if (inputs.empty() || outputs.empty()) {
+       if (!ARDOUR::AudioEngine::instance()->running()) {
+               MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
+               notebook.set_current_page (0);
+               msg.run ();
+               return;
+       }
+       else if (inputs.empty() || outputs.empty()) {
                MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
-               lm_measure_button.set_sensitive (false);
                notebook.set_current_page (0);
                msg.run ();
                return;
        }
 
-       if (!outputs.empty()) {
-               set_popdown_strings (lm_output_channel_combo, outputs);
-               lm_output_channel_combo.set_active_text (outputs.front());
-               lm_output_channel_combo.set_sensitive (true);
+       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.hide ();
        } else {
-               lm_output_channel_combo.set_sensitive (false);
+               lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
+               lm_preamble.show ();
        }
 
-       if (!inputs.empty()) {
-               set_popdown_strings (lm_input_channel_combo, inputs);
-               lm_input_channel_combo.set_active_text (inputs.front());
-               lm_input_channel_combo.set_sensitive (true);
-       } else {
-               lm_input_channel_combo.set_sensitive (false);
-       }
+       set_popdown_strings (lm_output_channel_combo, outputs);
+       lm_output_channel_combo.set_active_text (outputs.front());
+       lm_output_channel_combo.set_sensitive (true);
+
+       set_popdown_strings (lm_input_channel_combo, inputs);
+       lm_input_channel_combo.set_active_text (inputs.front());
+       lm_input_channel_combo.set_sensitive (true);
 
        lm_measure_button.set_sensitive (true);
 }
@@ -697,9 +716,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 ();
@@ -781,25 +811,47 @@ 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);
 
        } else {
+               device_combo.clear();
                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);
+               if (_have_control) {
+                       ok_button->set_sensitive (false);
+                       apply_button->set_sensitive (false);
+               } else {
+                       ok_button->set_sensitive (true);
+                       apply_button->set_sensitive (true);
+               }
        }
 }
 
@@ -1031,23 +1083,23 @@ EngineControl::parameter_changed ()
        }
 }
 
-EngineControl::State*
+EngineControl::State
 EngineControl::get_matching_state (
                const string& backend,
                const string& driver,
                const string& device)
 {
        for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
-               if ((*i).backend == backend &&
-                               (*i).driver == driver &&
-                               (*i).device == device) {
-                       return &(*i);
+               if ((*i)->backend == backend &&
+                               (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
+               {
+                       return (*i);
                }
        }
-       return 0;
+       return State();
 }
 
-EngineControl::State*
+EngineControl::State
 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
 {
        boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
@@ -1064,44 +1116,52 @@ EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
                        device_combo.get_active_text());
 }
 
-EngineControl::State*
+EngineControl::State
 EngineControl::save_state ()
 {
+       State state;
+
        if (!_have_control) {
-               return 0;
+               state = get_matching_state (backend_combo.get_active_text(), string(), string());
+               if (state) {
+                       return state;
+               }
+               state.reset(new StateStruct);
+               state->backend = get_backend ();
+       } else {
+               state.reset(new StateStruct);
+               store_state (state);
        }
-       State* state = new State;
-       store_state (*state);
 
        for (StateList::iterator i = states.begin(); i != states.end();) {
-               if ((*i).backend == state->backend &&
-                               (*i).driver == state->driver &&
-                               (*i).device == state->device) {
+               if ((*i)->backend == state->backend &&
+                               (*i)->driver == state->driver &&
+                               (*i)->device == state->device) {
                        i =  states.erase(i);
                } else {
                        ++i;
                }
        }
 
-       states.push_back (*state);
+       states.push_back (state);
 
        return state;
 }
 
 void
-EngineControl::store_state (State& state)
+EngineControl::store_state (State state)
 {
-       state.backend = get_backend ();
-       state.driver = get_driver ();
-       state.device = get_device_name ();
-       state.sample_rate = get_rate ();
-       state.buffer_size = get_buffer_size ();
-       state.input_latency = get_input_latency ();
-       state.output_latency = get_output_latency ();
-       state.input_channels = get_input_channels ();
-       state.output_channels = get_output_channels ();
-       state.midi_option = get_midi_option ();
-       state.midi_devices = _midi_devices;
+       state->backend = get_backend ();
+       state->driver = get_driver ();
+       state->device = get_device_name ();
+       state->sample_rate = get_rate ();
+       state->buffer_size = get_buffer_size ();
+       state->input_latency = get_input_latency ();
+       state->output_latency = get_output_latency ();
+       state->input_channels = get_input_channels ();
+       state->output_channels = get_output_channels ();
+       state->midi_option = get_midi_option ();
+       state->midi_devices = _midi_devices;
 }
 
 void
@@ -1111,7 +1171,7 @@ EngineControl::maybe_display_saved_state ()
                return;
        }
 
-       State* state = get_saved_state_for_currently_displayed_backend_and_device ();
+       State state = get_saved_state_for_currently_displayed_backend_and_device ();
 
        if (state) {
                PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
@@ -1147,20 +1207,20 @@ EngineControl::get_state ()
 
                        XMLNode* node = new XMLNode ("State");
 
-                       node->add_property ("backend", (*i).backend);
-                       node->add_property ("driver", (*i).driver);
-                       node->add_property ("device", (*i).device);
-                       node->add_property ("sample-rate", (*i).sample_rate);
-                       node->add_property ("buffer-size", (*i).buffer_size);
-                       node->add_property ("input-latency", (*i).input_latency);
-                       node->add_property ("output-latency", (*i).output_latency);
-                       node->add_property ("input-channels", (*i).input_channels);
-                       node->add_property ("output-channels", (*i).output_channels);
-                       node->add_property ("active", (*i).active ? "yes" : "no");
-                       node->add_property ("midi-option", (*i).midi_option);
+                       node->add_property ("backend", (*i)->backend);
+                       node->add_property ("driver", (*i)->driver);
+                       node->add_property ("device", (*i)->device);
+                       node->add_property ("sample-rate", (*i)->sample_rate);
+                       node->add_property ("buffer-size", (*i)->buffer_size);
+                       node->add_property ("input-latency", (*i)->input_latency);
+                       node->add_property ("output-latency", (*i)->output_latency);
+                       node->add_property ("input-channels", (*i)->input_channels);
+                       node->add_property ("output-channels", (*i)->output_channels);
+                       node->add_property ("active", (*i)->active ? "yes" : "no");
+                       node->add_property ("midi-option", (*i)->midi_option);
 
                        XMLNode* midi_devices = new XMLNode ("MIDIDevices");
-                       for (std::vector<MidiDeviceSettings>::const_iterator p = (*i).midi_devices.begin(); p != (*i).midi_devices.end(); ++p) {
+                       for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
                                XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
                                midi_device_stuff->add_property (X_("name"), (*p)->name);
                                midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
@@ -1207,7 +1267,7 @@ EngineControl::set_state (const XMLNode& root)
                cclist = child->children();
 
                for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
-                       State state;
+                       State state (new StateStruct);
 
                        grandchild = *cciter;
 
@@ -1218,61 +1278,61 @@ EngineControl::set_state (const XMLNode& root)
                        if ((prop = grandchild->property ("backend")) == 0) {
                                continue;
                        }
-                       state.backend = prop->value ();
+                       state->backend = prop->value ();
 
                        if ((prop = grandchild->property ("driver")) == 0) {
                                continue;
                        }
-                       state.driver = prop->value ();
+                       state->driver = prop->value ();
 
                        if ((prop = grandchild->property ("device")) == 0) {
                                continue;
                        }
-                       state.device = prop->value ();
+                       state->device = prop->value ();
 
                        if ((prop = grandchild->property ("sample-rate")) == 0) {
                                continue;
                        }
-                       state.sample_rate = atof (prop->value ());
+                       state->sample_rate = atof (prop->value ());
 
                        if ((prop = grandchild->property ("buffer-size")) == 0) {
                                continue;
                        }
-                       state.buffer_size = atoi (prop->value ());
+                       state->buffer_size = atoi (prop->value ());
 
                        if ((prop = grandchild->property ("input-latency")) == 0) {
                                continue;
                        }
-                       state.input_latency = atoi (prop->value ());
+                       state->input_latency = atoi (prop->value ());
 
                        if ((prop = grandchild->property ("output-latency")) == 0) {
                                continue;
                        }
-                       state.output_latency = atoi (prop->value ());
+                       state->output_latency = atoi (prop->value ());
 
                        if ((prop = grandchild->property ("input-channels")) == 0) {
                                continue;
                        }
-                       state.input_channels = atoi (prop->value ());
+                       state->input_channels = atoi (prop->value ());
 
                        if ((prop = grandchild->property ("output-channels")) == 0) {
                                continue;
                        }
-                       state.output_channels = atoi (prop->value ());
+                       state->output_channels = atoi (prop->value ());
 
                        if ((prop = grandchild->property ("active")) == 0) {
                                continue;
                        }
-                       state.active = string_is_affirmative (prop->value ());
+                       state->active = string_is_affirmative (prop->value ());
 
                        if ((prop = grandchild->property ("midi-option")) == 0) {
                                continue;
                        }
-                       state.midi_option = prop->value ();
+                       state->midi_option = prop->value ();
 
-                       state.midi_devices.clear();
+                       state->midi_devices.clear();
                        XMLNode* midinode;
-                       if ((midinode = find_named_node (*grandchild, "MIDIDevices")) != 0) {
+                       if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
                                const XMLNodeList mnc = midinode->children();
                                for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
                                        if ((*n)->property (X_("name")) == 0
@@ -1289,7 +1349,7 @@ EngineControl::set_state (const XMLNode& root)
                                                                atoi ((*n)->property (X_("input-latency"))->value ()),
                                                                atoi ((*n)->property (X_("output-latency"))->value ())
                                                                ));
-                                       state.midi_devices.push_back (ptr);
+                                       state->midi_devices.push_back (ptr);
                                }
                        }
 
@@ -1298,9 +1358,9 @@ EngineControl::set_state (const XMLNode& root)
                         * this can be removed again before release
                         */
                        for (StateList::iterator i = states.begin(); i != states.end();) {
-                               if ((*i).backend == state.backend &&
-                                               (*i).driver == state.driver &&
-                                               (*i).device == state.device) {
+                               if ((*i)->backend == state->backend &&
+                                               (*i)->driver == state->driver &&
+                                               (*i)->device == state->device) {
                                        i =  states.erase(i);
                                } else {
                                        ++i;
@@ -1314,18 +1374,33 @@ EngineControl::set_state (const XMLNode& root)
 
        /* now see if there was an active state and switch the setup to it */
 
+       // purge states of backend that are not available in this built
+       vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
+       vector<std::string> backend_names;
+
+       for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
+               backend_names.push_back((*i)->name);
+       }
+       for (StateList::iterator i = states.begin(); i != states.end();) {
+               if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
+                       i = states.erase(i);
+               } else {
+                       ++i;
+               }
+       }
+
        for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
 
-               if ((*i).active) {
+               if ((*i)->active) {
                        ignore_changes++;
-                       backend_combo.set_active_text ((*i).backend);
-                       driver_combo.set_active_text ((*i).driver);
-                       device_combo.set_active_text ((*i).device);
-                       sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
-                       buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
-                       input_latency.set_value ((*i).input_latency);
-                       output_latency.set_value ((*i).output_latency);
-                       midi_option_combo.set_active_text ((*i).midi_option);
+                       backend_combo.set_active_text ((*i)->backend);
+                       driver_combo.set_active_text ((*i)->driver);
+                       device_combo.set_active_text ((*i)->device);
+                       sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
+                       buffer_size_combo.set_active_text (bufsize_as_string ((*i)->buffer_size));
+                       input_latency.set_value ((*i)->input_latency);
+                       output_latency.set_value ((*i)->output_latency);
+                       midi_option_combo.set_active_text ((*i)->midi_option);
                        ignore_changes--;
                        break;
                }
@@ -1590,26 +1665,26 @@ EngineControl::post_push ()
         * necessary
         */
 
-       if (_have_control) {
-               State* state = get_saved_state_for_currently_displayed_backend_and_device ();
+       State state = get_saved_state_for_currently_displayed_backend_and_device ();
 
-               if (!state) {
-                       state = save_state ();
-                       assert (state);
-               }
+       if (!state) {
+               state = save_state ();
+               assert (state);
+       }
 
-               /* all off */
+       /* all off */
 
-               for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
-                       (*i).active = false;
-               }
+       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)
-                */
+       /* mark this one active (to be used next time the dialog is
+        * shown)
+        */
 
-               state->active = true;
+       state->active = true;
 
+       if (_have_control) { // XXX
                manage_control_app_sensitivity ();
        }
 
@@ -1796,6 +1871,7 @@ EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
 
        } else {
                if (lm_running) {
+                       end_latency_detection ();
                        ARDOUR::AudioEngine::instance()->stop_latency_detection();
                }
        }
@@ -1851,9 +1927,10 @@ EngineControl::check_audio_latency_measurement ()
        }
 
        if (solid) {
+               have_lm_results = true;
                end_latency_detection ();
                lm_use_button.set_sensitive (true);
-               have_lm_results = true;
+               return false;
        }
 
        lm_results.set_markup (string_compose (results_markup, buf));
@@ -1906,9 +1983,15 @@ EngineControl::check_midi_latency_measurement ()
        }
 
        if (solid) {
+               have_lm_results = true;
                end_latency_detection ();
                lm_use_button.set_sensitive (true);
-               have_lm_results = true;
+               return false;
+       } else if (mididm->processed () > 400) {
+               have_lm_results = false;
+               end_latency_detection ();
+               lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
+               return false;
        }
 
        lm_results.set_markup (string_compose (results_markup, buf));
@@ -1936,13 +2019,6 @@ EngineControl::start_latency_detection ()
                lm_output_channel_combo.set_sensitive (false);
                lm_running = true;
        }
-
-       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));
-       } else {
-               lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
-       }
 }
 
 void
@@ -1952,8 +2028,6 @@ EngineControl::end_latency_detection ()
        ARDOUR::AudioEngine::instance()->stop_latency_detection ();
        lm_measure_label.set_text (_("Measure"));
        if (!have_lm_results) {
-               lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
-       } else {
                lm_use_button.set_sensitive (false);
        }
        lm_input_channel_combo.set_sensitive (true);
@@ -2057,7 +2131,10 @@ EngineControl::connect_disconnect_click()
 void
 EngineControl::calibrate_audio_latency ()
 {
-       _measure_midi.reset();
+       _measure_midi.reset ();
+       have_lm_results = false;
+       lm_use_button.set_sensitive (false);
+       lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
        notebook.set_current_page (latency_tab);
 }
 
@@ -2065,6 +2142,9 @@ void
 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
 {
        _measure_midi = s;
+       have_lm_results = false;
+       lm_use_button.set_sensitive (false);
+       lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
        notebook.set_current_page (latency_tab);
 }