ardour
engine_dialog.cc
Go to the documentation of this file.
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 <fstream>
24 #include <map>
25 
26 #include <boost/scoped_ptr.hpp>
27 
28 #include <gtkmm/messagedialog.h>
29 
30 #include "pbd/error.h"
31 #include "pbd/xml++.h"
32 #include "pbd/unwind.h"
33 #include "pbd/failed_constructor.h"
34 
35 #include <gtkmm/alignment.h>
36 #include <gtkmm/stock.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm2ext/utils.h>
39 
40 #include "ardour/audio_backend.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/mtdm.h"
43 #include "ardour/mididm.h"
45 #include "ardour/types.h"
46 #include "ardour/profile.h"
47 
48 #include "pbd/convert.h"
49 #include "pbd/error.h"
50 
51 #include "opts.h"
52 #include "ardour_ui.h"
53 #include "engine_dialog.h"
54 #include "gui_thread.h"
55 #include "utils.h"
56 #include "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 static const unsigned int midi_tab = 2;
66 static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
67 
68 static const char* results_markup = X_("<span weight=\"bold\" size=\"larger\">%1</span>");
69 
71  : ArdourDialog (_("Audio/MIDI Setup"))
72  , engine_status ("")
73  , basic_packer (9, 4)
74  , input_latency_adjustment (0, 0, 99999, 1)
75  , input_latency (input_latency_adjustment)
76  , output_latency_adjustment (0, 0, 99999, 1)
77  , output_latency (output_latency_adjustment)
78  , input_channels_adjustment (0, 0, 256, 1)
79  , input_channels (input_channels_adjustment)
80  , output_channels_adjustment (0, 0, 256, 1)
81  , output_channels (output_channels_adjustment)
82  , ports_adjustment (128, 8, 1024, 1, 16)
83  , ports_spinner (ports_adjustment)
84  , control_app_button (_("Device Control Panel"))
85  , midi_devices_button (_("Midi Device Setup"))
86  , lm_measure_label (_("Measure"))
87  , lm_use_button (_("Use results"))
88  , lm_back_button (_("Back to settings ... (ignore results)"))
89  , lm_button_audio (_("Calibrate Audio"))
90  , lm_table (12, 3)
91  , have_lm_results (false)
92  , lm_running (false)
93  , midi_back_button (_("Back to settings"))
94  , ignore_changes (0)
95  , _desired_sample_rate (0)
96  , started_at_least_once (false)
97  , queue_device_changed (false)
98 {
99  using namespace Notebook_Helpers;
100  vector<string> backend_names;
101  Label* label;
102  AttachOptions xopt = AttachOptions (FILL|EXPAND);
103  int row;
104 
105  set_name (X_("AudioMIDISetup"));
106 
107  /* the backend combo is the one thing that is ALWAYS visible */
108 
109  vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
110 
111  if (backends.empty()) {
112  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));
113  msg.run ();
114  throw failed_constructor ();
115  }
116 
117  for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
118  backend_names.push_back ((*b)->name);
119  }
120 
121  set_popdown_strings (backend_combo, backend_names);
122  backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
123 
124  /* setup basic packing characteristics for the table used on the main
125  * tab of the notebook
126  */
127 
128  basic_packer.set_spacings (6);
129  basic_packer.set_border_width (12);
130  basic_packer.set_homogeneous (false);
131 
132  /* pack it in */
133 
134  basic_hbox.pack_start (basic_packer, false, false);
135 
136  /* latency measurement tab */
137 
138  lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool")));
139 
140  row = 0;
141  lm_table.set_row_spacings (12);
142  lm_table.set_col_spacings (6);
143  lm_table.set_homogeneous (false);
144 
145  lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
146  row++;
147 
148  lm_preamble.set_width_chars (60);
149  lm_preamble.set_line_wrap (true);
150  lm_preamble.set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
151 
152  lm_table.attach (lm_preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
153  row++;
154 
155  Gtk::Label* preamble;
156  preamble = manage (new Label);
157  preamble->set_width_chars (60);
158  preamble->set_line_wrap (true);
159  preamble->set_markup (_("Select two channels below and connect them using a cable."));
160 
161  lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
162  row++;
163 
164  label = manage (new Label (_("Output channel")));
165  lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
166 
167  Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5));
168  misc_align->add (lm_output_channel_combo);
169  lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
170  ++row;
171 
172  label = manage (new Label (_("Input channel")));
173  lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
174 
175  misc_align = manage (new Alignment (0.0, 0.5));
176  misc_align->add (lm_input_channel_combo);
177  lm_table.attach (*misc_align, 1, 3, row, row+1, FILL, (AttachOptions) 0);
178  ++row;
179 
180  xopt = AttachOptions(0);
181 
182  lm_measure_label.set_padding (10, 10);
184  lm_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
185  lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
186  lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
187 
188  lm_use_button.set_sensitive (false);
189 
190  /* Increase the default spacing around the labels of these three
191  * buttons
192  */
193 
194  Gtk::Misc* l;
195 
196  if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
197  l->set_padding (10, 10);
198  }
199 
200  if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
201  l->set_padding (10, 10);
202  }
203 
204  preamble = manage (new Label);
205  preamble->set_width_chars (60);
206  preamble->set_line_wrap (true);
207  preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
208  lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
209  row++;
210 
211  preamble = manage (new Label);
212  preamble->set_width_chars (60);
213  preamble->set_line_wrap (true);
214  preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button."));
215  lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
216 
217  ++row; // skip a row in the table
218  ++row; // skip a row in the table
219 
220  lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
221 
222  ++row; // skip a row in the table
223  ++row; // skip a row in the table
224 
225  lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
226  lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
227  lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
228 
229  lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
230 
231  lm_vbox.set_border_width (12);
232  lm_vbox.pack_start (lm_table, false, false);
233 
234  midi_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
235 
236  /* pack it all up */
237 
238  notebook.pages().push_back (TabElem (basic_vbox, _("Audio")));
239  notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
240  notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
241  notebook.set_border_width (12);
242 
243  notebook.set_show_tabs (false);
244  notebook.show_all ();
245 
246  notebook.set_name ("SettingsNotebook");
247 
248  /* packup the notebook */
249 
250  get_vbox()->set_border_width (12);
251  get_vbox()->pack_start (notebook);
252 
253  get_action_area()->pack_start (engine_status);
254  engine_status.show();
255 
256  /* need a special function to print "all available channels" when the
257  * channel counts hit zero.
258  */
259 
260  input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels));
261  output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels));
262 
264  midi_devices_button.set_sensitive (false);
265  midi_devices_button.set_name ("generic button");
266  midi_devices_button.set_can_focus(true);
267 
268  control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked));
270 
271  cancel_button = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
272  apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
273  ok_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
274 
275  /* Pick up any existing audio setup configuration, if appropriate */
276 
277  XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
278 
283 
284  if (audio_setup) {
285  set_state (*audio_setup);
286  }
287 
288  if (backend_combo.get_active_text().empty()) {
289  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
290  backend_combo.set_active_text (backend_names.front());
291  }
292 
293  backend_changed ();
294 
295  /* in case the setting the backend failed, e.g. stale config, from set_state(), try again */
296  if (0 == ARDOUR::AudioEngine::instance()->current_backend()) {
297  backend_combo.set_active_text (backend_names.back());
298  /* ignore: don't save state */
299  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
300  backend_changed ();
301  }
302 
303 
304  /* Connect to signals */
305 
306  driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
307  sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed));
308  buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed));
309  device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed));
310  midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_changed));
311 
312  input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
313  output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
314  input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
315  output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed));
316 
317  notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
318 
319  connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click));
320  connect_disconnect_button.set_no_show_all();
321 
322 }
323 
324 void
326 {
328  if (!ARDOUR::AudioEngine::instance()->current_backend() || !ARDOUR::AudioEngine::instance()->running()) {
329  // re-check _have_control (jackd running) see #6041
330  backend_changed ();
331  }
332  device_changed ();
333  ok_button->grab_focus();
334 }
335 
336 void
337 EngineControl::on_response (int response_id)
338 {
339  ArdourDialog::on_response (response_id);
340 
341  switch (response_id) {
342  case RESPONSE_APPLY:
343  push_state_to_backend (true);
344  break;
345  case RESPONSE_OK:
346 #ifdef PLATFORM_WINDOWS
347  // For some reason we don't understand, 'hide()'
348  // needs to get called first in Windows
349  hide ();
350 
351  // But if there's no session open, this can produce
352  // a long gap when nothing appears to be happening.
353  // Let's show the splash image while we're waiting.
355  if ( ARDOUR_UI::instance() ) {
356  if ( !ARDOUR_UI::instance()->session_loaded ) {
358  }
359  }
360  }
361  push_state_to_backend (true);
362  break;
363 #else
364  push_state_to_backend (true);
365  hide ();
366  break;
367 #endif
368  case RESPONSE_DELETE_EVENT:
369  {
370  GdkEventButton ev;
371  ev.type = GDK_BUTTON_PRESS;
372  ev.button = 1;
373  on_delete_event ((GdkEventAny*) &ev);
374  break;
375  }
376  default:
377  hide ();
378  }
379 }
380 
381 void
383 {
384  Label* label;
385  AttachOptions xopt = AttachOptions (FILL|EXPAND);
386 
387  /* clear the table */
388 
391 
392  if (control_app_button.get_parent()) {
393  control_app_button.get_parent()->remove (control_app_button);
394  }
395 
396  label = manage (left_aligned_label (_("Audio System:")));
397  basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
398  basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
399 
401  lm_button_audio.set_name ("generic button");
402  lm_button_audio.set_can_focus(true);
403 
404  if (_have_control) {
406  } else {
408  }
409 
410  basic_vbox.pack_start (basic_hbox, false, false);
411 
412  {
413  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
414  basic_vbox.show_all ();
415  }
416 }
417 
418 void
420 {
422  assert (backend);
423 
424  using namespace Notebook_Helpers;
425  Label* label;
426  vector<string> strings;
427  AttachOptions xopt = AttachOptions (FILL|EXPAND);
428  int row = 1; // row zero == backend combo
429 
430  /* start packing it up */
431 
432  if (backend->requires_driver_selection()) {
433  label = manage (left_aligned_label (_("Driver:")));
434  basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
435  basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
436  row++;
437  }
438 
439  label = manage (left_aligned_label (_("Device:")));
440  basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
441  basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
442  row++;
443 
444  label = manage (left_aligned_label (_("Sample rate:")));
445  basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
446  basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
447  row++;
448 
449 
450  label = manage (left_aligned_label (_("Buffer size:")));
451  basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
452  basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
453  buffer_size_duration_label.set_alignment (0.0); /* left-align */
454  basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
455 
456  /* button spans 2 rows */
457 
458  basic_packer.attach (control_app_button, 3, 4, row-1, row+1, xopt, xopt);
459  row++;
460 
461  input_channels.set_name ("InputChannels");
462  input_channels.set_flags (Gtk::CAN_FOCUS);
463  input_channels.set_digits (0);
464  input_channels.set_wrap (false);
465  output_channels.set_editable (true);
466 
467  if (!ARDOUR::Profile->get_mixbus()) {
468  label = manage (left_aligned_label (_("Input Channels:")));
469  basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
470  basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
471  ++row;
472  }
473 
474  output_channels.set_name ("OutputChannels");
475  output_channels.set_flags (Gtk::CAN_FOCUS);
476  output_channels.set_digits (0);
477  output_channels.set_wrap (false);
478  output_channels.set_editable (true);
479 
480  if (!ARDOUR::Profile->get_mixbus()) {
481  label = manage (left_aligned_label (_("Output Channels:")));
482  basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
483  basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
484  ++row;
485  }
486 
487  input_latency.set_name ("InputLatency");
488  input_latency.set_flags (Gtk::CAN_FOCUS);
489  input_latency.set_digits (0);
490  input_latency.set_wrap (false);
491  input_latency.set_editable (true);
492 
493  label = manage (left_aligned_label (_("Hardware input latency:")));
494  basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
495  basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
496  label = manage (left_aligned_label (_("samples")));
497  basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
498  ++row;
499 
500  output_latency.set_name ("OutputLatency");
501  output_latency.set_flags (Gtk::CAN_FOCUS);
502  output_latency.set_digits (0);
503  output_latency.set_wrap (false);
504  output_latency.set_editable (true);
505 
506  label = manage (left_aligned_label (_("Hardware output latency:")));
507  basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
508  basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
509  label = manage (left_aligned_label (_("samples")));
510  basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
511 
512  /* button spans 2 rows */
513 
514  basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
515  ++row;
516 
517  label = manage (left_aligned_label (_("MIDI System:")));
518  basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
519  basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
520  basic_packer.attach (midi_devices_button, 3, 4, row, row+1, xopt, xopt);
521  row++;
522 }
523 
524 void
526 {
528  assert (backend);
529 
530  using namespace Notebook_Helpers;
531  Label* label;
532  vector<string> strings;
533  AttachOptions xopt = AttachOptions (FILL|EXPAND);
534  int row = 1; // row zero == backend combo
535  const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name());
536 
537  label = manage (new Label);
538  label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
539  basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
540  row++;
541 
542  if (backend->can_change_sample_rate_when_running()) {
543  label = manage (left_aligned_label (_("Sample rate:")));
544  basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
545  basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
546  row++;
547  }
548 
549  if (backend->can_change_buffer_size_when_running()) {
550  label = manage (left_aligned_label (_("Buffer size:")));
551  basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
552  basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
553  buffer_size_duration_label.set_alignment (0.0); /* left-align */
554  basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
555  row++;
556  }
557 
558  basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0));
559  row++;
560 }
561 
563 {
564  ignore_changes = true;
565 }
566 
567 void
569 {
570  vector<string> empty;
573  lm_measure_button.set_sensitive (false);
574  lm_use_button.set_sensitive (false);
575 }
576 
577 void
579 {
580  vector<string> outputs;
581  vector<string> inputs;
582 
586 
587  if (!ARDOUR::AudioEngine::instance()->running()) {
588  MessageDialog msg (_("Failed to start or connect to audio-engine.\n\nLatency calibration requires a working audio interface."));
589  notebook.set_current_page (0);
590  msg.run ();
591  return;
592  }
593  else if (inputs.empty() || outputs.empty()) {
594  MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
595  notebook.set_current_page (0);
596  msg.run ();
597  return;
598  }
599 
600  lm_back_button_signal.disconnect();
601  if (_measure_midi) {
602  lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), midi_tab));
603  lm_preamble.hide ();
604  } else {
605  lm_back_button_signal = lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
606  lm_preamble.show ();
607  }
608 
610  lm_output_channel_combo.set_active_text (outputs.front());
611  lm_output_channel_combo.set_sensitive (true);
612 
614  lm_input_channel_combo.set_active_text (inputs.front());
615  lm_input_channel_combo.set_sensitive (true);
616 
617  lm_measure_button.set_sensitive (true);
618 }
619 
620 void
622 {
623  string backend = backend_combo.get_active_text ();
624 
626 
627  midi_vbox.set_border_width (12);
628  midi_device_table.set_border_width (12);
629 
630  if (backend == "JACK") {
632  }
633 
634  midi_vbox.pack_start (midi_device_table, true, true);
635  midi_vbox.pack_start (midi_back_button, false, false);
636  midi_vbox.show_all ();
637 }
638 
639 void
641 {
642 }
643 
644 void
645 EngineControl::midi_latency_adjustment_changed (Gtk::Adjustment *a, MidiDeviceSettings device, bool for_input) {
646  if (for_input) {
647  device->input_latency = a->get_value();
648  } else {
649  device->output_latency = a->get_value();
650  }
651 }
652 
653 void
655  b->set_active (!b->get_active());
656  device->enabled = b->get_active();
657  refresh_midi_display(device->name);
658 }
659 
660 void
662 {
664  assert (backend);
665 
666  int row = 0;
667  AttachOptions xopt = AttachOptions (FILL|EXPAND);
668  Gtk::Label* l;
669 
671 
672  midi_device_table.set_spacings (6);
673 
674  l = manage (new Label);
675  l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Devices")));
676  midi_device_table.attach (*l, 0, 4, row, row + 1, xopt, AttachOptions (0));
677  l->set_alignment (0.5, 0.5);
678  row++;
679  l->show ();
680 
681  l = manage (new Label (_("Device"))); l->show (); l->set_alignment (0.5, 0.5);
682  midi_device_table.attach (*l, 0, 1, row, row + 2, xopt, AttachOptions (0));
683  l = manage (new Label (_("Hardware Latencies"))); l->show (); l->set_alignment (0.5, 0.5);
684  midi_device_table.attach (*l, 1, 3, row, row + 1, xopt, AttachOptions (0));
685  row++;
686  l = manage (new Label (_("Input"))); l->show (); l->set_alignment (0.5, 0.5);
687  midi_device_table.attach (*l, 1, 2, row, row + 1, xopt, AttachOptions (0));
688  l = manage (new Label (_("Output"))); l->show (); l->set_alignment (0.5, 0.5);
689  midi_device_table.attach (*l, 2, 3, row, row + 1, xopt, AttachOptions (0));
690  row++;
691 
692  for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
693  ArdourButton *m;
694  Gtk::Button* b;
695  Gtk::Adjustment *a;
696  Gtk::SpinButton *s;
697  bool enabled = (*p)->enabled;
698 
699  m = manage (new ArdourButton ((*p)->name, ArdourButton::led_default_elements));
700  m->set_name ("midi device");
701  m->set_can_focus (Gtk::CAN_FOCUS);
702  m->add_events (Gdk::BUTTON_RELEASE_MASK);
703  m->set_active (enabled);
704  m->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_device_enabled_toggled), m, *p));
705  midi_device_table.attach (*m, 0, 1, row, row + 1, xopt, AttachOptions (0)); m->show ();
706  if ((*p)->name == focus) {
707  m->grab_focus();
708  }
709 
710  a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
711  s = manage (new Gtk::SpinButton (*a));
712  a->set_value ((*p)->input_latency);
713  s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, true));
714  s->set_sensitive (_can_set_midi_latencies && enabled);
715  midi_device_table.attach (*s, 1, 2, row, row + 1, xopt, AttachOptions (0)); s->show ();
716 
717  a = manage (new Gtk::Adjustment (0, 0, 99999, 1));
718  s = manage (new Gtk::SpinButton (*a));
719  a->set_value ((*p)->output_latency);
720  s->signal_value_changed().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::midi_latency_adjustment_changed), a, *p, false));
721  s->set_sensitive (_can_set_midi_latencies && enabled);
722  midi_device_table.attach (*s, 2, 3, row, row + 1, xopt, AttachOptions (0)); s->show ();
723 
724  b = manage (new Button (_("Calibrate")));
725  b->signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency), *p));
726  b->set_sensitive (_can_set_midi_latencies && enabled);
727  midi_device_table.attach (*b, 3, 4, row, row + 1, xopt, AttachOptions (0)); b->show ();
728 
729  row++;
730  }
731 }
732 
733 void
735 {
736 }
737 
738 void
740 {
741  string backend_name = backend_combo.get_active_text();
743 
744  if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
745  /* eh? setting the backend failed... how ? */
746  /* A: stale config contains a backend that does not exist in current build */
747  return;
748  }
749 
751 
752  build_notebook ();
754  _midi_devices.clear();
755 
756  if (backend->requires_driver_selection()) {
757  vector<string> drivers = backend->enumerate_drivers();
758  driver_combo.set_sensitive (true);
759 
760  if (!drivers.empty()) {
761  {
762  string current_driver;
763  current_driver = backend->driver_name ();
764 
765  // driver might not have been set yet
766  if (current_driver == "") {
767  current_driver = driver_combo.get_active_text ();
768  if (current_driver == "")
769  // driver has never been set, make sure it's not blank
770  current_driver = drivers.front ();
771  }
772 
773  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
775  driver_combo.set_active_text (current_driver);
776  }
777 
778  driver_changed ();
779  }
780 
781  } else {
782  driver_combo.set_sensitive (false);
783  /* this will change the device text which will cause a call to
784  * device changed which will set up parameters
785  */
786  list_devices ();
787  }
788 
789  vector<string> midi_options = backend->enumerate_midi_options();
790 
791  if (midi_options.size() == 1) {
792  /* only contains the "none" option */
793  midi_option_combo.set_sensitive (false);
794  } else {
795  if (_have_control) {
796  set_popdown_strings (midi_option_combo, midi_options);
797  midi_option_combo.set_active_text (midi_options.front());
798  midi_option_combo.set_sensitive (true);
799  } else {
800  midi_option_combo.set_sensitive (false);
801  }
802  }
803 
805 
807 
808  started_at_least_once = false;
809 
810  if (!ignore_changes) {
812  }
813 }
814 
815 bool
817 {
818  if (ARDOUR::Profile->get_mixbus()) {
819  return true;
820  }
821 
822  uint32_t cnt = (uint32_t) sb->get_value();
823  if (cnt == 0) {
824  sb->set_text (_("all available channels"));
825  } else {
826  char buf[32];
827  snprintf (buf, sizeof (buf), "%d", cnt);
828  sb->set_text (buf);
829  }
830  return true;
831 }
832 
833 void
835 {
837  assert (backend);
838 
839  /* now fill out devices, mark sample rates, buffer sizes insensitive */
840 
841  vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
842 
843  /* NOTE: Ardour currently does not display the "available" field of the
844  * returned devices.
845  *
846  * Doing so would require a different GUI widget than the combo
847  * box/popdown that we currently use, since it has no way to list
848  * items that are not selectable. Something more like a popup menu,
849  * which could have unselectable items, would be appropriate.
850  */
851 
852  vector<string> available_devices;
853 
854  for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
855  available_devices.push_back (i->name);
856  }
857 
858  if (!available_devices.empty()) {
859 
861 
862  {
863  string current_device, found_device;
864  current_device = device_combo.get_active_text ();
865  if (current_device == "") {
866  current_device = backend->device_name ();
867  }
868 
869  // Make sure that the active text is still relevant for this
870  // device (it might only be relevant to the previous device!!)
871  for (vector<string>::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) {
872  if (*i == current_device)
873  found_device = current_device;
874  }
875  if (found_device == "")
876  // device has never been set (or was not relevant
877  // for this backend) Let's make sure it's not blank
878  current_device = available_devices.front ();
879 
880  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
881  set_popdown_strings (device_combo, available_devices);
882 
883  device_combo.set_active_text (current_device);
884  }
885 
886  device_changed ();
887 
888  input_latency.set_sensitive (true);
889  output_latency.set_sensitive (true);
890  input_channels.set_sensitive (true);
891  output_channels.set_sensitive (true);
892 
893  ok_button->set_sensitive (true);
894  apply_button->set_sensitive (true);
895 
896  } else {
897  device_combo.clear();
898  sample_rate_combo.set_sensitive (false);
899  buffer_size_combo.set_sensitive (false);
900  input_latency.set_sensitive (false);
901  output_latency.set_sensitive (false);
902  input_channels.set_sensitive (false);
903  output_channels.set_sensitive (false);
904  if (_have_control) {
905  ok_button->set_sensitive (false);
906  apply_button->set_sensitive (false);
907  } else {
908  ok_button->set_sensitive (true);
909  apply_button->set_sensitive (true);
910  if (backend->can_change_sample_rate_when_running() && sample_rate_combo.get_children().size() > 0) {
911  sample_rate_combo.set_sensitive (true);
912  }
913  if (backend->can_change_buffer_size_when_running() && buffer_size_combo.get_children().size() > 0) {
914  buffer_size_combo.set_sensitive (true);
915  }
916 
917  }
918  }
919 }
920 
921 void
923 {
925  assert (backend);
926 
927  backend->set_driver (driver_combo.get_active_text());
928  list_devices ();
929 
930  if (!ignore_changes) {
932  }
933 }
934 
935 void
937 {
938 
940  assert (backend);
941  string device_name = device_combo.get_active_text ();
942  vector<string> s;
943 
944  if (device_name != backend->device_name()) {
945  /* we set the backend-device to query various device related intormation.
946  * This has the side effect that backend->device_name() will match
947  * the device_name and 'change_device' will never be true.
948  * so work around this by setting...
949  */
950  queue_device_changed = true;
951  }
952 
953  //the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
954  backend->set_device_name(device_name);
955 
956  {
957  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
958 
959  /* don't allow programmatic change to combos to cause a
960  recursive call to this method.
961  */
962 
963  /* sample rates */
964 
965  string desired;
966 
967  vector<float> sr;
968 
969  if (_have_control) {
970  sr = backend->available_sample_rates (device_name);
971  } else {
972 
973  sr.push_back (8000.0f);
974  sr.push_back (16000.0f);
975  sr.push_back (32000.0f);
976  sr.push_back (44100.0f);
977  sr.push_back (48000.0f);
978  sr.push_back (88200.0f);
979  sr.push_back (96000.0f);
980  sr.push_back (192000.0f);
981  sr.push_back (384000.0f);
982  }
983 
984  for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
985  s.push_back (rate_as_string (*x));
986  if (*x == _desired_sample_rate) {
987  desired = s.back();
988  }
989  }
990 
991  if (!s.empty()) {
992  sample_rate_combo.set_sensitive (true);
994 
995  if (desired.empty()) {
996  sample_rate_combo.set_active_text (rate_as_string (backend->default_sample_rate()));
997  } else {
998  sample_rate_combo.set_active_text (desired);
999  }
1000 
1001  } else {
1002  sample_rate_combo.set_sensitive (false);
1003  }
1004 
1005  /* buffer sizes */
1006 
1007  vector<uint32_t> bs;
1008 
1009  if (_have_control) {
1010  bs = backend->available_buffer_sizes (device_name);
1011  } else if (backend->can_change_buffer_size_when_running()) {
1012  bs.push_back (8);
1013  bs.push_back (16);
1014  bs.push_back (32);
1015  bs.push_back (64);
1016  bs.push_back (128);
1017  bs.push_back (256);
1018  bs.push_back (512);
1019  bs.push_back (1024);
1020  bs.push_back (2048);
1021  bs.push_back (4096);
1022  bs.push_back (8192);
1023  }
1024  s.clear ();
1025  for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
1026  s.push_back (bufsize_as_string (*x));
1027  }
1028 
1029  if (!s.empty()) {
1030  buffer_size_combo.set_sensitive (true);
1032 
1033  uint32_t period = backend->buffer_size();
1034  if (0 == period) {
1035  period = backend->default_buffer_size(device_name);
1036  }
1039  } else {
1040  buffer_size_combo.set_sensitive (false);
1041  }
1042 
1043  /* XXX theoretically need to set min + max channel counts here
1044  */
1045 
1047  }
1048 
1049  /* pick up any saved state for this device */
1050 
1051  if (!ignore_changes) {
1053  }
1054 }
1055 
1056 string
1058 {
1059  /* Translators: "samples" is always plural here, so no
1060  need for plural+singular forms.
1061  */
1062  char buf[64];
1063  snprintf (buf, sizeof (buf), "%u %s", sz, P_("sample", "samples", sz));
1064  return buf;
1065 }
1066 
1067 void
1069 {
1070  /* reset the strings for buffer size to show the correct msec value
1071  (reflecting the new sample rate).
1072  */
1073 
1075 
1076 }
1077 
1078 void
1080 {
1082 }
1083 
1084 void
1086 {
1087 
1088  /* buffer sizes - convert from just samples to samples + msecs for
1089  * the displayed string
1090  */
1091 
1092  string bs_text = buffer_size_combo.get_active_text ();
1093  uint32_t samples = atoi (bs_text); /* will ignore trailing text */
1094  uint32_t rate = get_rate();
1095 
1096  /* Developers: note the hard-coding of a double buffered model
1097  in the (2 * samples) computation of latency. we always start
1098  the audiobackend in this configuration.
1099  */
1100  /* note to jack1 developers: ardour also always starts the engine
1101  * in async mode (no jack2 --sync option) which adds an extra cycle
1102  * of latency with jack2 (and *3 would be correct)
1103  * The value can also be wrong if jackd is started externally..
1104  *
1105  * At the time of writing the ALSA backend always uses double-buffering *2,
1106  * The Dummy backend *1, and who knows what ASIO really does :)
1107  *
1108  * So just display the period size, that's also what
1109  * ARDOUR_UI::update_sample_rate() does for the status bar.
1110  * (the statusbar calls AudioEngine::instance()->usecs_per_cycle()
1111  * but still, that's the buffer period, not [round-trip] latency)
1112  */
1113  char buf[32];
1114  snprintf (buf, sizeof (buf), _("(%.1f ms)"), (samples / (rate/1000.0f)));
1115  buffer_size_duration_label.set_text (buf);
1116 }
1117 
1118 void
1120 {
1122  assert (backend);
1123 
1124  backend->set_midi_option (get_midi_option());
1125 
1126  vector<ARDOUR::AudioBackend::DeviceStatus> midi_devices = backend->enumerate_midi_devices();
1127 
1128  //_midi_devices.clear(); // TODO merge with state-saved settings..
1130  std::vector<MidiDeviceSettings> new_devices;
1131 
1132  for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = midi_devices.begin(); i != midi_devices.end(); ++i) {
1133  MidiDeviceSettings mds = find_midi_device (i->name);
1134  if (i->available && !mds) {
1135  uint32_t input_latency = 0;
1136  uint32_t output_latency = 0;
1138  input_latency = backend->systemic_midi_input_latency (i->name);
1139  output_latency = backend->systemic_midi_output_latency (i->name);
1140  }
1141  bool enabled = backend->midi_device_enabled (i->name);
1142  MidiDeviceSettings ptr (new MidiDeviceSetting (i->name, enabled, input_latency, output_latency));
1143  new_devices.push_back (ptr);
1144  } else if (i->available) {
1145  new_devices.push_back (mds);
1146  }
1147  }
1148  _midi_devices = new_devices;
1149 
1150  if (_midi_devices.empty()) {
1151  midi_devices_button.set_sensitive (false);
1152  } else {
1153  midi_devices_button.set_sensitive (true);
1154  }
1155 }
1156 
1157 void
1159 {
1160 }
1161 
1164  const string& backend,
1165  const string& driver,
1166  const string& device)
1167 {
1168  for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1169  if ((*i)->backend == backend &&
1170  (!_have_control || ((*i)->driver == driver && (*i)->device == device)))
1171  {
1172  return (*i);
1173  }
1174  }
1175  return State();
1176 }
1177 
1180 {
1182 
1183  if (backend) {
1184  return get_matching_state (backend_combo.get_active_text(),
1185  (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
1186  device_combo.get_active_text());
1187  }
1188 
1189 
1190  return get_matching_state (backend_combo.get_active_text(),
1191  string(),
1192  device_combo.get_active_text());
1193 }
1194 
1197 {
1198  State state;
1199 
1200  if (!_have_control) {
1201  state = get_matching_state (backend_combo.get_active_text(), string(), string());
1202  if (state) {
1203  return state;
1204  }
1205  state.reset(new StateStruct);
1206  state->backend = get_backend ();
1207  } else {
1208  state.reset(new StateStruct);
1209  store_state (state);
1210  }
1211 
1212  for (StateList::iterator i = states.begin(); i != states.end();) {
1213  if ((*i)->backend == state->backend &&
1214  (*i)->driver == state->driver &&
1215  (*i)->device == state->device) {
1216  i = states.erase(i);
1217  } else {
1218  ++i;
1219  }
1220  }
1221 
1222  states.push_back (state);
1223 
1224  return state;
1225 }
1226 
1227 void
1229 {
1230  state->backend = get_backend ();
1231  state->driver = get_driver ();
1232  state->device = get_device_name ();
1233  state->sample_rate = get_rate ();
1234  state->buffer_size = get_buffer_size ();
1235  state->input_latency = get_input_latency ();
1236  state->output_latency = get_output_latency ();
1237  state->input_channels = get_input_channels ();
1238  state->output_channels = get_output_channels ();
1239  state->midi_option = get_midi_option ();
1240  state->midi_devices = _midi_devices;
1241 }
1242 
1243 void
1245 {
1246  if (!_have_control) {
1247  return;
1248  }
1249 
1251 
1252  if (state) {
1253  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1254 
1255  if (!_desired_sample_rate) {
1256  sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
1257  }
1259  /* call this explicitly because we're ignoring changes to
1260  the controls at this point.
1261  */
1263  input_latency.set_value (state->input_latency);
1264  output_latency.set_value (state->output_latency);
1265 
1266  if (!state->midi_option.empty()) {
1267  midi_option_combo.set_active_text (state->midi_option);
1268  _midi_devices = state->midi_devices;
1269  }
1270  }
1271 }
1272 
1273 XMLNode&
1275 {
1276  XMLNode* root = new XMLNode ("AudioMIDISetup");
1277  std::string path;
1278 
1279  if (!states.empty()) {
1280  XMLNode* state_nodes = new XMLNode ("EngineStates");
1281 
1282  for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1283 
1284  XMLNode* node = new XMLNode ("State");
1285 
1286  node->add_property ("backend", (*i)->backend);
1287  node->add_property ("driver", (*i)->driver);
1288  node->add_property ("device", (*i)->device);
1289  node->add_property ("sample-rate", (*i)->sample_rate);
1290  node->add_property ("buffer-size", (*i)->buffer_size);
1291  node->add_property ("input-latency", (*i)->input_latency);
1292  node->add_property ("output-latency", (*i)->output_latency);
1293  node->add_property ("input-channels", (*i)->input_channels);
1294  node->add_property ("output-channels", (*i)->output_channels);
1295  node->add_property ("active", (*i)->active ? "yes" : "no");
1296  node->add_property ("midi-option", (*i)->midi_option);
1297 
1298  XMLNode* midi_devices = new XMLNode ("MIDIDevices");
1299  for (std::vector<MidiDeviceSettings>::const_iterator p = (*i)->midi_devices.begin(); p != (*i)->midi_devices.end(); ++p) {
1300  XMLNode* midi_device_stuff = new XMLNode ("MIDIDevice");
1301  midi_device_stuff->add_property (X_("name"), (*p)->name);
1302  midi_device_stuff->add_property (X_("enabled"), (*p)->enabled);
1303  midi_device_stuff->add_property (X_("input-latency"), (*p)->input_latency);
1304  midi_device_stuff->add_property (X_("output-latency"), (*p)->output_latency);
1305  midi_devices->add_child_nocopy (*midi_device_stuff);
1306  }
1307  node->add_child_nocopy (*midi_devices);
1308 
1309  state_nodes->add_child_nocopy (*node);
1310  }
1311 
1312  root->add_child_nocopy (*state_nodes);
1313  }
1314 
1315  return *root;
1316 }
1317 
1318 void
1320 {
1321  XMLNodeList clist, cclist;
1322  XMLNodeConstIterator citer, cciter;
1323  XMLNode* child;
1324  XMLNode* grandchild;
1325  XMLProperty* prop = NULL;
1326 
1327  if (root.name() != "AudioMIDISetup") {
1328  return;
1329  }
1330 
1331  clist = root.children();
1332 
1333  states.clear ();
1334 
1335  for (citer = clist.begin(); citer != clist.end(); ++citer) {
1336 
1337  child = *citer;
1338 
1339  if (child->name() != "EngineStates") {
1340  continue;
1341  }
1342 
1343  cclist = child->children();
1344 
1345  for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
1346  State state (new StateStruct);
1347 
1348  grandchild = *cciter;
1349 
1350  if (grandchild->name() != "State") {
1351  continue;
1352  }
1353 
1354  if ((prop = grandchild->property ("backend")) == 0) {
1355  continue;
1356  }
1357  state->backend = prop->value ();
1358 
1359  if ((prop = grandchild->property ("driver")) == 0) {
1360  continue;
1361  }
1362  state->driver = prop->value ();
1363 
1364  if ((prop = grandchild->property ("device")) == 0) {
1365  continue;
1366  }
1367  state->device = prop->value ();
1368 
1369  if ((prop = grandchild->property ("sample-rate")) == 0) {
1370  continue;
1371  }
1372  state->sample_rate = atof (prop->value ());
1373 
1374  if ((prop = grandchild->property ("buffer-size")) == 0) {
1375  continue;
1376  }
1377  state->buffer_size = atoi (prop->value ());
1378 
1379  if ((prop = grandchild->property ("input-latency")) == 0) {
1380  continue;
1381  }
1382  state->input_latency = atoi (prop->value ());
1383 
1384  if ((prop = grandchild->property ("output-latency")) == 0) {
1385  continue;
1386  }
1387  state->output_latency = atoi (prop->value ());
1388 
1389  if ((prop = grandchild->property ("input-channels")) == 0) {
1390  continue;
1391  }
1392  state->input_channels = atoi (prop->value ());
1393 
1394  if ((prop = grandchild->property ("output-channels")) == 0) {
1395  continue;
1396  }
1397  state->output_channels = atoi (prop->value ());
1398 
1399  if ((prop = grandchild->property ("active")) == 0) {
1400  continue;
1401  }
1402  state->active = string_is_affirmative (prop->value ());
1403 
1404  if ((prop = grandchild->property ("midi-option")) == 0) {
1405  continue;
1406  }
1407  state->midi_option = prop->value ();
1408 
1409  state->midi_devices.clear();
1410  XMLNode* midinode;
1411  if ((midinode = ARDOUR::find_named_node (*grandchild, "MIDIDevices")) != 0) {
1412  const XMLNodeList mnc = midinode->children();
1413  for (XMLNodeList::const_iterator n = mnc.begin(); n != mnc.end(); ++n) {
1414  if ((*n)->property (X_("name")) == 0
1415  || (*n)->property (X_("enabled")) == 0
1416  || (*n)->property (X_("input-latency")) == 0
1417  || (*n)->property (X_("output-latency")) == 0
1418  ) {
1419  continue;
1420  }
1421 
1423  (*n)->property (X_("name"))->value (),
1424  string_is_affirmative ((*n)->property (X_("enabled"))->value ()),
1425  atoi ((*n)->property (X_("input-latency"))->value ()),
1426  atoi ((*n)->property (X_("output-latency"))->value ())
1427  ));
1428  state->midi_devices.push_back (ptr);
1429  }
1430  }
1431 
1432 #if 1
1433  /* remove accumulated duplicates (due to bug in ealier version)
1434  * this can be removed again before release
1435  */
1436  for (StateList::iterator i = states.begin(); i != states.end();) {
1437  if ((*i)->backend == state->backend &&
1438  (*i)->driver == state->driver &&
1439  (*i)->device == state->device) {
1440  i = states.erase(i);
1441  } else {
1442  ++i;
1443  }
1444  }
1445 #endif
1446 
1447  states.push_back (state);
1448  }
1449  }
1450 
1451  /* now see if there was an active state and switch the setup to it */
1452 
1453  // purge states of backend that are not available in this built
1454  vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
1455  vector<std::string> backend_names;
1456 
1457  for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator i = backends.begin(); i != backends.end(); ++i) {
1458  backend_names.push_back((*i)->name);
1459  }
1460  for (StateList::iterator i = states.begin(); i != states.end();) {
1461  if (std::find(backend_names.begin(), backend_names.end(), (*i)->backend) == backend_names.end()) {
1462  i = states.erase(i);
1463  } else {
1464  ++i;
1465  }
1466  }
1467 
1468  for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
1469 
1470  if ((*i)->active) {
1471  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1472  backend_combo.set_active_text ((*i)->backend);
1473  driver_combo.set_active_text ((*i)->driver);
1474  device_combo.set_active_text ((*i)->device);
1475  sample_rate_combo.set_active_text (rate_as_string ((*i)->sample_rate));
1477  input_latency.set_value ((*i)->input_latency);
1478  output_latency.set_value ((*i)->output_latency);
1479  midi_option_combo.set_active_text ((*i)->midi_option);
1480  break;
1481  }
1482  }
1483 }
1484 
1485 int
1487 {
1489 
1490  if (!backend) {
1491  return 0;
1492  }
1493 
1494  /* figure out what is going to change */
1495 
1496  bool restart_required = false;
1497  bool was_running = ARDOUR::AudioEngine::instance()->running();
1498  bool change_driver = false;
1499  bool change_device = false;
1500  bool change_rate = false;
1501  bool change_bufsize = false;
1502  bool change_latency = false;
1503  bool change_channels = false;
1504  bool change_midi = false;
1505 
1506  uint32_t ochan = get_output_channels ();
1507  uint32_t ichan = get_input_channels ();
1508 
1509  if (_have_control) {
1510 
1511  if (started_at_least_once) {
1512 
1513  /* we can control the backend */
1514 
1515  if (backend->requires_driver_selection()) {
1516  if (get_driver() != backend->driver_name()) {
1517  change_driver = true;
1518  }
1519  }
1520 
1521  if (queue_device_changed || get_device_name() != backend->device_name()) {
1522  change_device = true;
1523  }
1524 
1525  if (get_rate() != backend->sample_rate()) {
1526  change_rate = true;
1527  }
1528 
1529  if (get_buffer_size() != backend->buffer_size()) {
1530  change_bufsize = true;
1531  }
1532 
1533  if (get_midi_option() != backend->midi_option()) {
1534  change_midi = true;
1535  }
1536 
1537  /* zero-requested channels means "all available" */
1538 
1539  if (ichan == 0) {
1540  ichan = backend->input_channels();
1541  }
1542 
1543  if (ochan == 0) {
1544  ochan = backend->output_channels();
1545  }
1546 
1547  if (ichan != backend->input_channels()) {
1548  change_channels = true;
1549  }
1550 
1551  if (ochan != backend->output_channels()) {
1552  change_channels = true;
1553  }
1554 
1555  if (get_input_latency() != backend->systemic_input_latency() ||
1556  get_output_latency() != backend->systemic_output_latency()) {
1557  change_latency = true;
1558  }
1559  } else {
1560  /* backend never started, so we have to force a group
1561  of settings.
1562  */
1563  change_device = true;
1564  if (backend->requires_driver_selection()) {
1565  change_driver = true;
1566  }
1567  change_rate = true;
1568  change_bufsize = true;
1569  change_channels = true;
1570  change_latency = true;
1571  change_midi = true;
1572  }
1573 
1574  } else {
1575 
1576  /* we have no control over the backend, meaning that we can
1577  * only possibly change sample rate and buffer size.
1578  */
1579 
1580 
1581  if (get_rate() != backend->sample_rate()) {
1582  change_bufsize = true;
1583  }
1584 
1585  if (get_buffer_size() != backend->buffer_size()) {
1586  change_bufsize = true;
1587  }
1588  }
1589 
1590  queue_device_changed = false;
1591 
1592  if (!_have_control) {
1593 
1594  /* We do not have control over the backend, so the best we can
1595  * do is try to change the sample rate and/or bufsize and get
1596  * out of here.
1597  */
1598 
1599  if (change_rate && !backend->can_change_sample_rate_when_running()) {
1600  return 1;
1601  }
1602 
1603  if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1604  return 1;
1605  }
1606 
1607  if (change_rate) {
1608  backend->set_sample_rate (get_rate());
1609  }
1610 
1611  if (change_bufsize) {
1612  backend->set_buffer_size (get_buffer_size());
1613  }
1614 
1615  if (start) {
1616  if (ARDOUR::AudioEngine::instance()->start ()) {
1617  error << string_compose (_("Could not start backend engine %1"), backend->name()) << endmsg;
1618  return -1;
1619  }
1620  }
1621 
1622  post_push ();
1623 
1624  return 0;
1625  }
1626 
1627  /* determine if we need to stop the backend before changing parameters */
1628 
1629  if (change_driver || change_device || change_channels || change_latency ||
1630  (change_rate && !backend->can_change_sample_rate_when_running()) ||
1631  change_midi ||
1632  (change_bufsize && !backend->can_change_buffer_size_when_running())) {
1633  restart_required = true;
1634  } else {
1635  restart_required = false;
1636  }
1637 
1638  if (was_running) {
1639 
1640  if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
1641  /* no changes in any parameters that absolutely require a
1642  * restart, so check those that might be changeable without a
1643  * restart
1644  */
1645 
1646  if (change_rate && !backend->can_change_sample_rate_when_running()) {
1647  /* can't do this while running ... */
1648  restart_required = true;
1649  }
1650 
1651  if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
1652  /* can't do this while running ... */
1653  restart_required = true;
1654  }
1655  }
1656  }
1657 
1658  if (was_running) {
1659  if (restart_required) {
1661  return -1;
1662  }
1663  }
1664  }
1665 
1666 
1667  if (change_driver && backend->set_driver (get_driver())) {
1668  error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
1669  return -1;
1670  }
1671  if (change_device && backend->set_device_name (get_device_name())) {
1672  error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
1673  return -1;
1674  }
1675  if (change_rate && backend->set_sample_rate (get_rate())) {
1676  error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
1677  return -1;
1678  }
1679  if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
1680  error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
1681  return -1;
1682  }
1683 
1684  if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
1685  if (backend->set_input_channels (get_input_channels())) {
1686  error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
1687  return -1;
1688  }
1689  if (backend->set_output_channels (get_output_channels())) {
1690  error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
1691  return -1;
1692  }
1693  }
1694  if (change_latency) {
1695  if (backend->set_systemic_input_latency (get_input_latency())) {
1696  error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
1697  return -1;
1698  }
1700  error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
1701  return -1;
1702  }
1703  }
1704 
1705  if (change_midi) {
1706  backend->set_midi_option (get_midi_option());
1707  }
1708 
1709  if (1 /* TODO */) {
1710  for (vector<MidiDeviceSettings>::const_iterator p = _midi_devices.begin(); p != _midi_devices.end(); ++p) {
1711  if (_measure_midi) {
1712  if (*p == _measure_midi) {
1713  backend->set_midi_device_enabled ((*p)->name, true);
1714  } else {
1715  backend->set_midi_device_enabled ((*p)->name, false);
1716  }
1717  continue;
1718  }
1719  backend->set_midi_device_enabled ((*p)->name, (*p)->enabled);
1720  if (backend->can_set_systemic_midi_latencies()) {
1721  backend->set_systemic_midi_input_latency ((*p)->name, (*p)->input_latency);
1722  backend->set_systemic_midi_output_latency ((*p)->name, (*p)->output_latency);
1723  }
1724  }
1725  }
1726 
1727  if (start || (was_running && restart_required)) {
1728  if (ARDOUR_UI::instance()->reconnect_to_engine()) {
1729  return -1;
1730  }
1731  }
1732 
1733  post_push ();
1734 
1735  return 0;
1736 }
1737 
1738 void
1740 {
1741  /* get a pointer to the current state object, creating one if
1742  * necessary
1743  */
1744 
1746 
1747  if (!state) {
1748  state = save_state ();
1749  assert (state);
1750  } else {
1751  store_state(state);
1752  }
1753 
1754  /* all off */
1755 
1756  for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
1757  (*i)->active = false;
1758  }
1759 
1760  /* mark this one active (to be used next time the dialog is
1761  * shown)
1762  */
1763 
1764  state->active = true;
1765 
1766  if (_have_control) { // XXX
1768  }
1769 
1770  /* schedule a redisplay of MIDI ports */
1771  //Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
1772 }
1773 
1774 
1775 float
1777 {
1778  float r = atof (sample_rate_combo.get_active_text ());
1779  /* the string may have been translated with an abbreviation for
1780  * thousands, so use a crude heuristic to fix this.
1781  */
1782  if (r < 1000.0) {
1783  r *= 1000.0;
1784  }
1785  return r;
1786 }
1787 
1788 
1789 uint32_t
1791 {
1792  string txt = buffer_size_combo.get_active_text ();
1793  uint32_t samples;
1794 
1795  if (sscanf (txt.c_str(), "%d", &samples) != 1) {
1796  fprintf(stderr, "Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them.\n");
1797  fprintf(stderr, "Ardour will likely crash now, giving you time to get the trout.\n");
1798  throw exception ();
1799  }
1800 
1801  return samples;
1802 }
1803 
1804 string
1806 {
1807  return midi_option_combo.get_active_text();
1808 }
1809 
1810 uint32_t
1812 {
1813  if (ARDOUR::Profile->get_mixbus()) {
1815  if (!backend) return 0;
1816  return backend->input_channels();
1817  }
1818  return (uint32_t) input_channels_adjustment.get_value();
1819 }
1820 
1821 uint32_t
1823 {
1824  if (ARDOUR::Profile->get_mixbus()) {
1826  if (!backend) return 0;
1827  return backend->input_channels();
1828  }
1829  return (uint32_t) output_channels_adjustment.get_value();
1830 }
1831 
1832 uint32_t
1834 {
1835  return (uint32_t) input_latency_adjustment.get_value();
1836 }
1837 
1838 uint32_t
1840 {
1841  return (uint32_t) output_latency_adjustment.get_value();
1842 }
1843 
1844 string
1846 {
1847  return backend_combo.get_active_text ();
1848 }
1849 
1850 string
1852 {
1853  if (driver_combo.get_sensitive() && driver_combo.get_parent()) {
1854  return driver_combo.get_active_text ();
1855  } else {
1856  return "";
1857  }
1858 }
1859 
1860 string
1862 {
1863  return device_combo.get_active_text ();
1864 }
1865 
1866 void
1868 {
1870 
1871  if (!backend) {
1872  return;
1873  }
1874 
1875  backend->launch_control_app ();
1876 }
1877 
1878 void
1880 {
1882 
1883  if (!backend) {
1884  return;
1885  }
1886 
1887  string appname = backend->control_app_name();
1888 
1889  if (appname.empty()) {
1890  control_app_button.set_sensitive (false);
1891  } else {
1892  control_app_button.set_sensitive (true);
1893  }
1894 }
1895 
1896 void
1898 {
1899  _desired_sample_rate = sr;
1900  device_changed ();
1901 }
1902 
1903 void
1904 EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
1905 {
1906  if (page_num == 0) {
1907  cancel_button->set_sensitive (true);
1908  ok_button->set_sensitive (true);
1909  apply_button->set_sensitive (true);
1910  _measure_midi.reset();
1911  } else {
1912  cancel_button->set_sensitive (false);
1913  ok_button->set_sensitive (false);
1914  apply_button->set_sensitive (false);
1915  }
1916 
1917  if (page_num == midi_tab) {
1918  /* MIDI tab */
1920  }
1921 
1922  if (page_num == latency_tab) {
1923  /* latency tab */
1924 
1925  if (ARDOUR::AudioEngine::instance()->running()) {
1926  // TODO - mark as 'stopped for latency
1928  }
1929 
1930  {
1931  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
1932 
1933  /* save any existing latency values */
1934 
1935  uint32_t il = (uint32_t) input_latency.get_value ();
1936  uint32_t ol = (uint32_t) input_latency.get_value ();
1937 
1938  /* reset to zero so that our new test instance
1939  will be clean of any existing latency measures.
1940 
1941  NB. this should really be done by the backend
1942  when stated for latency measurement.
1943  */
1944 
1945  input_latency.set_value (0);
1946  output_latency.set_value (0);
1947 
1948  push_state_to_backend (false);
1949 
1950  /* reset control */
1951 
1952  input_latency.set_value (il);
1953  output_latency.set_value (ol);
1954 
1955  }
1956  // This should be done in push_state_to_backend()
1957  if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
1959  }
1960 
1961  enable_latency_tab ();
1962 
1963  } else {
1964  if (lm_running) {
1967  }
1968  }
1969 }
1970 
1971 /* latency measurement */
1972 
1973 bool
1975 {
1976  MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
1977 
1978  if (mtdm->resolve () < 0) {
1979  lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
1980  return true;
1981  }
1982 
1983  if (mtdm->err () > 0.3) {
1984  mtdm->invert ();
1985  mtdm->resolve ();
1986  }
1987 
1988  char buf[256];
1990 
1991  if (sample_rate == 0) {
1992  lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
1994  return false;
1995  }
1996 
1997  int frames_total = mtdm->del();
1998  int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
1999 
2000  snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
2001  _("Detected roundtrip latency: "),
2002  frames_total, frames_total * 1000.0f/sample_rate,
2003  _("Systemic latency: "),
2004  extra, extra * 1000.0f/sample_rate);
2005 
2006  bool solid = true;
2007 
2008  if (mtdm->err () > 0.2) {
2009  strcat (buf, " ");
2010  strcat (buf, _("(signal detection error)"));
2011  solid = false;
2012  }
2013 
2014  if (mtdm->inv ()) {
2015  strcat (buf, " ");
2016  strcat (buf, _("(inverted - bad wiring)"));
2017  solid = false;
2018  }
2019 
2020  lm_results.set_markup (string_compose (results_markup, buf));
2021 
2022  if (solid) {
2023  have_lm_results = true;
2025  lm_use_button.set_sensitive (true);
2026  return false;
2027  }
2028 
2029  return true;
2030 }
2031 
2032 bool
2034 {
2036 
2037  if (!mididm->have_signal () || mididm->latency () == 0) {
2038  lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
2039  return true;
2040  }
2041 
2042  char buf[256];
2044 
2045  if (sample_rate == 0) {
2046  lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
2048  return false;
2049  }
2050 
2051  ARDOUR::framecnt_t frames_total = mididm->latency();
2053  snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
2054  _("Detected roundtrip latency: "),
2055  frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
2056  _("Systemic latency: "),
2057  extra, extra * 1000.0f / sample_rate);
2058 
2059  bool solid = true;
2060 
2061  if (!mididm->ok ()) {
2062  strcat (buf, " ");
2063  strcat (buf, _("(averaging)"));
2064  solid = false;
2065  }
2066 
2067  if (mididm->deviation () > 50.0) {
2068  strcat (buf, " ");
2069  strcat (buf, _("(too large jitter)"));
2070  solid = false;
2071  } else if (mididm->deviation () > 10.0) {
2072  strcat (buf, " ");
2073  strcat (buf, _("(large jitter)"));
2074  }
2075 
2076  if (solid) {
2077  have_lm_results = true;
2079  lm_use_button.set_sensitive (true);
2080  lm_results.set_markup (string_compose (results_markup, buf));
2081  return false;
2082  } else if (mididm->processed () > 400) {
2083  have_lm_results = false;
2085  lm_results.set_markup (string_compose (results_markup, _("Timeout - large MIDI jitter.")));
2086  return false;
2087  }
2088 
2089  lm_results.set_markup (string_compose (results_markup, buf));
2090 
2091  return true;
2092 }
2093 
2094 void
2096 {
2099 
2101  lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
2102  if (_measure_midi) {
2103  latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
2104  } else {
2105  latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
2106  }
2107  lm_measure_label.set_text (_("Cancel"));
2108  have_lm_results = false;
2109  lm_use_button.set_sensitive (false);
2110  lm_input_channel_combo.set_sensitive (false);
2111  lm_output_channel_combo.set_sensitive (false);
2112  lm_running = true;
2113  }
2114 }
2115 
2116 void
2118 {
2119  latency_timeout.disconnect ();
2121  lm_measure_label.set_text (_("Measure"));
2122  if (!have_lm_results) {
2123  lm_use_button.set_sensitive (false);
2124  }
2125  lm_input_channel_combo.set_sensitive (true);
2126  lm_output_channel_combo.set_sensitive (true);
2127  lm_running = false;
2128 }
2129 
2130 void
2132 {
2133  if (!lm_running) {
2135  } else {
2137  }
2138 }
2139 
2140 void
2142 {
2143  if (_measure_midi) {
2145  if (!mididm) {
2146  return;
2147  }
2148  ARDOUR::framecnt_t frames_total = mididm->latency();
2150  uint32_t one_way = max ((ARDOUR::framecnt_t) 0, extra / 2);
2151  _measure_midi->input_latency = one_way;
2152  _measure_midi->output_latency = one_way;
2153  notebook.set_current_page (midi_tab);
2154  } else {
2155  MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
2156 
2157  if (!mtdm) {
2158  return;
2159  }
2160 
2161  double one_way = rint ((mtdm->del() - ARDOUR::AudioEngine::instance()->latency_signal_delay()) / 2.0);
2162  one_way = std::max (0., one_way);
2163 
2164  input_latency_adjustment.set_value (one_way);
2165  output_latency_adjustment.set_value (one_way);
2166 
2167  /* back to settings page */
2168  notebook.set_current_page (0);
2169 }
2170  }
2171 
2172 
2173 bool
2175 {
2176  if (notebook.get_current_page() == 2) {
2177  /* currently on latency tab - be sure to clean up */
2179  }
2180  return ArdourDialog::on_delete_event (ev);
2181 }
2182 
2183 void
2185 {
2187  assert (backend);
2188 
2190  sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate()));
2191 
2192  buffer_size_combo.set_sensitive (true);
2193  sample_rate_combo.set_sensitive (true);
2194 
2195  connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name()));
2197 
2198  started_at_least_once = true;
2199  engine_status.set_markup(string_compose ("<span foreground=\"green\">%1</span>", _("Active")));
2200 }
2201 
2202 void
2204 {
2206  assert (backend);
2207 
2208  buffer_size_combo.set_sensitive (false);
2209  connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name()));
2211 
2212  sample_rate_combo.set_sensitive (true);
2213  buffer_size_combo.set_sensitive (true);
2214  engine_status.set_markup(string_compose ("<span foreground=\"red\">%1</span>", _("Inactive")));
2215 }
2216 
2217 void
2219 {
2220  PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1); // ??
2221  list_devices ();
2223 }
2224 
2225 void
2227 {
2228  if (ARDOUR::AudioEngine::instance()->running()) {
2230  } else {
2232  }
2233 }
2234 
2235 void
2237 {
2238  _measure_midi.reset ();
2239  have_lm_results = false;
2240  lm_use_button.set_sensitive (false);
2241  lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2242  notebook.set_current_page (latency_tab);
2243 }
2244 
2245 void
2247 {
2248  _measure_midi = s;
2249  have_lm_results = false;
2250  lm_use_button.set_sensitive (false);
2251  lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
2252  notebook.set_current_page (latency_tab);
2253 }
2254 
2255 void
2257 {
2258  notebook.set_current_page (midi_tab);
2259 }
virtual std::string name() const =0
void midi_option_changed()
Gtk::Button * cancel_button
void build_notebook()
void setup_midi_tab_for_jack()
Gtk::Button control_app_button
Definition: engine_dialog.h:83
double del(void)
Definition: mtdm.h:35
int atoi(const string &s)
Definition: convert.cc:140
int reconnect_to_engine()
Definition: ardour_ui.cc:4403
virtual std::string device_name() const =0
Gtk::ComboBoxText driver_combo
Definition: engine_dialog.h:65
virtual uint32_t systemic_output_latency() const =0
virtual std::vector< float > available_sample_rates(const std::string &device) const =0
sigc::signal< void > signal_clicked
const std::string & value() const
Definition: xml++.h:159
virtual int set_midi_option(const std::string &option)=0
uint32_t get_input_latency() const
PBD::ScopedConnection running_connection
Gtk::ComboBoxText midi_option_combo
Definition: engine_dialog.h:68
static const unsigned int latency_tab
virtual int set_input_channels(uint32_t)=0
sigc::connection latency_timeout
Gtk::Label lm_results
Definition: engine_dialog.h:99
bool started_at_least_once
int start_latency_detection(bool)
bool running() const
Definition: audioengine.h:130
Definition: mtdm.h:26
bool check_audio_latency_measurement()
std::string get_device_name() const
void device_changed()
Gtk::Button lm_measure_button
Definition: engine_dialog.h:93
Gtk::ComboBoxText sample_rate_combo
Definition: engine_dialog.h:67
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
std::string get_backend() const
LIBGTKMM2EXT_API bool set_active_text_if_present(Gtk::ComboBoxText &, const std::string)
Definition: utils.cc:334
const std::string & name() const
Definition: xml++.h:104
framecnt_t latency(void)
Definition: mididm.h:37
double err(void)
Definition: mtdm.h:36
bool ok(void)
Definition: mididm.h:40
boost::shared_ptr< AudioBackend > current_backend() const
Definition: audioengine.h:73
Gtk::Adjustment input_channels_adjustment
Definition: engine_dialog.h:75
void show_splash()
Definition: ardour_ui.cc:3368
virtual int set_device_name(const std::string &)=0
void on_switch_page(GtkNotebookPage *, guint page_num)
ArdourButton lm_button_audio
Definition: engine_dialog.h:96
Gtk::SpinButton input_latency
Definition: engine_dialog.h:72
Gtk::VBox lm_vbox
tuple f
Definition: signals.py:35
Definition: Beats.hpp:239
virtual float sample_rate() const =0
LIBPBD_API Transmitter error
Gtk::Label lm_preamble
Definition: engine_dialog.h:98
Gtk::ComboBoxText backend_combo
Definition: engine_dialog.h:64
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
Gtk::Table midi_device_table
PBD::Signal0< void > DeviceListChanged
Definition: audioengine.h:177
uint32_t ignore_changes
std::string get_midi_option() const
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
virtual std::string driver_name() const
void build_no_control_notebook()
LIBGTKMM2EXT_API void set_popdown_strings(Gtk::ComboBoxText &, const std::vector< std::string > &)
std::string bufsize_as_string(uint32_t)
virtual int set_systemic_midi_output_latency(std::string const, uint32_t)=0
std::string get_driver() const
#define P_(Singular, Plural, HowMany)
Definition: i18n.h:41
virtual uint32_t default_buffer_size(const std::string &device) const
virtual bool midi_device_enabled(std::string const) const =0
void sample_rate_changed()
void set_desired_sample_rate(uint32_t)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
static AudioEngine * instance()
Definition: audioengine.h:196
uint32_t get_output_latency() const
Gtk::HBox basic_hbox
Definition: engine_dialog.h:61
bool have_signal(void)
Definition: mididm.h:41
virtual std::vector< uint32_t > available_buffer_sizes(const std::string &device) const =0
virtual int set_systemic_input_latency(uint32_t)=0
Gtk::SpinButton input_channels
Definition: engine_dialog.h:76
virtual uint32_t systemic_midi_input_latency(std::string const) const =0
Gtk::Label lm_title
Definition: engine_dialog.h:97
framecnt_t processed(void)
Definition: mididm.h:38
virtual int set_systemic_output_latency(uint32_t)=0
void set_latency_input_port(const std::string &)
Gtk::Table basic_packer
Definition: engine_dialog.h:60
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
void get_physical_outputs(DataType type, std::vector< std::string > &)
virtual int set_output_channels(uint32_t)=0
void driver_changed()
#define _(Text)
Definition: i18n.h:11
void device_list_changed()
bool check_midi_latency_measurement()
virtual std::string control_app_name() const =0
framecnt_t sample_rate() const
Definition: audioengine.cc:974
static const char * results_markup
void backend_changed()
void calibrate_midi_latency(MidiDeviceSettings)
void end_latency_detection()
#define X_(Text)
Definition: i18n.h:13
Gtk::Button * apply_button
void configure_midi_devices()
int64_t framecnt_t
Definition: types.h:76
virtual std::vector< std::string > enumerate_drivers() const
bool on_delete_event(GdkEventAny *)
XMLProperty * property(const char *)
Definition: xml++.cc:413
Gtk::Label engine_status
Definition: engine_dialog.h:56
void invert(void)
Definition: mtdm.h:33
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
virtual uint32_t input_channels() const =0
State get_matching_state(const std::string &backend, const std::string &driver, const std::string &device)
uint32_t get_buffer_size() const
Gtk::ComboBoxText lm_input_channel_combo
Definition: engine_dialog.h:91
void setup_midi_tab_for_backend()
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
void latency_button_clicked()
#define gui_context()
Definition: gui_thread.h:36
PBD::ScopedConnectionList stopped_connection
virtual int set_driver(const std::string &)
Gtk::Label lm_measure_label
Definition: engine_dialog.h:92
void store_state(State)
void update_sensitivity()
std::string rate_as_string(float r)
Definition: utils.cc:914
virtual std::string midi_option() const =0
virtual int set_sample_rate(float)=0
LIBGTKMM2EXT_API Gtk::Label * left_aligned_label(std::string const &)
virtual int set_midi_device_enabled(std::string const, bool)=0
MidiDeviceSettings find_midi_device(std::string devicename) const
void set_latency_output_port(const std::string &)
virtual uint32_t systemic_input_latency() const =0
virtual uint32_t systemic_midi_output_latency(std::string const) const =0
Gtk::Button lm_back_button
Definition: engine_dialog.h:95
uint32_t _desired_sample_rate
void calibrate_audio_latency()
Gtk::Table lm_table
LIBARDOUR_API XMLNode * find_named_node(const XMLNode &node, std::string name)
void connect_disconnect_click()
virtual std::vector< std::string > enumerate_midi_options() const =0
void manage_control_app_sensitivity()
void disable_latency_tab()
PBD::Signal0< void > Running
Definition: audioengine.h:187
std::vector< MidiDeviceSettings > _midi_devices
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
bool queue_device_changed
void control_app_button_clicked()
Gtk::Adjustment output_latency_adjustment
Definition: engine_dialog.h:73
State get_saved_state_for_currently_displayed_backend_and_device()
int inv(void)
Definition: mtdm.h:34
XMLNode & get_state()
virtual void launch_control_app()=0
XMLProperty * add_property(const char *name, const std::string &value)
void midi_device_enabled_toggled(ArdourButton *, MidiDeviceSettings)
void buffer_size_changed()
void build_full_control_notebook()
void maybe_display_saved_state()
Gtk::Button lm_use_button
Definition: engine_dialog.h:94
float get_rate() const
virtual uint32_t output_channels() const =0
boost::shared_ptr< StateStruct > State
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
bool get_active()
Definition: cairo_widget.h:57
static bool print_channel_count(Gtk::SpinButton *)
bool setup_required() const
std::vector< const AudioBackendInfo * > available_backends() const
Definition: audioengine.cc:747
int push_state_to_backend(bool start)
void on_response(int)
Gtk::Label buffer_size_duration_label
Definition: engine_dialog.h:70
void set_active(bool)
void start_latency_detection()
bool _can_set_midi_latencies
Definition: xml++.h:95
virtual bool can_change_sample_rate_when_running() const =0
uint32_t get_input_channels() const
virtual std::vector< DeviceStatus > enumerate_devices() const =0
Gtk::VBox midi_vbox
static const unsigned int midi_tab
XMLNode * extra_xml(const std::string &str, bool add_if_missing=false)
Definition: stateful.cc:77
Definition: debug.h:30
void midi_latency_adjustment_changed(Gtk::Adjustment *, MidiDeviceSettings, bool)
int resolve(void)
Definition: mtdm.cc:93
ArdourButton midi_devices_button
Definition: engine_dialog.h:84
double deviation(void)
Definition: mididm.h:39
void set_state(const XMLNode &)
Gtk::ComboBoxText lm_output_channel_combo
Definition: engine_dialog.h:90
Gtk::ComboBoxText device_combo
Definition: engine_dialog.h:66
bool on_delete_event(GdkEventAny *)
Gtk::Button * ok_button
void show_buffer_duration()
PBD::Signal1< void, const char * > Halted
Definition: audioengine.h:181
PBD::Signal0< void > Stopped
Definition: audioengine.h:188
StateList states
void get_physical_inputs(DataType type, std::vector< std::string > &)
virtual int set_buffer_size(uint32_t)=0
int disconnect_from_engine()
Definition: ardour_ui.cc:4382
virtual int set_systemic_midi_input_latency(std::string const, uint32_t)=0
void enable_latency_tab()
virtual bool requires_driver_selection() const
virtual uint32_t buffer_size() const =0
static Element led_default_elements
Definition: ardour_button.h:64
Gtk::Notebook notebook
Definition: engine_dialog.h:54
void use_latency_button_clicked()
virtual bool can_change_buffer_size_when_running() const =0
#define MISSING_INVALIDATOR
Definition: event_loop.h:86
XMLNodeList::const_iterator XMLNodeConstIterator
Definition: xml++.h:49
virtual std::vector< DeviceStatus > enumerate_midi_devices() const =0
uint32_t get_output_channels() const
Gtk::Button midi_back_button
Gtk::Button connect_disconnect_button
Definition: engine_dialog.h:86
void refresh_midi_display(std::string focus="")
Gtk::VBox basic_vbox
Definition: engine_dialog.h:62
MidiDeviceSettings _measure_midi
Gtk::ComboBoxText buffer_size_combo
Definition: engine_dialog.h:69
Gtk::SpinButton output_channels
Definition: engine_dialog.h:78
virtual bool can_set_systemic_midi_latencies() const =0
Gtk::SpinButton output_latency
Definition: engine_dialog.h:74
Gtk::Adjustment input_latency_adjustment
Definition: engine_dialog.h:71
PBD::ScopedConnection devicelist_connection
Gtk::Adjustment output_channels_adjustment
Definition: engine_dialog.h:77
sigc::connection lm_back_button_signal
uint32_t latency_signal_delay() const
Definition: audioengine.h:225
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
LIBGTKMM2EXT_API void container_clear(Gtk::Container &)
Definition: utils.cc:511
double atof(const string &s)
Definition: convert.cc:158
virtual float default_sample_rate() const
void parameter_changed()