beginnings of a tab in Audio/MIDI setup to manage MIDI port functionality
[ardour.git] / gtk2_ardour / engine_dialog.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <exception>
21 #include <vector>
22 #include <cmath>
23 #include <map>
24
25 #include <boost/scoped_ptr.hpp>
26
27 #include <gtkmm/messagedialog.h>
28
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/unwind.h"
32 #include "pbd/failed_constructor.h"
33
34 #include <gtkmm/alignment.h>
35 #include <gtkmm/stock.h>
36 #include <gtkmm/notebook.h>
37 #include <gtkmm2ext/utils.h>
38
39 #include "ardour/audio_backend.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/mtdm.h"
42 #include "ardour/mididm.h"
43 #include "ardour/rc_configuration.h"
44 #include "ardour/types.h"
45 #include "ardour/profile.h"
46
47 #include "pbd/convert.h"
48 #include "pbd/error.h"
49
50 #include "opts.h"
51 #include "debug.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
55 #include "utils.h"
56 #include "pbd/i18n.h"
57
58 using namespace std;
59 using namespace Gtk;
60 using namespace Gtkmm2ext;
61 using namespace PBD;
62 using namespace Glib;
63 using namespace ARDOUR_UI_UTILS;
64
65 #define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
66
67 static const unsigned int midi_tab = 2;
68 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
69
70 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
71
72 EngineControl::EngineControl ()
73         : ArdourDialog (_("Audio/MIDI Setup"))
74         , engine_status ("")
75         , basic_packer (9, 4)
76         , input_latency_adjustment (0, 0, 99999, 1)
77         , input_latency (input_latency_adjustment)
78         , output_latency_adjustment (0, 0, 99999, 1)
79         , output_latency (output_latency_adjustment)
80         , input_channels_adjustment (0, 0, 256, 1)
81         , input_channels (input_channels_adjustment)
82         , output_channels_adjustment (0, 0, 256, 1)
83         , output_channels (output_channels_adjustment)
84         , ports_adjustment (128, 8, 1024, 1, 16)
85         , ports_spinner (ports_adjustment)
86         , control_app_button (_("Device Control Panel"))
87         , midi_devices_button (_("Midi Device Setup"))
88         , start_stop_button (_("Stop"))
89         , update_devices_button (_("Refresh Devices"))
90         , use_buffered_io_button (_("Use Buffered I/O"), ArdourButton::led_default_elements)
91         , lm_measure_label (_("Measure"))
92         , lm_use_button (_("Use results"))
93         , lm_back_button (_("Back to settings ... (ignore results)"))
94         , lm_button_audio (_("Calibrate Audio"))
95         , lm_table (12, 3)
96         , have_lm_results (false)
97         , lm_running (false)
98         , midi_back_button (_("Back to settings"))
99         , ignore_changes (0)
100         , ignore_device_changes (0)
101         , _desired_sample_rate (0)
102         , started_at_least_once (false)
103         , queue_device_changed (false)
104         , _have_control (true)
105         , block_signals(0)
106 {
107         using namespace Notebook_Helpers;
108         vector<string> backend_names;
109         Label* label;
110         AttachOptions xopt = AttachOptions (FILL|EXPAND);
111         int row;
112
113         set_name (X_("AudioMIDISetup"));
114
115         /* the backend combo is the one thing that is ALWAYS visible */
116
117         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
118
119         if (backends.empty()) {
120                 MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
121                 msg.run ();
122                 throw failed_constructor ();
123         }
124
125         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
126                 backend_names.push_back ((*b)->name);
127         }
128
129         set_popdown_strings (backend_combo, backend_names);
130
131         /* setup basic packing characteristics for the table used on the main
132          * tab of the notebook
133          */
134
135         basic_packer.set_spacings (6);
136         basic_packer.set_border_width (12);
137         basic_packer.set_homogeneous (false);
138
139         /* pack it in */
140
141         basic_hbox.pack_start (basic_packer, false, false);
142
143         /* latency measurement tab */
144
145         lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
146
147         row = 0;
148         lm_table.set_row_spacings (12);
149         lm_table.set_col_spacings (6);
150         lm_table.set_homogeneous (false);
151
152         lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
153         row++;
154
155         lm_preamble.set_width_chars (60);
156         lm_preamble.set_line_wrap (true);
157         lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
158
159         lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
160         row++;
161
162         Gtk::Label* preamble;
163         preamble = manage (new Label);
164         preamble->set_width_chars (60);
165         preamble->set_line_wrap (true);
166         preamble->set_markup (_("Select two channels below and connect them using a cable."));
167
168         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
169         row++;
170
171         label = manage (new Label (_("Output channel")));
172         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
173
174         Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
175         misc_align->add (lm_output_channel_combo);
176         lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
177         ++row;
178
179         label = manage (new Label (_("Input channel")));
180         lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
181
182         misc_align = manage (new Alignment (0.0, 0.5));
183         misc_align->add (lm_input_channel_combo);
184         lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
185         ++row;
186
187         lm_measure_label.set_padding (10, 10);
188         lm_measure_button.add (lm_measure_label);
189         lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
190         lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
191         lm_back_button_signal = lm_back_button.signal_clicked().connect(
192             sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
193
194         lm_use_button.set_sensitive (false);
195
196         /* Increase the default spacing around the labels of these three
197          * buttons
198          */
199
200         Gtk::Misc* l;
201
202         if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
203                 l->set_padding (10, 10);
204         }
205
206         if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
207                 l->set_padding (10, 10);
208         }
209
210         preamble = manage (new Label);
211         preamble->set_width_chars (60);
212         preamble->set_line_wrap (true);
213         preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
214         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
215         row++;
216
217         preamble = manage (new Label);
218         preamble->set_width_chars (60);
219         preamble->set_line_wrap (true);
220         preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
221         lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
222
223         ++row; // skip a row in the table
224         ++row; // skip a row in the table
225
226         lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227
228         ++row; // skip a row in the table
229         ++row; // skip a row in the table
230
231         lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
232         lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
233         lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
234
235         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
236
237         lm_vbox.set_border_width (12);
238         lm_vbox.pack_start (lm_table, false, false);
239
240         midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
241
242         midi_vbox.set_border_width (12);
243         midi_vbox.set_spacing (6);
244         midi_vbox.pack_start (midi_input_view);
245         midi_vbox.pack_start (midi_output_view);
246
247         /* pack it all up */
248
249         notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
250         notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
251         notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
252         notebook.set_border_width (12);
253
254         //notebook.set_show_tabs (false);
255         notebook.show_all ();
256
257         notebook.set_name ("SettingsNotebook");
258
259         /* packup the notebook */
260
261         get_vbox()->set_border_width (12);
262         get_vbox()->pack_start (notebook);
263
264         /* need a special function to print "all available channels" when the
265          * channel counts hit zero.
266          */
267
268         input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
269         output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
270
271         midi_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::configure_midi_devices));
272         midi_devices_button.set_name ("generic button");
273         midi_devices_button.set_can_focus(true);
274
275         control_app_button.signal_clicked.connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
276         control_app_button.set_name ("generic button");
277         control_app_button.set_can_focus(true);
278         manage_control_app_sensitivity ();
279
280         start_stop_button.signal_clicked.connect (mem_fun (*this, &EngineControl::start_stop_button_clicked));
281         start_stop_button.set_sensitive (false);
282         start_stop_button.set_name ("generic button");
283         start_stop_button.set_can_focus(true);
284
285         update_devices_button.signal_clicked.connect (mem_fun (*this, &EngineControl::update_devices_button_clicked));
286         update_devices_button.set_sensitive (false);
287         update_devices_button.set_name ("generic button");
288         update_devices_button.set_can_focus(true);
289
290         use_buffered_io_button.signal_clicked.connect (mem_fun (*this, &EngineControl::use_buffered_io_button_clicked));
291         use_buffered_io_button.set_sensitive (false);
292         use_buffered_io_button.set_name ("generic button");
293         use_buffered_io_button.set_can_focus(true);
294
295         cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
296         ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
297
298         /* Pick up any existing audio setup configuration, if appropriate */
299
300         XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
301
302         ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context());
303         ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
304         ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context());
305         ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (devicelist_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::device_list_changed, this), gui_context());
306
307         if (audio_setup) {
308                 if (!set_state (*audio_setup)) {
309                         set_default_state ();
310                 }
311         } else {
312                 set_default_state ();
313         }
314
315         update_sensitivity ();
316         connect_changed_signals ();
317
318         notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
319
320         connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
321
322         connect_disconnect_button.set_no_show_all();
323         use_buffered_io_button.set_no_show_all();
324         update_devices_button.set_no_show_all();
325         start_stop_button.set_no_show_all();
326         midi_devices_button.set_no_show_all();
327 }
328
329 void
330 EngineControl::connect_changed_signals ()
331 {
332         backend_combo_connection = backend_combo.signal_changed ().connect (
333             sigc::mem_fun (*this, &EngineControl::backend_changed));
334         driver_combo_connection = driver_combo.signal_changed ().connect (
335             sigc::mem_fun (*this, &EngineControl::driver_changed));
336         sample_rate_combo_connection = sample_rate_combo.signal_changed ().connect (
337             sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
338         buffer_size_combo_connection = buffer_size_combo.signal_changed ().connect (
339             sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
340         nperiods_combo_connection = nperiods_combo.signal_changed ().connect (
341             sigc::mem_fun (*this, &EngineControl::nperiods_changed));
342         device_combo_connection = device_combo.signal_changed ().connect (
343             sigc::mem_fun (*this, &EngineControl::device_changed));
344         midi_option_combo_connection = midi_option_combo.signal_changed ().connect (
345             sigc::mem_fun (*this, &EngineControl::midi_option_changed));
346
347         input_device_combo_connection = input_device_combo.signal_changed ().connect (
348             sigc::mem_fun (*this, &EngineControl::input_device_changed));
349         output_device_combo_connection = output_device_combo.signal_changed ().connect (
350             sigc::mem_fun (*this, &EngineControl::output_device_changed));
351
352         input_latency_connection = input_latency.signal_changed ().connect (
353             sigc::mem_fun (*this, &EngineControl::parameter_changed));
354         output_latency_connection = output_latency.signal_changed ().connect (
355             sigc::mem_fun (*this, &EngineControl::parameter_changed));
356         input_channels_connection = input_channels.signal_changed ().connect (
357             sigc::mem_fun (*this, &EngineControl::parameter_changed));
358         output_channels_connection = output_channels.signal_changed ().connect (
359             sigc::mem_fun (*this, &EngineControl::parameter_changed));
360 }
361
362 void
363 EngineControl::block_changed_signals ()
364 {
365         if (block_signals++ == 0) {
366                 DEBUG_ECONTROL ("Blocking changed signals");
367                 backend_combo_connection.block ();
368                 driver_combo_connection.block ();
369                 sample_rate_combo_connection.block ();
370                 buffer_size_combo_connection.block ();
371                 nperiods_combo_connection.block ();
372                 device_combo_connection.block ();
373                 input_device_combo_connection.block ();
374                 output_device_combo_connection.block ();
375                 midi_option_combo_connection.block ();
376                 input_latency_connection.block ();
377                 output_latency_connection.block ();
378                 input_channels_connection.block ();
379                 output_channels_connection.block ();
380         }
381 }
382
383 void
384 EngineControl::unblock_changed_signals ()
385 {
386         if (--block_signals == 0) {
387                 DEBUG_ECONTROL ("Unblocking changed signals");
388                 backend_combo_connection.unblock ();
389                 driver_combo_connection.unblock ();
390                 sample_rate_combo_connection.unblock ();
391                 buffer_size_combo_connection.unblock ();
392                 nperiods_combo_connection.unblock ();
393                 device_combo_connection.unblock ();
394                 input_device_combo_connection.unblock ();
395                 output_device_combo_connection.unblock ();
396                 midi_option_combo_connection.unblock ();
397                 input_latency_connection.unblock ();
398                 output_latency_connection.unblock ();
399                 input_channels_connection.unblock ();
400                 output_channels_connection.unblock ();
401         }
402 }
403
404 EngineControl::SignalBlocker::SignalBlocker (EngineControl& engine_control,
405                                              const std::string& reason)
406     : ec (engine_control)
407     , m_reason (reason)
408 {
409         DEBUG_ECONTROL (string_compose ("SignalBlocker: %1", m_reason));
410         ec.block_changed_signals ();
411 }
412
413 EngineControl::SignalBlocker::~SignalBlocker ()
414 {
415         DEBUG_ECONTROL (string_compose ("~SignalBlocker: %1", m_reason));
416         ec.unblock_changed_signals ();
417 }
418
419 void
420 EngineControl::on_show ()
421 {
422         ArdourDialog::on_show ();
423         if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
424                 // re-check _have_control (jackd running) see #6041
425                 backend_changed ();
426         }
427         device_changed ();
428         ok_button->grab_focus();
429 }
430
431 bool
432 EngineControl::try_autostart ()
433 {
434         if (!start_stop_button.get_sensitive()) {
435                 return false;
436         }
437         if (ARDOUR::AudioEngine::instance()->running()) {
438                 return true;
439         }
440         return start_engine ();
441 }
442
443 bool
444 EngineControl::start_engine ()
445 {
446         if (push_state_to_backend(true) != 0) {
447                 MessageDialog msg(*this,
448                                   ARDOUR::AudioEngine::instance()->get_last_backend_error());
449                 msg.run();
450                 return false;
451         }
452         return true;
453 }
454
455 bool
456 EngineControl::stop_engine (bool for_latency)
457 {
458         if (ARDOUR::AudioEngine::instance()->stop(for_latency)) {
459                 MessageDialog msg(*this,
460                                   ARDOUR::AudioEngine::instance()->get_last_backend_error());
461                 msg.run();
462                 return false;
463         }
464         return true;
465 }
466
467 void
468 EngineControl::on_response (int response_id)
469 {
470         ArdourDialog::on_response (response_id);
471
472         switch (response_id) {
473         case RESPONSE_OK:
474                 if (!start_engine()) {
475                         return;
476                 } else {
477                         hide();
478                 }
479 #ifdef PLATFORM_WINDOWS
480
481                 // But if there's no session open, this can produce
482                 // a long gap when nothing appears to be happening.
483                 // Let's show the splash image while we're waiting.
484                 if (!ARDOUR_COMMAND_LINE::no_splash) {
485                         if (ARDOUR_UI::instance()) {
486                                 if (!ARDOUR_UI::instance()->session_loaded) {
487                                         ARDOUR_UI::instance()->show_splash();
488                                 }
489                         }
490                 }
491 #endif
492                 break;
493         case RESPONSE_DELETE_EVENT: {
494                 GdkEventButton ev;
495                 ev.type = GDK_BUTTON_PRESS;
496                 ev.button = 1;
497                 on_delete_event((GdkEventAny*)&ev);
498                 break;
499         }
500         case RESPONSE_CANCEL:
501                 if (ARDOUR_UI::instance() && ARDOUR_UI::instance()->session_loaded) {
502                         ARDOUR_UI::instance()->check_audioengine(*this);
503                 }
504         // fall through
505         default:
506                 hide();
507         }
508 }
509
510 void
511 EngineControl::build_notebook ()
512 {
513         Label* label;
514         AttachOptions xopt = AttachOptions (FILL|EXPAND);
515
516         /* clear the table */
517
518         Gtkmm2ext::container_clear (basic_vbox);
519         Gtkmm2ext::container_clear (basic_packer);
520
521         if (control_app_button.get_parent()) {
522                 control_app_button.get_parent()->remove (control_app_button);
523         }
524
525         label = manage (left_aligned_label (_("Audio System:")));
526         basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
527         basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
528
529         basic_packer.attach (engine_status, 2, 3, 0, 1, xopt, (AttachOptions) 0);
530         engine_status.show();
531
532         basic_packer.attach (start_stop_button, 3, 4, 0, 1, xopt, xopt);
533         basic_packer.attach (update_devices_button, 3, 4, 1, 2, xopt, xopt);
534         basic_packer.attach (use_buffered_io_button, 3, 4, 2, 3, xopt, xopt);
535
536         lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
537         lm_button_audio.set_name ("generic button");
538         lm_button_audio.set_can_focus(true);
539
540         if (_have_control) {
541                 build_full_control_notebook ();
542         } else {
543                 build_no_control_notebook ();
544         }
545
546         basic_vbox.pack_start (basic_hbox, false, false);
547
548         {
549                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
550                 basic_vbox.show_all ();
551         }
552 }
553
554 void
555 EngineControl::build_full_control_notebook ()
556 {
557         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
558         assert (backend);
559
560         using namespace Notebook_Helpers;
561         Label* label;
562         vector<string> strings;
563         AttachOptions xopt = AttachOptions (FILL|EXPAND);
564         int row = 1; // row zero == backend combo
565
566         /* start packing it up */
567
568         if (backend->requires_driver_selection()) {
569                 label = manage (left_aligned_label (_("Driver:")));
570                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
571                 basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
572                 row++;
573         }
574
575         if (backend->use_separate_input_and_output_devices()) {
576                 label = manage (left_aligned_label (_("Input Device:")));
577                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
578                 basic_packer.attach (input_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
579                 row++;
580                 label = manage (left_aligned_label (_("Output Device:")));
581                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
582                 basic_packer.attach (output_device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
583                 row++;
584                 // reset so it isn't used in state comparisons
585                 device_combo.set_active_text ("");
586         } else {
587                 label = manage (left_aligned_label (_("Device:")));
588                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
589                 basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
590                 row++;
591                 // reset these so they don't get used in state comparisons
592                 input_device_combo.set_active_text ("");
593                 output_device_combo.set_active_text ("");
594         }
595
596         label = manage (left_aligned_label (_("Sample rate:")));
597         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
598         basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
599         row++;
600
601
602         label = manage (left_aligned_label (_("Buffer size:")));
603         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
604         basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
605         buffer_size_duration_label.set_alignment (0.0); /* left-align */
606         basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
607
608         int ctrl_btn_span = 1;
609         if (backend->can_set_period_size ()) {
610                 row++;
611                 label = manage (left_aligned_label (_("Periods:")));
612                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
613                 basic_packer.attach (nperiods_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
614                 ++ctrl_btn_span;
615         }
616
617         /* button spans 2 or 3 rows */
618
619         basic_packer.attach (control_app_button, 3, 4, row - ctrl_btn_span, row + 1, xopt, xopt);
620         row++;
621
622         input_channels.set_name ("InputChannels");
623         input_channels.set_flags (Gtk::CAN_FOCUS);
624         input_channels.set_digits (0);
625         input_channels.set_wrap (false);
626         output_channels.set_editable (true);
627
628         if (!ARDOUR::Profile->get_mixbus()) {
629                 label = manage (left_aligned_label (_("Input Channels:")));
630                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
631                 basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
632                 ++row;
633         }
634
635         output_channels.set_name ("OutputChannels");
636         output_channels.set_flags (Gtk::CAN_FOCUS);
637         output_channels.set_digits (0);
638         output_channels.set_wrap (false);
639         output_channels.set_editable (true);
640
641         if (!ARDOUR::Profile->get_mixbus()) {
642                 label = manage (left_aligned_label (_("Output Channels:")));
643                 basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
644                 basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
645                 ++row;
646         }
647
648         input_latency.set_name ("InputLatency");
649         input_latency.set_flags (Gtk::CAN_FOCUS);
650         input_latency.set_digits (0);
651         input_latency.set_wrap (false);
652         input_latency.set_editable (true);
653
654         label = manage (left_aligned_label (_("Hardware input latency:")));
655         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
656         basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
657         label = manage (left_aligned_label (_("samples")));
658         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
659         ++row;
660
661         output_latency.set_name ("OutputLatency");
662         output_latency.set_flags (Gtk::CAN_FOCUS);
663         output_latency.set_digits (0);
664         output_latency.set_wrap (false);
665         output_latency.set_editable (true);
666
667         label = manage (left_aligned_label (_("Hardware output latency:")));
668         basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
669         basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
670         label = manage (left_aligned_label (_("samples")));
671         basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
672
673         /* button spans 2 rows */
674
675         basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
676         ++row;
677
678         label = manage (left_aligned_label (_("MIDI System:")));
679         basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
680         basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
681         basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
682         row++;
683 }
684
685 void
686 EngineControl::build_no_control_notebook ()
687 {
688         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
689         assert (backend);
690
691         using namespace Notebook_Helpers;
692         Label* label;
693         vector<string> strings;
694         AttachOptions xopt = AttachOptions (FILL|EXPAND);
695         int row = 1; // row zero == backend combo
696         const string msg = string_compose (_("%1 is already running. %2 will connect to it and use the existing settings."), backend->name(), PROGRAM_NAME);
697
698         label = manage (new Label);
699         label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
700         basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
701         row++;
702
703         if (backend->can_change_sample_rate_when_running()) {
704                 label = manage (left_aligned_label (_("Sample rate:")));
705                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
706                 basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
707                 row++;
708         }
709
710         if (backend->can_change_buffer_size_when_running()) {
711                 label = manage (left_aligned_label (_("Buffer size:")));
712                 basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
713                 basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
714                 buffer_size_duration_label.set_alignment (0.0); /* left-align */
715                 basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
716                 row++;
717         }
718
719         basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
720         row++;
721 }
722
723 EngineControl::~EngineControl ()
724 {
725         ignore_changes = true;
726 }
727
728 void
729 EngineControl::disable_latency_tab ()
730 {
731         vector<string> empty;
732         set_popdown_strings (lm_output_channel_combo, empty);
733         set_popdown_strings (lm_input_channel_combo, empty);
734         lm_measure_button.set_sensitive (false);
735         lm_use_button.set_sensitive (false);
736 }
737
738 void
739 EngineControl::enable_latency_tab ()
740 {
741         vector<string> outputs;
742         vector<string> inputs;
743
744         ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
745         ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
746         ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
747
748         if (!ARDOUR::AudioEngine::instance()->running()) {
749                 MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
750                 notebook.set_current_page (0);
751                 msg.run ();
752                 return;
753         }
754         else if (inputs.empty() || outputs.empty()) {
755                 MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
756                 notebook.set_current_page (0);
757                 msg.run ();
758                 return;
759         }
760
761         lm_back_button_signal.disconnect();
762         if (_measure_midi) {
763                 lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
764                 lm_preamble.hide ();
765         } else {
766                 lm_back_button_signal = lm_back_button.signal_clicked().connect(
767                     sigc::mem_fun(*this, &EngineControl::latency_back_button_clicked));
768                 lm_preamble.show ();
769         }
770
771         set_popdown_strings (lm_output_channel_combo, outputs);
772         lm_output_channel_combo.set_active_text (outputs.front());
773         lm_output_channel_combo.set_sensitive (true);
774
775         set_popdown_strings (lm_input_channel_combo, inputs);
776         lm_input_channel_combo.set_active_text (inputs.front());
777         lm_input_channel_combo.set_sensitive (true);
778
779         lm_measure_button.set_sensitive (true);
780 }
781
782 void
783 EngineControl::setup_midi_tab_for_backend ()
784 {
785 }
786
787 void
788 EngineControl::refill_midi_ports (bool for_input)
789 {
790         using namespace ARDOUR;
791
792         std::vector<string> ports;
793
794         AudioEngine::instance()->get_ports (string(), DataType::MIDI, for_input ? IsInput : IsOutput, ports);
795
796         Glib::RefPtr<ListStore> model = Gtk::ListStore::create (midi_port_columns);
797
798         for (vector<string>::const_iterator s = ports.begin(); s != ports.end(); ++s) {
799
800                 if (AudioEngine::instance()->port_is_mine (*s)) {
801                         continue;
802                 }
803
804                 TreeModel::Row row = *(model->append());
805
806                 string pretty = AudioEngine::instance()->get_pretty_name_by_name (*s);
807                 cerr << "pretty for " << *s << " = " << pretty << endl;
808                 row[midi_port_columns.name] = *s;
809                 row[midi_port_columns.pretty_name] = (pretty.empty() ? *s : pretty);
810                 row[midi_port_columns.in_use] = true;
811                 row[midi_port_columns.music_data] = true;
812                 row[midi_port_columns.control_data] = true;
813         }
814
815         Gtk::TreeView& view (for_input ? midi_input_view : midi_output_view);
816         int pretty_name_column;
817         view.set_model (model);
818         view.append_column (_("Name"), midi_port_columns.name);
819         pretty_name_column = view.append_column (_("Pretty Name"), midi_port_columns.pretty_name) - 1;
820         view.append_column (_("Use"), midi_port_columns.in_use);
821         view.append_column (_("Music Data"), midi_port_columns.music_data);
822         view.append_column (_("Control Data"), midi_port_columns.control_data);
823
824         CellRendererText* pretty_name_cell = dynamic_cast<CellRendererText*> (view.get_column_cell_renderer (pretty_name_column));
825         pretty_name_cell->property_editable() = true;
826         pretty_name_cell->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::pretty_name_edit), &view));
827 }
828
829 void
830 EngineControl::pretty_name_edit (std::string const & path, string const & new_text, Gtk::TreeView* view)
831 {
832         TreeIter iter = view->get_model()->get_iter (path);
833
834         if (!iter) {
835                 return;
836         }
837
838         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
839         if (backend) {
840                 ARDOUR::PortEngine::PortHandle ph = backend->get_port_by_name ((*iter)[midi_port_columns.name]);
841                 if (ph) {
842                         backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", new_text, "");
843                         (*iter)[midi_port_columns.pretty_name] = new_text;
844                 }
845         }
846 }
847
848 void
849 EngineControl::update_sensitivity ()
850 {
851         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
852         if (!backend) {
853                 ok_button->set_sensitive (false);
854                 start_stop_button.set_sensitive (false);
855                 return;
856         }
857
858         bool valid = true;
859         size_t devices_available = 0;
860
861         if (backend->use_separate_input_and_output_devices ()) {
862                 devices_available += get_popdown_string_count (input_device_combo);
863                 devices_available += get_popdown_string_count (output_device_combo);
864         } else {
865                 devices_available += get_popdown_string_count (device_combo);
866         }
867
868         if (devices_available == 0) {
869                 valid = false;
870                 input_latency.set_sensitive (false);
871                 output_latency.set_sensitive (false);
872                 input_channels.set_sensitive (false);
873                 output_channels.set_sensitive (false);
874         } else {
875                 input_latency.set_sensitive (true);
876                 output_latency.set_sensitive (true);
877                 input_channels.set_sensitive (true);
878                 output_channels.set_sensitive (true);
879         }
880
881         if (get_popdown_string_count (buffer_size_combo) > 0) {
882                 if (!ARDOUR::AudioEngine::instance()->running()) {
883                         buffer_size_combo.set_sensitive (valid);
884                 } else if (backend->can_change_sample_rate_when_running()) {
885                         buffer_size_combo.set_sensitive (valid || !_have_control);
886                 } else {
887 #if 1
888                         /* TODO
889                          * Currently there is no way to manually stop the
890                          * engine in order to re-configure it.
891                          * This needs to remain sensitive for now.
892                          *
893                          * (it's also handy to implicily
894                          * re-start the engine)
895                          */
896                         buffer_size_combo.set_sensitive (true);
897 #else
898                         buffer_size_combo.set_sensitive (false);
899 #endif
900                 }
901         } else {
902                 buffer_size_combo.set_sensitive (false);
903                 valid = false;
904         }
905
906         if (get_popdown_string_count (sample_rate_combo) > 0) {
907                 bool allow_to_set_rate = false;
908                 if (!ARDOUR::AudioEngine::instance()->running()) {
909                         if (!ARDOUR_UI::instance()->session_loaded) {
910                                 // engine is not running, no session loaded -> anything goes.
911                                 allow_to_set_rate = true;
912                         } else if (_desired_sample_rate > 0 && get_rate () != _desired_sample_rate) {
913                                 // only allow to change if the current setting is not the native session rate.
914                                 allow_to_set_rate = true;
915                         }
916                 }
917                 sample_rate_combo.set_sensitive (allow_to_set_rate);
918         } else {
919                 sample_rate_combo.set_sensitive (false);
920                 valid = false;
921         }
922
923         if (get_popdown_string_count (nperiods_combo) > 0) {
924                 if (!ARDOUR::AudioEngine::instance()->running()) {
925                         nperiods_combo.set_sensitive (true);
926                 } else {
927                         nperiods_combo.set_sensitive (false);
928                 }
929         } else {
930                 nperiods_combo.set_sensitive (false);
931         }
932
933         if (_have_control) {
934                 start_stop_button.set_sensitive(true);
935                 start_stop_button.show();
936                 if (ARDOUR::AudioEngine::instance()->running()) {
937                         start_stop_button.set_text("Stop");
938                         update_devices_button.set_sensitive(false);
939                         use_buffered_io_button.set_sensitive(false);
940                 } else {
941                         if (backend->can_request_update_devices()) {
942                                 update_devices_button.show();
943                         } else {
944                                 update_devices_button.hide();
945                         }
946                         if (backend->can_use_buffered_io()) {
947                                 use_buffered_io_button.show();
948                         } else {
949                                 use_buffered_io_button.hide();
950                         }
951                         start_stop_button.set_text("Start");
952                         update_devices_button.set_sensitive(true);
953                         use_buffered_io_button.set_sensitive(true);
954                 }
955         } else {
956                 update_devices_button.set_sensitive(false);
957                 update_devices_button.hide();
958                 use_buffered_io_button.set_sensitive(false);
959                 use_buffered_io_button.hide();
960                 start_stop_button.set_sensitive(false);
961                 start_stop_button.hide();
962         }
963
964         if (ARDOUR::AudioEngine::instance()->running() && _have_control) {
965                 input_device_combo.set_sensitive (false);
966                 output_device_combo.set_sensitive (false);
967                 device_combo.set_sensitive (false);
968                 driver_combo.set_sensitive (false);
969         } else {
970                 input_device_combo.set_sensitive (true);
971                 output_device_combo.set_sensitive (true);
972                 device_combo.set_sensitive (true);
973                 if (backend->requires_driver_selection() && get_popdown_string_count(driver_combo) > 0) {
974                         driver_combo.set_sensitive (true);
975                 } else {
976                         driver_combo.set_sensitive (false);
977                 }
978         }
979
980         if (valid || !_have_control) {
981                 ok_button->set_sensitive (true);
982         } else {
983                 ok_button->set_sensitive (false);
984         }
985 }
986
987 void
988 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
989         if (for_input) {
990                 device->input_latency = a->get_value();
991         } else {
992                 device->output_latency = a->get_value();
993         }
994 }
995
996 void
997 EngineControl::midi_device_enabled_toggled (ArdourButton *b, MidiDeviceSettings device) {
998         b->set_active (!b->get_active());
999         device->enabled = b->get_active();
1000         refresh_midi_display(device->name);
1001 }
1002
1003 void
1004 EngineControl::refresh_midi_display (std::string focus)
1005 {
1006         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1007         assert (backend);
1008
1009         int row  = 0;
1010         AttachOptions xopt = AttachOptions (FILL|EXPAND);
1011         Gtk::Label* l;
1012
1013         Gtkmm2ext::container_clear (midi_device_table);
1014
1015         midi_device_table.set_spacings (6);
1016
1017         l = manage (new Label);
1018         l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
1019         midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
1020         l->set_alignment (0.5, 0.5);
1021         row++;
1022         l->show ();
1023
1024         l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
1025         midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
1026         l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
1027         midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
1028         row++;
1029         l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
1030         midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
1031         l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
1032         midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
1033         row++;
1034
1035         for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1036                 ArdourButton *m;
1037                 Gtk::Button* b;
1038                 Gtk::Adjustment *a;
1039                 Gtk::SpinButton *s;
1040                 bool enabled = (*p)->enabled;
1041
1042                 m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
1043                 m->set_name ("midi device");
1044                 m->set_can_focus (Gtk::CAN_FOCUS);
1045                 m->add_events (Gdk::BUTTON_RELEASE_MASK);
1046                 m->set_active (enabled);
1047                 m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
1048                 midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
1049                 if ((*p)->name == focus) {
1050                         m->grab_focus();
1051                 }
1052
1053                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1054                 s = manage (new Gtk::SpinButton (*a));
1055                 a->set_value ((*p)->input_latency);
1056                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
1057                 s->set_sensitive (_can_set_midi_latencies && enabled);
1058                 midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
1059
1060                 a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
1061                 s = manage (new Gtk::SpinButton (*a));
1062                 a->set_value ((*p)->output_latency);
1063                 s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
1064                 s->set_sensitive (_can_set_midi_latencies && enabled);
1065                 midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
1066
1067                 b = manage (new Button (_("Calibrate")));
1068                 b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
1069                 b->set_sensitive (_can_set_midi_latencies && enabled);
1070                 midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
1071
1072                 row++;
1073         }
1074 }
1075
1076 void
1077 EngineControl::backend_changed ()
1078 {
1079         cerr << "BE\n";
1080         SignalBlocker blocker (*this, "backend_changed");
1081         string backend_name = backend_combo.get_active_text();
1082         boost::shared_ptr<ARDOUR::AudioBackend> backend;
1083
1084         if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, downcase (std::string(PROGRAM_NAME)), ""))) {
1085                 /* eh? setting the backend failed... how ? */
1086                 /* A: stale config contains a backend that does not exist in current build */
1087                 return;
1088         }
1089
1090         DEBUG_ECONTROL (string_compose ("Backend name: %1", backend_name));
1091
1092         _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
1093
1094         build_notebook ();
1095         cerr << "ME\n";
1096         setup_midi_tab_for_backend ();
1097         _midi_devices.clear();
1098
1099         if (backend->requires_driver_selection()) {
1100                 if (set_driver_popdown_strings ()) {
1101                         driver_changed ();
1102                 }
1103         } else {
1104                 /* this will change the device text which will cause a call to
1105                  * device changed which will set up parameters
1106                  */
1107                 list_devices ();
1108         }
1109
1110         update_midi_options ();
1111
1112         connect_disconnect_button.hide();
1113
1114         midi_option_changed();
1115
1116         started_at_least_once = false;
1117
1118         /* changing the backend implies stopping the engine
1119          * ARDOUR::AudioEngine() may or may not emit this signal
1120          * depending on previous engine state
1121          */
1122         engine_stopped (); // set "active/inactive"
1123
1124         if (!_have_control) {
1125                 // set settings from backend that we do have control over
1126                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
1127         }
1128
1129         if (_have_control && !ignore_changes) {
1130                 // set driver & devices
1131                 State state = get_matching_state (backend_combo.get_active_text());
1132                 if (state) {
1133                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1134                         set_current_state (state);
1135                 }
1136         }
1137
1138         if (!ignore_changes) {
1139                 maybe_display_saved_state ();
1140         }
1141 }
1142
1143 void
1144 EngineControl::update_midi_options ()
1145 {
1146         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1147         vector<string> midi_options = backend->enumerate_midi_options();
1148
1149         if (midi_options.size() == 1) {
1150                 /* only contains the "none" option */
1151                 midi_option_combo.set_sensitive (false);
1152         } else {
1153                 if (_have_control) {
1154                         set_popdown_strings (midi_option_combo, midi_options);
1155                         midi_option_combo.set_active_text (midi_options.front());
1156                         midi_option_combo.set_sensitive (true);
1157                 } else {
1158                         midi_option_combo.set_sensitive (false);
1159                 }
1160         }
1161 }
1162
1163 bool
1164 EngineControl::print_channel_count (Gtk::SpinButton* sb)
1165 {
1166         if (ARDOUR::Profile->get_mixbus()) {
1167                 return true;
1168         }
1169
1170         uint32_t cnt = (uint32_t) sb->get_value();
1171         if (cnt == 0) {
1172                 sb->set_text (_("all available channels"));
1173         } else {
1174                 char buf[32];
1175                 snprintf (buf, sizeof (buf), "%d", cnt);
1176                 sb->set_text (buf);
1177         }
1178         return true;
1179 }
1180
1181 // @return true if there are drivers available
1182 bool
1183 EngineControl::set_driver_popdown_strings ()
1184 {
1185         DEBUG_ECONTROL ("set_driver_popdown_strings");
1186         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1187         vector<string> drivers = backend->enumerate_drivers();
1188
1189         if (drivers.empty ()) {
1190                 // This is an error...?
1191                 return false;
1192         }
1193
1194         string current_driver = backend->driver_name ();
1195
1196         DEBUG_ECONTROL (string_compose ("backend->driver_name: %1", current_driver));
1197
1198         if (std::find (drivers.begin (), drivers.end (), current_driver) ==
1199             drivers.end ()) {
1200
1201                 current_driver = drivers.front ();
1202         }
1203
1204         set_popdown_strings (driver_combo, drivers);
1205         DEBUG_ECONTROL (
1206             string_compose ("driver_combo.set_active_text: %1", current_driver));
1207         driver_combo.set_active_text (current_driver);
1208         return true;
1209 }
1210
1211 std::string
1212 EngineControl::get_default_device(const string& current_device_name,
1213                                   const vector<string>& available_devices)
1214 {
1215         // If the current device is available, use it as default
1216         if (std::find (available_devices.begin (),
1217                        available_devices.end (),
1218                        current_device_name) != available_devices.end ()) {
1219
1220                 return current_device_name;
1221         }
1222
1223         using namespace ARDOUR;
1224
1225         string default_device_name =
1226             AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault);
1227
1228         vector<string>::const_iterator i;
1229
1230         // If there is a "Default" device available, use it
1231         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1232                 if (*i == default_device_name) {
1233                         return *i;
1234                 }
1235         }
1236
1237         string none_device_name =
1238             AudioBackend::get_standard_device_name(AudioBackend::DeviceNone);
1239
1240         // Use the first device that isn't "None"
1241         for (i = available_devices.begin(); i != available_devices.end(); ++i) {
1242                 if (*i != none_device_name) {
1243                         return *i;
1244                 }
1245         }
1246
1247         // Use "None" if there are no other available
1248         return available_devices.front();
1249 }
1250
1251 // @return true if there are devices available
1252 bool
1253 EngineControl::set_device_popdown_strings ()
1254 {
1255         DEBUG_ECONTROL ("set_device_popdown_strings");
1256         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1257         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
1258
1259         /* NOTE: Ardour currently does not display the "available" field of the
1260          * returned devices.
1261          *
1262          * Doing so would require a different GUI widget than the combo
1263          * box/popdown that we currently use, since it has no way to list
1264          * items that are not selectable. Something more like a popup menu,
1265          * which could have unselectable items, would be appropriate.
1266          */
1267
1268         vector<string> available_devices;
1269
1270         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1271                 available_devices.push_back (i->name);
1272         }
1273
1274         if (available_devices.empty ()) {
1275                 return false;
1276         }
1277
1278         set_popdown_strings (device_combo, available_devices);
1279
1280         std::string default_device =
1281             get_default_device(backend->device_name(), available_devices);
1282
1283         DEBUG_ECONTROL (
1284             string_compose ("set device_combo active text: %1", default_device));
1285
1286         device_combo.set_active_text(default_device);
1287         return true;
1288 }
1289
1290 // @return true if there are input devices available
1291 bool
1292 EngineControl::set_input_device_popdown_strings ()
1293 {
1294         DEBUG_ECONTROL ("set_input_device_popdown_strings");
1295         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1296         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_input_devices ();
1297
1298         vector<string> available_devices;
1299
1300         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1301                 available_devices.push_back (i->name);
1302         }
1303
1304         if (available_devices.empty()) {
1305                 return false;
1306         }
1307
1308         set_popdown_strings (input_device_combo, available_devices);
1309
1310         std::string default_device =
1311             get_default_device(backend->input_device_name(), available_devices);
1312
1313         DEBUG_ECONTROL (
1314             string_compose ("set input_device_combo active text: %1", default_device));
1315         input_device_combo.set_active_text(default_device);
1316         return true;
1317 }
1318
1319 // @return true if there are output devices available
1320 bool
1321 EngineControl::set_output_device_popdown_strings ()
1322 {
1323         DEBUG_ECONTROL ("set_output_device_popdown_strings");
1324         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1325         vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_output_devices ();
1326
1327         vector<string> available_devices;
1328
1329         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
1330                 available_devices.push_back (i->name);
1331         }
1332
1333         if (available_devices.empty()) {
1334                 return false;
1335         }
1336
1337         set_popdown_strings (output_device_combo, available_devices);
1338
1339         std::string default_device =
1340             get_default_device(backend->output_device_name(), available_devices);
1341
1342         DEBUG_ECONTROL (
1343             string_compose ("set output_device_combo active text: %1", default_device));
1344         output_device_combo.set_active_text(default_device);
1345         return true;
1346 }
1347
1348 void
1349 EngineControl::list_devices ()
1350 {
1351         DEBUG_ECONTROL ("list_devices");
1352         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1353         assert (backend);
1354
1355         /* now fill out devices, mark sample rates, buffer sizes insensitive */
1356
1357         bool devices_available = false;
1358
1359         if (backend->use_separate_input_and_output_devices ()) {
1360                 bool input_devices_available = set_input_device_popdown_strings ();
1361                 bool output_devices_available = set_output_device_popdown_strings ();
1362                 devices_available = input_devices_available || output_devices_available;
1363         } else {
1364                 devices_available = set_device_popdown_strings ();
1365         }
1366
1367         if (devices_available) {
1368                 device_changed ();
1369         } else {
1370                 device_combo.clear();
1371                 input_device_combo.clear();
1372                 output_device_combo.clear();
1373         }
1374         update_sensitivity ();
1375 }
1376
1377 void
1378 EngineControl::driver_changed ()
1379 {
1380         SignalBlocker blocker (*this, "driver_changed");
1381         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1382         assert (backend);
1383
1384         backend->set_driver (driver_combo.get_active_text());
1385         list_devices ();
1386
1387         // TODO load LRU device(s) for backend + driver combo
1388
1389         if (!ignore_changes) {
1390                 maybe_display_saved_state ();
1391         }
1392 }
1393
1394 vector<float>
1395 EngineControl::get_sample_rates_for_all_devices ()
1396 {
1397         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1398             ARDOUR::AudioEngine::instance ()->current_backend ();
1399         vector<float> all_rates;
1400
1401         if (backend->use_separate_input_and_output_devices ()) {
1402                 all_rates = backend->available_sample_rates2 (get_input_device_name (), get_output_device_name ());
1403         } else {
1404                 all_rates = backend->available_sample_rates (get_device_name ());
1405         }
1406         return all_rates;
1407 }
1408
1409 vector<float>
1410 EngineControl::get_default_sample_rates ()
1411 {
1412         vector<float> rates;
1413         rates.push_back (8000.0f);
1414         rates.push_back (16000.0f);
1415         rates.push_back (32000.0f);
1416         rates.push_back (44100.0f);
1417         rates.push_back (48000.0f);
1418         rates.push_back (88200.0f);
1419         rates.push_back (96000.0f);
1420         rates.push_back (192000.0f);
1421         rates.push_back (384000.0f);
1422         return rates;
1423 }
1424
1425 void
1426 EngineControl::set_samplerate_popdown_strings ()
1427 {
1428         DEBUG_ECONTROL ("set_samplerate_popdown_strings");
1429         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1430         string desired;
1431         vector<float> sr;
1432         vector<string> s;
1433
1434         if (_have_control) {
1435                 sr = get_sample_rates_for_all_devices ();
1436         } else {
1437                 sr = get_default_sample_rates ();
1438         }
1439
1440         for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
1441                 s.push_back (rate_as_string (*x));
1442                 if (*x == _desired_sample_rate) {
1443                         desired = s.back();
1444                 }
1445         }
1446
1447         set_popdown_strings (sample_rate_combo, s);
1448
1449         if (!s.empty()) {
1450                 if (ARDOUR::AudioEngine::instance()->running()) {
1451                         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
1452                 }
1453                 else if (desired.empty ()) {
1454                         float new_active_sr = backend->default_sample_rate ();
1455
1456                         if (std::find (sr.begin (), sr.end (), new_active_sr) == sr.end ()) {
1457                                 new_active_sr = sr.front ();
1458                         }
1459
1460                         sample_rate_combo.set_active_text (rate_as_string (new_active_sr));
1461                 } else {
1462                         sample_rate_combo.set_active_text (desired);
1463                 }
1464
1465         }
1466         update_sensitivity ();
1467 }
1468
1469 vector<uint32_t>
1470 EngineControl::get_buffer_sizes_for_all_devices ()
1471 {
1472         boost::shared_ptr<ARDOUR::AudioBackend> backend =
1473             ARDOUR::AudioEngine::instance ()->current_backend ();
1474         vector<uint32_t> all_sizes;
1475
1476         if (backend->use_separate_input_and_output_devices ()) {
1477                 all_sizes = backend->available_buffer_sizes2 (get_input_device_name (), get_output_device_name ());
1478         } else {
1479                 all_sizes = backend->available_buffer_sizes (get_device_name ());
1480         }
1481         return all_sizes;
1482 }
1483
1484 vector<uint32_t>
1485 EngineControl::get_default_buffer_sizes ()
1486 {
1487         vector<uint32_t> sizes;
1488         sizes.push_back (8);
1489         sizes.push_back (16);
1490         sizes.push_back (32);
1491         sizes.push_back (64);
1492         sizes.push_back (128);
1493         sizes.push_back (256);
1494         sizes.push_back (512);
1495         sizes.push_back (1024);
1496         sizes.push_back (2048);
1497         sizes.push_back (4096);
1498         sizes.push_back (8192);
1499         return sizes;
1500 }
1501
1502 void
1503 EngineControl::set_buffersize_popdown_strings ()
1504 {
1505         DEBUG_ECONTROL ("set_buffersize_popdown_strings");
1506         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1507         vector<uint32_t> bs;
1508         vector<string> s;
1509
1510         if (_have_control) {
1511                 bs = get_buffer_sizes_for_all_devices ();
1512         } else if (backend->can_change_buffer_size_when_running()) {
1513                 bs = get_default_buffer_sizes ();
1514         }
1515
1516         for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1517                 s.push_back (bufsize_as_string (*x));
1518         }
1519
1520         uint32_t previous_size = 0;
1521         if (!buffer_size_combo.get_active_text().empty()) {
1522                 previous_size = get_buffer_size ();
1523         }
1524
1525         set_popdown_strings (buffer_size_combo, s);
1526
1527         if (!s.empty()) {
1528
1529                 if (std::find(bs.begin(), bs.end(), previous_size) != bs.end()) {
1530                         buffer_size_combo.set_active_text(bufsize_as_string(previous_size));
1531                 } else {
1532
1533                         buffer_size_combo.set_active_text(s.front());
1534
1535                         uint32_t period = backend->buffer_size();
1536                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1537                                 period = backend->default_buffer_size(get_input_device_name());
1538                         }
1539                         if (0 == period && backend->use_separate_input_and_output_devices()) {
1540                                 period = backend->default_buffer_size(get_output_device_name());
1541                         }
1542                         if (0 == period && !backend->use_separate_input_and_output_devices()) {
1543                                 period = backend->default_buffer_size(get_device_name());
1544                         }
1545
1546                         set_active_text_if_present(buffer_size_combo, bufsize_as_string(period));
1547                 }
1548                 show_buffer_duration ();
1549         }
1550         update_sensitivity ();
1551 }
1552
1553 void
1554 EngineControl::set_nperiods_popdown_strings ()
1555 {
1556         DEBUG_ECONTROL ("set_nperiods_popdown_strings");
1557         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1558         vector<uint32_t> np;
1559         vector<string> s;
1560
1561         if (backend->can_set_period_size()) {
1562                 np = backend->available_period_sizes (get_driver());
1563         }
1564
1565         for (vector<uint32_t>::const_iterator x = np.begin(); x != np.end(); ++x) {
1566                 s.push_back (nperiods_as_string (*x));
1567         }
1568
1569         set_popdown_strings (nperiods_combo, s);
1570
1571         if (!s.empty()) {
1572                 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size())); // XXX
1573         }
1574
1575         update_sensitivity ();
1576 }
1577
1578 void
1579 EngineControl::device_changed ()
1580 {
1581         SignalBlocker blocker (*this, "device_changed");
1582         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1583         assert (backend);
1584
1585         string device_name_in;
1586         string device_name_out; // only used if backend support separate I/O devices
1587
1588         if (backend->use_separate_input_and_output_devices()) {
1589                 device_name_in  = get_input_device_name ();
1590                 device_name_out = get_output_device_name ();
1591         } else {
1592                 device_name_in = get_device_name ();
1593         }
1594
1595         /* we set the backend-device to query various device related intormation.
1596          * This has the side effect that backend->device_name() will match
1597          * the device_name and  'change_device' will never be true.
1598          * so work around this by setting...
1599          */
1600         if (backend->use_separate_input_and_output_devices()) {
1601                 if (device_name_in != backend->input_device_name() || device_name_out != backend->output_device_name ()) {
1602                         queue_device_changed = true;
1603                 }
1604         } else {
1605                 if (device_name_in != backend->device_name()) {
1606                         queue_device_changed = true;
1607                 }
1608         }
1609
1610         //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
1611         if (backend->use_separate_input_and_output_devices()) {
1612                 backend->set_input_device_name (device_name_in);
1613                 backend->set_output_device_name (device_name_out);
1614         } else {
1615                 backend->set_device_name(device_name_in);
1616         }
1617
1618         {
1619                 /* don't allow programmatic change to combos to cause a
1620                    recursive call to this method.
1621                  */
1622                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1623
1624                 set_samplerate_popdown_strings ();
1625                 set_buffersize_popdown_strings ();
1626                 set_nperiods_popdown_strings ();
1627
1628                 /* TODO set min + max channel counts here */
1629
1630                 manage_control_app_sensitivity ();
1631         }
1632
1633         /* pick up any saved state for this device */
1634
1635         if (!ignore_changes) {
1636                 maybe_display_saved_state ();
1637         }
1638 }
1639
1640 void
1641 EngineControl::input_device_changed ()
1642 {
1643         DEBUG_ECONTROL ("input_device_changed");
1644         device_changed ();
1645 }
1646
1647 void
1648 EngineControl::output_device_changed ()
1649 {
1650         DEBUG_ECONTROL ("output_device_changed");
1651         device_changed ();
1652 }
1653
1654 string
1655 EngineControl::bufsize_as_string (uint32_t sz)
1656 {
1657         return string_compose (P_("%1 sample", "%1 samples", sz), sz);
1658 }
1659
1660 string
1661 EngineControl::nperiods_as_string (uint32_t np)
1662 {
1663         char buf[8];
1664         snprintf (buf, sizeof (buf), "%u", np);
1665         return buf;
1666 }
1667
1668
1669 void
1670 EngineControl::sample_rate_changed ()
1671 {
1672         DEBUG_ECONTROL ("sample_rate_changed");
1673         /* reset the strings for buffer size to show the correct msec value
1674            (reflecting the new sample rate).
1675          */
1676
1677         show_buffer_duration ();
1678
1679 }
1680
1681 void
1682 EngineControl::buffer_size_changed ()
1683 {
1684         DEBUG_ECONTROL ("buffer_size_changed");
1685         show_buffer_duration ();
1686 }
1687
1688 void
1689 EngineControl::nperiods_changed ()
1690 {
1691         DEBUG_ECONTROL ("nperiods_changed");
1692         show_buffer_duration ();
1693 }
1694
1695 void
1696 EngineControl::show_buffer_duration ()
1697 {
1698         DEBUG_ECONTROL ("show_buffer_duration");
1699         /* buffer sizes  - convert from just samples to samples + msecs for
1700          * the displayed string
1701          */
1702
1703         string bs_text = buffer_size_combo.get_active_text ();
1704         uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1705         uint32_t rate = get_rate();
1706
1707         /* Except for ALSA and Dummy backends, we don't know the number of periods
1708          * per cycle and settings.
1709          *
1710          * jack1 vs jack2 have different default latencies since jack2 start
1711          * in async-mode unless --sync is given which adds an extra cycle
1712          * of latency. The value is not known if jackd is started externally..
1713          *
1714          * So just display the period size, that's also what
1715          * ARDOUR_UI::update_sample_rate() does for the status bar.
1716          * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1717          * but still, that's the buffer period, not [round-trip] latency)
1718          */
1719         char buf[32];
1720         snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1721         buffer_size_duration_label.set_text (buf);
1722 }
1723
1724 void
1725 EngineControl::midi_option_changed ()
1726 {
1727         DEBUG_ECONTROL ("midi_option_changed");
1728         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1729         assert (backend);
1730
1731         backend->set_midi_option (get_midi_option());
1732
1733         vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1734
1735         //_midi_devices.clear(); // TODO merge with state-saved settings..
1736         _can_set_midi_latencies = backend->can_set_systemic_midi_latencies();
1737         std::vector<MidiDeviceSettings> new_devices;
1738
1739         for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1740                 MidiDeviceSettings mds = find_midi_device (i->name);
1741                 if (i->available && !mds) {
1742                         uint32_t input_latency = 0;
1743                         uint32_t output_latency = 0;
1744                         if (_can_set_midi_latencies) {
1745                                 input_latency = backend->systemic_midi_input_latency (i->name);
1746                                 output_latency = backend->systemic_midi_output_latency (i->name);
1747                         }
1748                         bool enabled = backend->midi_device_enabled (i->name);
1749                         MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1750                         new_devices.push_back (ptr);
1751                 } else if (i->available) {
1752                         new_devices.push_back (mds);
1753                 }
1754         }
1755         _midi_devices = new_devices;
1756
1757         if (_midi_devices.empty()) {
1758                 midi_devices_button.hide ();
1759         } else {
1760                 midi_devices_button.show ();
1761         }
1762 }
1763
1764 void
1765 EngineControl::parameter_changed ()
1766 {
1767 }
1768
1769 EngineControl::State
1770 EngineControl::get_matching_state (const string& backend)
1771 {
1772         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1773                 if ((*i)->backend == backend) {
1774                         return (*i);
1775                 }
1776         }
1777         return State();
1778 }
1779
1780 EngineControl::State
1781 EngineControl::get_matching_state (
1782                 const string& backend,
1783                 const string& driver,
1784                 const string& device)
1785 {
1786         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1787                 if ((*i)->backend == backend &&
1788                                 (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1789                 {
1790                         return (*i);
1791                 }
1792         }
1793         return State();
1794 }
1795
1796 EngineControl::State
1797 EngineControl::get_matching_state (
1798                 const string& backend,
1799                 const string& driver,
1800                 const string& input_device,
1801                 const string& output_device)
1802 {
1803         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1804                 if ((*i)->backend == backend &&
1805                                 (!_have_control || ((*i)->driver == driver && ((*i)->input_device == input_device) && (*i)->output_device == output_device)))
1806                 {
1807                         return (*i);
1808                 }
1809         }
1810         return State();
1811 }
1812
1813 EngineControl::State
1814 EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
1815 {
1816         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
1817
1818         if (backend) {
1819                 if (backend->use_separate_input_and_output_devices ()) {
1820                         return get_matching_state (backend_combo.get_active_text(),
1821                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1822                                         input_device_combo.get_active_text(),
1823                                         output_device_combo.get_active_text());
1824                 } else {
1825                         return get_matching_state (backend_combo.get_active_text(),
1826                                         (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1827                                         device_combo.get_active_text());
1828                 }
1829         }
1830
1831         return get_matching_state (backend_combo.get_active_text(),
1832                         string(),
1833                         device_combo.get_active_text());
1834 }
1835
1836 bool EngineControl::equivalent_states (const EngineControl::State& state1,
1837                                        const EngineControl::State& state2)
1838 {
1839         if (state1->backend == state2->backend &&
1840                         state1->driver == state2->driver &&
1841                         state1->device == state2->device &&
1842                         state1->input_device == state2->input_device &&
1843                         state1->output_device == state2->output_device) {
1844                 return true;
1845         }
1846         return false;
1847 }
1848
1849 bool
1850 EngineControl::state_sort_cmp (const State &a, const State &b) {
1851         if (a->active) {
1852                 return true;
1853         }
1854         else if (b->active) {
1855                 return false;
1856         }
1857         else {
1858                 return a->lru < b->lru;
1859         }
1860 }
1861
1862 EngineControl::State
1863 EngineControl::save_state ()
1864 {
1865         State state;
1866
1867         if (!_have_control) {
1868                 state = get_matching_state (backend_combo.get_active_text(), string(), string());
1869                 if (state) {
1870                         state->lru = time (NULL) ;
1871                         return state;
1872                 }
1873                 state.reset(new StateStruct);
1874                 state->backend = get_backend ();
1875         } else {
1876                 state.reset(new StateStruct);
1877                 store_state (state);
1878         }
1879
1880         for (StateList::iterator i = states.begin(); i != states.end();) {
1881                 if (equivalent_states (*i, state)) {
1882                         i =  states.erase(i);
1883                 } else {
1884                         ++i;
1885                 }
1886         }
1887
1888         states.push_back (state);
1889
1890         states.sort (state_sort_cmp);
1891
1892         return state;
1893 }
1894
1895 void
1896 EngineControl::store_state (State state)
1897 {
1898         state->backend = get_backend ();
1899         state->driver = get_driver ();
1900         state->device = get_device_name ();
1901         state->input_device = get_input_device_name ();
1902         state->output_device = get_output_device_name ();
1903         state->sample_rate = get_rate ();
1904         state->buffer_size = get_buffer_size ();
1905         state->n_periods = get_nperiods ();
1906         state->input_latency = get_input_latency ();
1907         state->output_latency = get_output_latency ();
1908         state->input_channels = get_input_channels ();
1909         state->output_channels = get_output_channels ();
1910         state->midi_option = get_midi_option ();
1911         state->midi_devices = _midi_devices;
1912         state->use_buffered_io = get_use_buffered_io ();
1913         state->lru = time (NULL) ;
1914 }
1915
1916 void
1917 EngineControl::maybe_display_saved_state ()
1918 {
1919         if (!_have_control) {
1920                 return;
1921         }
1922
1923         State state = get_saved_state_for_currently_displayed_backend_and_device ();
1924
1925         if (state) {
1926                 DEBUG_ECONTROL ("Restoring saved state");
1927                 PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1928
1929                 if (!_desired_sample_rate) {
1930                         sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1931                 }
1932                 set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
1933
1934                 set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
1935                 /* call this explicitly because we're ignoring changes to
1936                    the controls at this point.
1937                  */
1938                 show_buffer_duration ();
1939                 input_latency.set_value (state->input_latency);
1940                 output_latency.set_value (state->output_latency);
1941
1942                 use_buffered_io_button.set_active (state->use_buffered_io);
1943
1944                 if (!state->midi_option.empty()) {
1945                         midi_option_combo.set_active_text (state->midi_option);
1946                         _midi_devices = state->midi_devices;
1947                 }
1948         } else {
1949                 DEBUG_ECONTROL ("Unable to find saved state for backend and devices");
1950         }
1951 }
1952
1953 XMLNode&
1954 EngineControl::get_state ()
1955 {
1956         LocaleGuard lg;
1957
1958         XMLNode* root = new XMLNode ("AudioMIDISetup");
1959         std::string path;
1960
1961         if (!states.empty()) {
1962                 XMLNode* state_nodes = new XMLNode ("EngineStates");
1963
1964                 for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1965
1966                         XMLNode* node = new XMLNode ("State");
1967
1968                         node->add_property ("backend", (*i)->backend);
1969                         node->add_property ("driver", (*i)->driver);
1970                         node->add_property ("device", (*i)->device);
1971                         node->add_property ("input-device", (*i)->input_device);
1972                         node->add_property ("output-device", (*i)->output_device);
1973                         node->add_property ("sample-rate", (*i)->sample_rate);
1974                         node->add_property ("buffer-size", (*i)->buffer_size);
1975                         node->add_property ("n-periods", (*i)->n_periods);
1976                         node->add_property ("input-latency", (*i)->input_latency);
1977                         node->add_property ("output-latency", (*i)->output_latency);
1978                         node->add_property ("input-channels", (*i)->input_channels);
1979                         node->add_property ("output-channels", (*i)->output_channels);
1980                         node->add_property ("active", (*i)->active ? "yes" : "no");
1981                         node->add_property ("use-buffered-io", (*i)->use_buffered_io ? "yes" : "no");
1982                         node->add_property ("midi-option", (*i)->midi_option);
1983                         node->add_property ("lru", (*i)->active ? time (NULL) : (*i)->lru);
1984
1985                         XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1986                         for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1987                                 XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1988                                 midi_device_stuff->add_property (X_("name"), (*p)->name);
1989                                 midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1990                                 midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1991                                 midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1992                                 midi_devices->add_child_nocopy (*midi_device_stuff);
1993                         }
1994                         node->add_child_nocopy (*midi_devices);
1995
1996                         state_nodes->add_child_nocopy (*node);
1997                 }
1998
1999                 root->add_child_nocopy (*state_nodes);
2000         }
2001
2002         return *root;
2003 }
2004
2005 void
2006 EngineControl::set_default_state ()
2007 {
2008         vector<string> backend_names;
2009         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2010
2011         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
2012                 backend_names.push_back ((*b)->name);
2013         }
2014         backend_combo.set_active_text (backend_names.front());
2015
2016         // We could set default backends per platform etc here
2017
2018         backend_changed ();
2019 }
2020
2021 bool
2022 EngineControl::set_state (const XMLNode& root)
2023 {
2024         XMLNodeList          clist, cclist;
2025         XMLNodeConstIterator citer, cciter;
2026         XMLNode const * child;
2027         XMLNode const * grandchild;
2028         XMLProperty const * prop = NULL;
2029
2030         if (root.name() != "AudioMIDISetup") {
2031                 return false;
2032         }
2033
2034         clist = root.children();
2035
2036         states.clear ();
2037
2038         for (citer = clist.begin(); citer != clist.end(); ++citer) {
2039
2040                 child = *citer;
2041
2042                 if (child->name() != "EngineStates") {
2043                         continue;
2044                 }
2045
2046                 cclist = child->children();
2047
2048                 for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
2049                         State state (new StateStruct);
2050
2051                         grandchild = *cciter;
2052
2053                         if (grandchild->name() != "State") {
2054                                 continue;
2055                         }
2056
2057                         if ((prop = grandchild->property ("backend")) == 0) {
2058                                 continue;
2059                         }
2060                         state->backend = prop->value ();
2061
2062                         if ((prop = grandchild->property ("driver")) == 0) {
2063                                 continue;
2064                         }
2065                         state->driver = prop->value ();
2066
2067                         if ((prop = grandchild->property ("device")) == 0) {
2068                                 continue;
2069                         }
2070                         state->device = prop->value ();
2071
2072                         if ((prop = grandchild->property ("input-device")) == 0) {
2073                                 continue;
2074                         }
2075                         state->input_device = prop->value ();
2076
2077                         if ((prop = grandchild->property ("output-device")) == 0) {
2078                                 continue;
2079                         }
2080                         state->output_device = prop->value ();
2081
2082                         if ((prop = grandchild->property ("sample-rate")) == 0) {
2083                                 continue;
2084                         }
2085                         state->sample_rate = atof (prop->value ());
2086
2087                         if ((prop = grandchild->property ("buffer-size")) == 0) {
2088                                 continue;
2089                         }
2090                         state->buffer_size = atoi (prop->value ());
2091
2092                         if ((prop = grandchild->property ("n-periods")) == 0) {
2093                                 // optional (new value in 4.5)
2094                                 state->n_periods = 0;
2095                         } else {
2096                                 state->n_periods = atoi (prop->value ());
2097                         }
2098
2099                         if ((prop = grandchild->property ("input-latency")) == 0) {
2100                                 continue;
2101                         }
2102                         state->input_latency = atoi (prop->value ());
2103
2104                         if ((prop = grandchild->property ("output-latency")) == 0) {
2105                                 continue;
2106                         }
2107                         state->output_latency = atoi (prop->value ());
2108
2109                         if ((prop = grandchild->property ("input-channels")) == 0) {
2110                                 continue;
2111                         }
2112                         state->input_channels = atoi (prop->value ());
2113
2114                         if ((prop = grandchild->property ("output-channels")) == 0) {
2115                                 continue;
2116                         }
2117                         state->output_channels = atoi (prop->value ());
2118
2119                         if ((prop = grandchild->property ("active")) == 0) {
2120                                 continue;
2121                         }
2122                         state->active = string_is_affirmative (prop->value ());
2123
2124                         if ((prop = grandchild->property ("use-buffered-io")) == 0) {
2125                                 continue;
2126                         }
2127                         state->use_buffered_io = string_is_affirmative (prop->value ());
2128
2129                         if ((prop = grandchild->property ("midi-option")) == 0) {
2130                                 continue;
2131                         }
2132                         state->midi_option = prop->value ();
2133
2134                         state->midi_devices.clear();
2135                         XMLNode* midinode;
2136                         if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
2137                                 const XMLNodeList mnc = midinode->children();
2138                                 for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
2139                                         if ((*n)->property (X_("name")) == 0
2140                                                         || (*n)->property (X_("enabled")) == 0
2141                                                         || (*n)->property (X_("input-latency")) == 0
2142                                                         || (*n)->property (X_("output-latency")) == 0
2143                                                  ) {
2144                                                 continue;
2145                                         }
2146
2147                                         MidiDeviceSettings ptr (new MidiDeviceSetting(
2148                                                                 (*n)->property (X_("name"))->value (),
2149                                                                 string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
2150                                                                 atoi ((*n)->property (X_("input-latency"))->value ()),
2151                                                                 atoi ((*n)->property (X_("output-latency"))->value ())
2152                                                                 ));
2153                                         state->midi_devices.push_back (ptr);
2154                                 }
2155                         }
2156
2157                         if ((prop = grandchild->property ("lru"))) {
2158                                 state->lru = atoi (prop->value ());
2159                         }
2160
2161 #if 1
2162                         /* remove accumulated duplicates (due to bug in ealier version)
2163                          * this can be removed again before release
2164                          */
2165                         for (StateList::iterator i = states.begin(); i != states.end();) {
2166                                 if ((*i)->backend == state->backend &&
2167                                                 (*i)->driver == state->driver &&
2168                                                 (*i)->device == state->device) {
2169                                         i =  states.erase(i);
2170                                 } else {
2171                                         ++i;
2172                                 }
2173                         }
2174 #endif
2175
2176                         states.push_back (state);
2177                 }
2178         }
2179
2180         /* now see if there was an active state and switch the setup to it */
2181
2182         // purge states of backend that are not available in this built
2183         vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
2184         vector<std::string> backend_names;
2185
2186         for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
2187                 backend_names.push_back((*i)->name);
2188         }
2189         for (StateList::iterator i = states.begin(); i != states.end();) {
2190                 if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
2191                         i = states.erase(i);
2192                 } else {
2193                         ++i;
2194                 }
2195         }
2196
2197         states.sort (state_sort_cmp);
2198
2199         for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
2200
2201                 if ((*i)->active) {
2202                         return set_current_state (*i);
2203                 }
2204         }
2205         return false;
2206 }
2207
2208 bool
2209 EngineControl::set_current_state (const State& state)
2210 {
2211         DEBUG_ECONTROL ("set_current_state");
2212
2213         boost::shared_ptr<ARDOUR::AudioBackend> backend;
2214
2215         if (!(backend = ARDOUR::AudioEngine::instance ()->set_backend (
2216                   state->backend, downcase (std::string(PROGRAM_NAME)), ""))) {
2217                 DEBUG_ECONTROL (string_compose ("Unable to set backend to %1", state->backend));
2218                 // this shouldn't happen as the invalid backend names should have been
2219                 // removed from the list of states.
2220                 return false;
2221         }
2222
2223         // now reflect the change in the backend in the GUI so backend_changed will
2224         // do the right thing
2225         backend_combo.set_active_text (state->backend);
2226
2227         if (!ARDOUR::AudioEngine::instance()->setup_required ()) {
2228                 backend_changed ();
2229                 // we don't have control don't restore state
2230                 return true;
2231         }
2232
2233
2234         if (!state->driver.empty ()) {
2235                 if (!backend->requires_driver_selection ()) {
2236                         DEBUG_ECONTROL ("Backend should require driver selection");
2237                         // A backend has changed from having driver selection to not having
2238                         // it or someone has been manually editing a config file and messed
2239                         // it up
2240                         return false;
2241                 }
2242
2243                 if (backend->set_driver (state->driver) != 0) {
2244                         DEBUG_ECONTROL (string_compose ("Unable to set driver %1", state->driver));
2245                         // Driver names for a backend have changed and the name in the
2246                         // config file is now invalid or support for driver is no longer
2247                         // included in the backend
2248                         return false;
2249                 }
2250                 // no need to set the driver_combo as backend_changed will use
2251                 // backend->driver_name to set the active driver
2252         }
2253
2254         if (!state->device.empty ()) {
2255                 if (backend->set_device_name (state->device) != 0) {
2256                         DEBUG_ECONTROL (
2257                             string_compose ("Unable to set device name %1", state->device));
2258                         // device is no longer available on the system
2259                         return false;
2260                 }
2261                 // no need to set active device as it will be picked up in
2262                 // via backend_changed ()/set_device_popdown_strings
2263
2264         } else {
2265                 // backend supports separate input/output devices
2266                 if (backend->set_input_device_name (state->input_device) != 0) {
2267                         DEBUG_ECONTROL (string_compose ("Unable to set input device name %1",
2268                                                         state->input_device));
2269                         // input device is no longer available on the system
2270                         return false;
2271                 }
2272
2273                 if (backend->set_output_device_name (state->output_device) != 0) {
2274                         DEBUG_ECONTROL (string_compose ("Unable to set output device name %1",
2275                                                         state->input_device));
2276                         // output device is no longer available on the system
2277                         return false;
2278                 }
2279                 // no need to set active devices as it will be picked up in via
2280                 // backend_changed ()/set_*_device_popdown_strings
2281         }
2282
2283         backend_changed ();
2284
2285         // Now restore the state of the rest of the controls
2286
2287         // We don't use a SignalBlocker as set_current_state is currently only
2288         // called from set_state before any signals are connected. If at some point
2289         // a more general named state mechanism is implemented and
2290         // set_current_state is called while signals are connected then a
2291         // SignalBlocker will need to be instantiated before setting these.
2292
2293         device_combo.set_active_text (state->device);
2294         input_device_combo.set_active_text (state->input_device);
2295         output_device_combo.set_active_text (state->output_device);
2296         if (!_desired_sample_rate) {
2297                 sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
2298         }
2299         set_active_text_if_present (buffer_size_combo, bufsize_as_string (state->buffer_size));
2300         set_active_text_if_present (nperiods_combo, nperiods_as_string (state->n_periods));
2301         input_latency.set_value (state->input_latency);
2302         output_latency.set_value (state->output_latency);
2303         midi_option_combo.set_active_text (state->midi_option);
2304         use_buffered_io_button.set_active (state->use_buffered_io);
2305         return true;
2306 }
2307
2308 int
2309 EngineControl::push_state_to_backend (bool start)
2310 {
2311         DEBUG_ECONTROL ("push_state_to_backend");
2312         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2313         PBD::Unwinder<uint32_t> protect_ignore_device_changes (ignore_device_changes, ignore_device_changes + 1);
2314
2315         if (!backend) {
2316                 return 0;
2317         }
2318
2319         /* figure out what is going to change */
2320
2321         bool restart_required = false;
2322         bool was_running = ARDOUR::AudioEngine::instance()->running();
2323         bool change_driver = false;
2324         bool change_device = false;
2325         bool change_rate = false;
2326         bool change_bufsize = false;
2327         bool change_nperiods = false;
2328         bool change_latency = false;
2329         bool change_channels = false;
2330         bool change_midi = false;
2331         bool change_buffered_io = false;
2332
2333         uint32_t ochan = get_output_channels ();
2334         uint32_t ichan = get_input_channels ();
2335
2336         if (_have_control) {
2337
2338                 if (started_at_least_once) {
2339
2340                         /* we can control the backend */
2341
2342                         if (backend->requires_driver_selection()) {
2343                                 if (get_driver() != backend->driver_name()) {
2344                                         change_driver = true;
2345                                 }
2346                         }
2347
2348                         if (backend->use_separate_input_and_output_devices()) {
2349                                 if (get_input_device_name() != backend->input_device_name()) {
2350                                         change_device = true;
2351                                 }
2352                                 if (get_output_device_name() != backend->output_device_name()) {
2353                                         change_device = true;
2354                                 }
2355                         } else {
2356                                 if (get_device_name() != backend->device_name()) {
2357                                         change_device = true;
2358                                 }
2359                         }
2360
2361                         if (queue_device_changed) {
2362                                 change_device = true;
2363                         }
2364
2365                         if (get_rate() != backend->sample_rate()) {
2366                                 change_rate = true;
2367                         }
2368
2369                         if (get_buffer_size() != backend->buffer_size()) {
2370                                 change_bufsize = true;
2371                         }
2372
2373                         if (backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0
2374                                         && get_nperiods() != backend->period_size()) {
2375                                 change_nperiods = true;
2376                         }
2377
2378                         if (get_midi_option() != backend->midi_option()) {
2379                                 change_midi = true;
2380                         }
2381
2382                         if (backend->can_use_buffered_io()) {
2383                                 if (get_use_buffered_io() != backend->get_use_buffered_io()) {
2384                                         change_buffered_io = true;
2385                                 }
2386                         }
2387
2388                         /* zero-requested channels means "all available" */
2389
2390                         if (ichan == 0) {
2391                                 ichan = backend->input_channels();
2392                         }
2393
2394                         if (ochan == 0) {
2395                                 ochan = backend->output_channels();
2396                         }
2397
2398                         if (ichan != backend->input_channels()) {
2399                                 change_channels = true;
2400                         }
2401
2402                         if (ochan != backend->output_channels()) {
2403                                 change_channels = true;
2404                         }
2405
2406                         if (get_input_latency() != backend->systemic_input_latency() ||
2407                                         get_output_latency() != backend->systemic_output_latency()) {
2408                                 change_latency = true;
2409                         }
2410                 } else {
2411                         /* backend never started, so we have to force a group
2412                            of settings.
2413                          */
2414                         change_device = true;
2415                         if (backend->requires_driver_selection()) {
2416                                 change_driver = true;
2417                         }
2418                         change_rate = true;
2419                         change_bufsize = true;
2420                         change_channels = true;
2421                         change_latency = true;
2422                         change_midi = true;
2423                         change_buffered_io = backend->can_use_buffered_io();
2424                         change_channels = true;
2425                         change_nperiods = backend->can_set_period_size() && get_popdown_string_count (nperiods_combo) > 0;
2426                 }
2427
2428         } else {
2429
2430                 /* we have no control over the backend, meaning that we can
2431                  * only possibly change sample rate and buffer size.
2432                  */
2433
2434
2435                 if (get_rate() != backend->sample_rate()) {
2436                         change_bufsize = true;
2437                 }
2438
2439                 if (get_buffer_size() != backend->buffer_size()) {
2440                         change_bufsize = true;
2441                 }
2442         }
2443
2444         queue_device_changed = false;
2445
2446         if (!_have_control) {
2447
2448                 /* We do not have control over the backend, so the best we can
2449                  * do is try to change the sample rate and/or bufsize and get
2450                  * out of here.
2451                  */
2452
2453                 if (change_rate && !backend->can_change_sample_rate_when_running()) {
2454                         return 1;
2455                 }
2456
2457                 if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
2458                         return 1;
2459                 }
2460
2461                 if (change_rate) {
2462                         backend->set_sample_rate (get_rate());
2463                 }
2464
2465                 if (change_bufsize) {
2466                         backend->set_buffer_size (get_buffer_size());
2467                 }
2468
2469                 if (start) {
2470                         if (ARDOUR::AudioEngine::instance()->start ()) {
2471                                 error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
2472                                 return -1;
2473                         }
2474                 }
2475
2476                 post_push ();
2477
2478                 return 0;
2479         }
2480
2481         /* determine if we need to stop the backend before changing parameters */
2482
2483         if (change_driver || change_device || change_channels || change_nperiods ||
2484                         (change_latency && !backend->can_change_systemic_latency_when_running ()) ||
2485                         (change_rate && !backend->can_change_sample_rate_when_running()) ||
2486                         change_midi || change_buffered_io ||
2487                         (change_bufsize && !backend->can_change_buffer_size_when_running())) {
2488                 restart_required = true;
2489         } else {
2490                 restart_required = false;
2491         }
2492
2493
2494         if (was_running) {
2495                 if (restart_required) {
2496                         if (ARDOUR::AudioEngine::instance()->stop()) {
2497                                 return -1;
2498                         }
2499                 }
2500         }
2501
2502         if (change_driver && backend->set_driver (get_driver())) {
2503                 error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
2504                 return -1;
2505         }
2506         if (backend->use_separate_input_and_output_devices()) {
2507                 if (change_device && backend->set_input_device_name (get_input_device_name())) {
2508                         error << string_compose (_("Cannot set input device name to %1"), get_input_device_name()) << endmsg;
2509                         return -1;
2510                 }
2511                 if (change_device && backend->set_output_device_name (get_output_device_name())) {
2512                         error << string_compose (_("Cannot set output device name to %1"), get_output_device_name()) << endmsg;
2513                         return -1;
2514                 }
2515         } else {
2516                 if (change_device && backend->set_device_name (get_device_name())) {
2517                         error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
2518                         return -1;
2519                 }
2520         }
2521         if (change_rate && backend->set_sample_rate (get_rate())) {
2522                 error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
2523                 return -1;
2524         }
2525         if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
2526                 error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
2527                 return -1;
2528         }
2529         if (change_nperiods && backend->set_peridod_size (get_nperiods())) {
2530                 error << string_compose (_("Cannot set periods to %1"), get_nperiods()) << endmsg;
2531                 return -1;
2532         }
2533
2534         if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
2535                 if (backend->set_input_channels (get_input_channels())) {
2536                         error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
2537                         return -1;
2538                 }
2539                 if (backend->set_output_channels (get_output_channels())) {
2540                         error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
2541                         return -1;
2542                 }
2543         }
2544         if (change_latency) {
2545                 if (backend->set_systemic_input_latency (get_input_latency())) {
2546                         error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
2547                         return -1;
2548                 }
2549                 if (backend->set_systemic_output_latency (get_output_latency())) {
2550                         error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
2551                         return -1;
2552                 }
2553         }
2554
2555         if (change_midi) {
2556                 backend->set_midi_option (get_midi_option());
2557         }
2558
2559         if (change_buffered_io) {
2560                 backend->set_use_buffered_io (use_buffered_io_button.get_active());
2561         }
2562
2563         if (1 /* TODO */) {
2564                 for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
2565                         if (_measure_midi) {
2566                                 if (*p == _measure_midi) {
2567                                         backend->set_midi_device_enabled ((*p)->name, true);
2568                                 } else {
2569                                         backend->set_midi_device_enabled ((*p)->name, false);
2570                                 }
2571                                 if (backend->can_change_systemic_latency_when_running ()) {
2572                                         backend->set_systemic_midi_input_latency ((*p)->name, 0);
2573                                         backend->set_systemic_midi_output_latency ((*p)->name, 0);
2574                                 }
2575                                 continue;
2576                         }
2577                         backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
2578                         if (backend->can_set_systemic_midi_latencies()) {
2579                                 backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
2580                                 backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
2581                         }
2582                 }
2583         }
2584
2585         if (start || (was_running && restart_required)) {
2586                 if (ARDOUR::AudioEngine::instance()->start()) {
2587                         return -1;
2588                 }
2589         }
2590
2591         post_push ();
2592
2593         return 0;
2594 }
2595
2596 void
2597 EngineControl::post_push ()
2598 {
2599         /* get a pointer to the current state object, creating one if
2600          * necessary
2601          */
2602
2603         State state = get_saved_state_for_currently_displayed_backend_and_device ();
2604
2605         if (!state) {
2606                 state = save_state ();
2607                 assert (state);
2608         } else {
2609                 store_state(state);
2610         }
2611
2612         states.sort (state_sort_cmp);
2613
2614         /* all off */
2615
2616         for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
2617                 (*i)->active = false;
2618         }
2619
2620         /* mark this one active (to be used next time the dialog is
2621          * shown)
2622          */
2623
2624         state->active = true;
2625
2626         if (_have_control) { // XXX
2627                 manage_control_app_sensitivity ();
2628         }
2629
2630         /* schedule a redisplay of MIDI ports */
2631         //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
2632 }
2633
2634
2635 float
2636 EngineControl::get_rate () const
2637 {
2638         float r = atof (sample_rate_combo.get_active_text ());
2639         /* the string may have been translated with an abbreviation for
2640          * thousands, so use a crude heuristic to fix this.
2641          */
2642         if (r < 1000.0) {
2643                 r *= 1000.0;
2644         }
2645         return r;
2646 }
2647
2648
2649 uint32_t
2650 EngineControl::get_buffer_size () const
2651 {
2652         string txt = buffer_size_combo.get_active_text ();
2653         uint32_t samples;
2654
2655         if (sscanf (txt.c_str(), "%d", &samples) != 1) {
2656                 fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
2657                 fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
2658                 throw exception ();
2659         }
2660
2661         return samples;
2662 }
2663
2664 uint32_t
2665 EngineControl::get_nperiods () const
2666 {
2667         string txt = nperiods_combo.get_active_text ();
2668         return atoi (txt.c_str());
2669 }
2670
2671 string
2672 EngineControl::get_midi_option () const
2673 {
2674         return midi_option_combo.get_active_text();
2675 }
2676
2677 bool
2678 EngineControl::get_use_buffered_io () const
2679 {
2680         return use_buffered_io_button.get_active();
2681 }
2682
2683 uint32_t
2684 EngineControl::get_input_channels() const
2685 {
2686         if (ARDOUR::Profile->get_mixbus()) {
2687                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2688                 if (!backend) return 0;
2689                 return backend->input_channels();
2690         }
2691         return (uint32_t) input_channels_adjustment.get_value();
2692 }
2693
2694 uint32_t
2695 EngineControl::get_output_channels() const
2696 {
2697         if (ARDOUR::Profile->get_mixbus()) {
2698                 boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2699                 if (!backend) return 0;
2700                 return backend->input_channels();
2701         }
2702         return (uint32_t) output_channels_adjustment.get_value();
2703 }
2704
2705 uint32_t
2706 EngineControl::get_input_latency() const
2707 {
2708         return (uint32_t) input_latency_adjustment.get_value();
2709 }
2710
2711 uint32_t
2712 EngineControl::get_output_latency() const
2713 {
2714         return (uint32_t) output_latency_adjustment.get_value();
2715 }
2716
2717 string
2718 EngineControl::get_backend () const
2719 {
2720         return backend_combo.get_active_text ();
2721 }
2722
2723 string
2724 EngineControl::get_driver () const
2725 {
2726         if (driver_combo.get_parent()) {
2727                 return driver_combo.get_active_text ();
2728         } else {
2729                 return "";
2730         }
2731 }
2732
2733 string
2734 EngineControl::get_device_name () const
2735 {
2736         return device_combo.get_active_text ();
2737 }
2738
2739 string
2740 EngineControl::get_input_device_name () const
2741 {
2742         return input_device_combo.get_active_text ();
2743 }
2744
2745 string
2746 EngineControl::get_output_device_name () const
2747 {
2748         return output_device_combo.get_active_text ();
2749 }
2750
2751 void
2752 EngineControl::control_app_button_clicked ()
2753 {
2754         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2755
2756         if (!backend) {
2757                 return;
2758         }
2759
2760         backend->launch_control_app ();
2761 }
2762
2763 void
2764 EngineControl::start_stop_button_clicked ()
2765 {
2766         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2767
2768         if (!backend) {
2769                 return;
2770         }
2771
2772         if (ARDOUR::AudioEngine::instance()->running()) {
2773                 ARDOUR::AudioEngine::instance()->stop ();
2774         } else {
2775                 start_engine ();
2776         }
2777 }
2778
2779 void
2780 EngineControl::update_devices_button_clicked ()
2781 {
2782         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2783
2784         if (!backend) {
2785                 return;
2786         }
2787
2788         if (backend->update_devices()) {
2789                 device_list_changed ();
2790         }
2791 }
2792
2793 void
2794 EngineControl::use_buffered_io_button_clicked ()
2795 {
2796         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2797
2798         if (!backend) {
2799                 return;
2800         }
2801
2802         bool set_buffered_io = !use_buffered_io_button.get_active();
2803         use_buffered_io_button.set_active (set_buffered_io);
2804         backend->set_use_buffered_io (set_buffered_io);
2805 }
2806
2807 void
2808 EngineControl::manage_control_app_sensitivity ()
2809 {
2810         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2811
2812         if (!backend) {
2813                 return;
2814         }
2815
2816         string appname = backend->control_app_name();
2817
2818         if (appname.empty()) {
2819                 control_app_button.set_sensitive (false);
2820         } else {
2821                 control_app_button.set_sensitive (true);
2822         }
2823 }
2824
2825 void
2826 EngineControl::set_desired_sample_rate (uint32_t sr)
2827 {
2828         _desired_sample_rate = sr;
2829         if (ARDOUR::AudioEngine::instance ()->running ()
2830                         && ARDOUR::AudioEngine::instance ()->sample_rate () != sr) {
2831                 stop_engine ();
2832         }
2833         device_changed ();
2834 }
2835
2836 void
2837 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
2838 {
2839         if (page_num == 0) {
2840                 cancel_button->set_sensitive (true);
2841                 _measure_midi.reset();
2842                 update_sensitivity ();
2843         } else {
2844                 cancel_button->set_sensitive (false);
2845                 ok_button->set_sensitive (false);
2846         }
2847
2848         if (page_num == midi_tab) {
2849                 /* MIDI tab */
2850                 refresh_midi_display ();
2851         }
2852
2853         if (page_num == latency_tab) {
2854                 /* latency tab */
2855
2856                 if (ARDOUR::AudioEngine::instance()->running()) {
2857                         stop_engine (true);
2858                 }
2859
2860                 {
2861                         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
2862
2863                         /* save any existing latency values */
2864
2865                         uint32_t il = (uint32_t) input_latency.get_value ();
2866                         uint32_t ol = (uint32_t) input_latency.get_value ();
2867
2868                         /* reset to zero so that our new test instance
2869                            will be clean of any existing latency measures.
2870
2871                            NB. this should really be done by the backend
2872                            when stated for latency measurement.
2873                         */
2874
2875                         input_latency.set_value (0);
2876                         output_latency.set_value (0);
2877
2878                         push_state_to_backend (false);
2879
2880                         /* reset control */
2881
2882                         input_latency.set_value (il);
2883                         output_latency.set_value (ol);
2884
2885                 }
2886                 // This should be done in push_state_to_backend()
2887                 if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
2888                         disable_latency_tab ();
2889                 }
2890
2891                 enable_latency_tab ();
2892
2893         } else {
2894                 if (lm_running) {
2895                         end_latency_detection ();
2896                         ARDOUR::AudioEngine::instance()->stop_latency_detection();
2897                 }
2898         }
2899 }
2900
2901 /* latency measurement */
2902
2903 bool
2904 EngineControl::check_audio_latency_measurement ()
2905 {
2906         MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2907
2908         if (mtdm->resolve () < 0) {
2909                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2910                 return true;
2911         }
2912
2913         if (mtdm->get_peak () > 0.707f) {
2914                 // get_peak() resets the peak-hold in the detector.
2915                 // this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
2916                 lm_results.set_markup (string_compose (results_markup, _("Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface.")));
2917                 return true;
2918         }
2919
2920         if (mtdm->err () > 0.3) {
2921                 mtdm->invert ();
2922                 mtdm->resolve ();
2923         }
2924
2925         char buf[256];
2926         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2927
2928         if (sample_rate == 0) {
2929                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2930                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2931                 return false;
2932         }
2933
2934         int frames_total = mtdm->del();
2935         int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2936
2937         snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2938                         _("Detected roundtrip latency: "),
2939                         frames_total, frames_total * 1000.0f/sample_rate,
2940                         _("Systemic latency: "),
2941                         extra, extra * 1000.0f/sample_rate);
2942
2943         bool solid = true;
2944
2945         if (mtdm->err () > 0.2) {
2946                 strcat (buf, " ");
2947                 strcat (buf, _("(signal detection error)"));
2948                 solid = false;
2949         }
2950
2951         if (mtdm->inv ()) {
2952                 strcat (buf, " ");
2953                 strcat (buf, _("(inverted - bad wiring)"));
2954                 solid = false;
2955         }
2956
2957         lm_results.set_markup (string_compose (results_markup, buf));
2958
2959         if (solid) {
2960                 have_lm_results = true;
2961                 end_latency_detection ();
2962                 lm_use_button.set_sensitive (true);
2963                 return false;
2964         }
2965
2966         return true;
2967 }
2968
2969 bool
2970 EngineControl::check_midi_latency_measurement ()
2971 {
2972         ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
2973
2974         if (!mididm->have_signal () || mididm->latency () == 0) {
2975                 lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2976                 return true;
2977         }
2978
2979         char buf[256];
2980         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
2981
2982         if (sample_rate == 0) {
2983                 lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2984                 ARDOUR::AudioEngine::instance()->stop_latency_detection ();
2985                 return false;
2986         }
2987
2988         ARDOUR::framecnt_t frames_total = mididm->latency();
2989         ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
2990         snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2991                         _("Detected roundtrip latency: "),
2992                         frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2993                         _("Systemic latency: "),
2994                         extra, extra * 1000.0f / sample_rate);
2995
2996         bool solid = true;
2997
2998         if (!mididm->ok ()) {
2999                 strcat (buf, " ");
3000                 strcat (buf, _("(averaging)"));
3001                 solid = false;
3002         }
3003
3004         if (mididm->deviation () > 50.0) {
3005                 strcat (buf, " ");
3006                 strcat (buf, _("(too large jitter)"));
3007                 solid = false;
3008         } else if (mididm->deviation () > 10.0) {
3009                 strcat (buf, " ");
3010                 strcat (buf, _("(large jitter)"));
3011         }
3012
3013         if (solid) {
3014                 have_lm_results = true;
3015                 end_latency_detection ();
3016                 lm_use_button.set_sensitive (true);
3017                 lm_results.set_markup (string_compose (results_markup, buf));
3018                 return false;
3019         } else if (mididm->processed () > 400) {
3020                 have_lm_results = false;
3021                 end_latency_detection ();
3022                 lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
3023                 return false;
3024         }
3025
3026         lm_results.set_markup (string_compose (results_markup, buf));
3027
3028         return true;
3029 }
3030
3031 void
3032 EngineControl::start_latency_detection ()
3033 {
3034         ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
3035         ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
3036
3037         if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi ? true : false) == 0) {
3038                 lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
3039                 if (_measure_midi) {
3040                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
3041                 } else {
3042                         latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
3043                 }
3044                 lm_measure_label.set_text (_("Cancel"));
3045                 have_lm_results = false;
3046                 lm_use_button.set_sensitive (false);
3047                 lm_input_channel_combo.set_sensitive (false);
3048                 lm_output_channel_combo.set_sensitive (false);
3049                 lm_running = true;
3050         }
3051 }
3052
3053 void
3054 EngineControl::end_latency_detection ()
3055 {
3056         latency_timeout.disconnect ();
3057         ARDOUR::AudioEngine::instance()->stop_latency_detection ();
3058         lm_measure_label.set_text (_("Measure"));
3059         if (!have_lm_results) {
3060                 lm_use_button.set_sensitive (false);
3061         }
3062         lm_input_channel_combo.set_sensitive (true);
3063         lm_output_channel_combo.set_sensitive (true);
3064         lm_running = false;
3065 }
3066
3067 void
3068 EngineControl::latency_button_clicked ()
3069 {
3070         if (!lm_running) {
3071                 start_latency_detection ();
3072         } else {
3073                 end_latency_detection ();
3074         }
3075 }
3076
3077 void
3078 EngineControl::latency_back_button_clicked ()
3079 {
3080         ARDOUR::AudioEngine::instance()->stop(true);
3081         notebook.set_current_page(0);
3082 }
3083
3084 void
3085 EngineControl::use_latency_button_clicked ()
3086 {
3087         if (_measure_midi) {
3088                 ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
3089                 if (!mididm) {
3090                         return;
3091                 }
3092                 ARDOUR::framecnt_t frames_total = mididm->latency();
3093                 ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
3094                 uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
3095                 _measure_midi->input_latency = one_way;
3096                 _measure_midi->output_latency = one_way;
3097                 notebook.set_current_page (midi_tab);
3098         } else {
3099                 MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
3100
3101                 if (!mtdm) {
3102                         return;
3103                 }
3104
3105                 double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
3106                 one_way = std::max (0., one_way);
3107
3108                 input_latency_adjustment.set_value (one_way);
3109                 output_latency_adjustment.set_value (one_way);
3110
3111                 /* back to settings page */
3112                 notebook.set_current_page (0);
3113         }
3114 }
3115
3116 bool
3117 EngineControl::on_delete_event (GdkEventAny* ev)
3118 {
3119         if (notebook.get_current_page() == 2) {
3120                 /* currently on latency tab - be sure to clean up */
3121                 end_latency_detection ();
3122         }
3123         return ArdourDialog::on_delete_event (ev);
3124 }
3125
3126 void
3127 EngineControl::engine_running ()
3128 {
3129         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3130         assert (backend);
3131
3132         set_active_text_if_present (buffer_size_combo, bufsize_as_string (backend->buffer_size()));
3133         sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
3134
3135         if (backend->can_set_period_size ()) {
3136                 set_active_text_if_present (nperiods_combo, nperiods_as_string (backend->period_size()));
3137         }
3138
3139         connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
3140         connect_disconnect_button.show();
3141
3142         started_at_least_once = true;
3143         if (_have_control) {
3144                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Running")));
3145         } else {
3146                 engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Connected")));
3147         }
3148         update_sensitivity();
3149
3150         refill_midi_ports (true);
3151         refill_midi_ports (false);
3152 }
3153
3154 void
3155 EngineControl::engine_stopped ()
3156 {
3157         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
3158         assert (backend);
3159
3160         connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
3161         connect_disconnect_button.show();
3162
3163         if (_have_control) {
3164                 engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Stopped")));
3165         } else {
3166                 engine_status.set_markup(X_(""));
3167         }
3168
3169         update_sensitivity();
3170 }
3171
3172 void
3173 EngineControl::device_list_changed ()
3174 {
3175         if (ignore_device_changes) {
3176                 return;
3177         }
3178         PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
3179         list_devices ();
3180         midi_option_changed();
3181 }
3182
3183 void
3184 EngineControl::connect_disconnect_click()
3185 {
3186         if (ARDOUR::AudioEngine::instance()->running()) {
3187                 stop_engine ();
3188         } else {
3189                 start_engine ();
3190         }
3191 }
3192
3193 void
3194 EngineControl::calibrate_audio_latency ()
3195 {
3196         _measure_midi.reset ();
3197         have_lm_results = false;
3198         lm_use_button.set_sensitive (false);
3199         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3200         notebook.set_current_page (latency_tab);
3201 }
3202
3203 void
3204 EngineControl::calibrate_midi_latency (MidiDeviceSettings s)
3205 {
3206         _measure_midi = s;
3207         have_lm_results = false;
3208         lm_use_button.set_sensitive (false);
3209         lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
3210         notebook.set_current_page (latency_tab);
3211 }
3212
3213 void
3214 EngineControl::configure_midi_devices ()
3215 {
3216         notebook.set_current_page (midi_tab);
3217 }