2010-07-25 21:54:51 -04:00
/*
Copyright ( C ) 2010 Paul Davis
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2013-08-05 12:51:51 -04:00
# include <exception>
2007-10-11 18:07:47 -04:00
# include <vector>
# include <cmath>
# include <fstream>
2008-01-10 17:22:29 -05:00
# include <map>
2007-10-11 18:07:47 -04:00
2011-01-07 11:25:57 -05:00
# include <boost/scoped_ptr.hpp>
2008-01-12 18:45:50 -05:00
# include <gtkmm/messagedialog.h>
2011-01-07 11:25:57 -05:00
2013-08-05 12:51:51 -04:00
# include "pbd/error.h"
2009-02-25 13:26:51 -05:00
# include "pbd/xml++.h"
2013-09-12 16:28:51 -04:00
# include "pbd/unwind.h"
2013-10-10 11:24:16 -04:00
# include "pbd/failed_constructor.h"
2007-10-11 18:07:47 -04:00
2013-09-16 15:21:32 -04:00
# include <gtkmm/alignment.h>
2007-10-11 18:07:47 -04:00
# include <gtkmm/stock.h>
2013-08-09 00:50:41 -04:00
# include <gtkmm/notebook.h>
2007-10-11 18:07:47 -04:00
# include <gtkmm2ext/utils.h>
2013-08-03 11:57:56 -04:00
# include "ardour/audio_backend.h"
# include "ardour/audioengine.h"
2013-09-10 22:58:33 -04:00
# include "ardour/mtdm.h"
2012-11-08 10:54:16 -05:00
# include "ardour/rc_configuration.h"
2013-09-10 22:58:33 -04:00
# include "ardour/types.h"
2012-11-08 10:54:16 -05:00
2009-02-25 13:26:51 -05:00
# include "pbd/convert.h"
# include "pbd/error.h"
2007-10-11 18:07:47 -04:00
2013-09-17 21:09:13 -04:00
# include "ardour_ui.h"
2007-10-11 18:07:47 -04:00
# include "engine_dialog.h"
2013-09-10 22:58:33 -04:00
# include "gui_thread.h"
2013-09-23 21:35:17 -04:00
# include "utils.h"
2007-10-11 18:07:47 -04:00
# include "i18n.h"
using namespace std ;
using namespace Gtk ;
using namespace Gtkmm2ext ;
using namespace PBD ;
using namespace Glib ;
2013-10-10 16:18:27 -04:00
static const unsigned int midi_tab = - 1 ; /* not currently in use */
static const unsigned int latency_tab = 1 ; /* zero-based, page zero is the main setup page */
2013-10-12 14:57:32 -04:00
static const char * results_markup = X_ ( " <span foreground= \" red \" style= \" italic \" size= \" larger \" >%1</span> " ) ;
2007-10-11 18:07:47 -04:00
EngineControl : : EngineControl ( )
2013-09-09 13:17:53 -04:00
: ArdourDialog ( _ ( " Audio/MIDI Setup " ) )
2013-10-12 14:57:32 -04:00
, basic_packer ( 9 , 4 )
2013-09-09 13:17:53 -04:00
, input_latency_adjustment ( 0 , 0 , 99999 , 1 )
2013-08-04 14:03:19 -04:00
, input_latency ( input_latency_adjustment )
, output_latency_adjustment ( 0 , 0 , 99999 , 1 )
, output_latency ( output_latency_adjustment )
2013-09-06 21:00:01 -04:00
, input_channels_adjustment ( 0 , 0 , 256 , 1 )
2013-08-04 14:03:19 -04:00
, input_channels ( input_channels_adjustment )
2013-09-06 21:00:01 -04:00
, output_channels_adjustment ( 0 , 0 , 256 , 1 )
2013-08-04 14:03:19 -04:00
, output_channels ( output_channels_adjustment )
, ports_adjustment ( 128 , 8 , 1024 , 1 , 16 )
, ports_spinner ( ports_adjustment )
2013-09-16 18:47:30 -04:00
, control_app_button ( _ ( " Device Control Panel " ) )
2013-10-15 14:55:54 -04:00
, lm_measure_label ( _ ( " Measure " ) )
2013-09-10 22:58:33 -04:00
, lm_use_button ( _ ( " Use results " ) )
2013-10-12 14:57:32 -04:00
, lm_back_button ( _ ( " Back to settings ... (ignore results) " ) )
, lm_button ( _ ( " Calibrate... " ) )
, lm_table ( 12 , 3 )
2013-09-16 15:21:32 -04:00
, have_lm_results ( false )
2013-10-12 14:57:32 -04:00
, lm_running ( false )
2013-09-17 10:01:24 -04:00
, midi_refresh_button ( _ ( " Refresh list " ) )
2013-09-09 21:23:12 -04:00
, ignore_changes ( 0 )
2013-09-10 15:41:19 -04:00
, _desired_sample_rate ( 0 )
2013-09-19 16:17:47 -04:00
, started_at_least_once ( false )
2013-09-09 13:17:53 -04:00
{
2013-09-19 15:03:20 -04:00
using namespace Notebook_Helpers ;
vector < string > strings ;
Label * label ;
AttachOptions xopt = AttachOptions ( FILL | EXPAND ) ;
int row ;
2013-09-17 21:09:13 -04:00
2013-09-16 22:03:59 -04:00
set_name ( X_ ( " AudioMIDISetup " ) ) ;
2013-09-19 15:03:20 -04:00
/* the backend combo is the one thing that is ALWAYS visible
*/
vector < const ARDOUR : : AudioBackendInfo * > backends = ARDOUR : : AudioEngine : : instance ( ) - > available_backends ( ) ;
2013-10-10 11:24:16 -04:00
if ( backends . empty ( ) ) {
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)) ;
msg . run ( ) ;
throw failed_constructor ( ) ;
}
2013-09-19 15:03:20 -04:00
for ( vector < const ARDOUR : : AudioBackendInfo * > : : const_iterator b = backends . begin ( ) ; b ! = backends . end ( ) ; + + b ) {
strings . push_back ( ( * b ) - > name ) ;
}
set_popdown_strings ( backend_combo , strings ) ;
backend_combo . set_active_text ( strings . front ( ) ) ;
backend_combo . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : backend_changed ) ) ;
/* setup basic packing characteristics for the table used on the main
* tab of the notebook
*/
basic_packer . set_spacings ( 6 ) ;
basic_packer . set_border_width ( 12 ) ;
2013-10-12 14:57:32 -04:00
basic_packer . set_homogeneous ( false ) ;
2013-09-19 15:03:20 -04:00
/* pack it in */
basic_hbox . pack_start ( basic_packer , false , false ) ;
/* latency tab */
/* latency measurement tab */
lm_title . set_markup ( string_compose ( " <span size= \" large \" weight= \" bold \" >%1</span> " , _ ( " Latency Measurement Tool " ) ) ) ;
row = 0 ;
lm_table . set_row_spacings ( 12 ) ;
2013-10-12 14:57:32 -04:00
lm_table . set_col_spacings ( 6 ) ;
lm_table . set_homogeneous ( false ) ;
lm_table . attach ( lm_title , 0 , 3 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
row + + ;
Gtk : : Label * preamble ;
preamble = manage ( new Label ) ;
preamble - > set_width_chars ( 60 ) ;
preamble - > set_line_wrap ( true ) ;
2013-10-12 14:57:32 -04:00
preamble - > set_markup ( _ ( " <span weight= \" bold \" >Turn down the volume on your audio equipment to a very low level.</span> " ) ) ;
2013-09-19 15:03:20 -04:00
2013-10-12 14:57:32 -04:00
lm_table . attach ( * preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
row + + ;
preamble = manage ( new Label ) ;
preamble - > set_width_chars ( 60 ) ;
preamble - > set_line_wrap ( true ) ;
2013-10-12 14:57:32 -04:00
preamble - > set_markup ( _ ( " Select two channels below and connect them using a cable. " ) ) ;
2013-09-19 15:03:20 -04:00
2013-10-12 14:57:32 -04:00
lm_table . attach ( * preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
row + + ;
label = manage ( new Label ( _ ( " Output channel " ) ) ) ;
lm_table . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
Gtk : : Alignment * misc_align = manage ( new Alignment ( 0.0 , 0.5 ) ) ;
misc_align - > add ( lm_output_channel_combo ) ;
2013-10-12 14:57:32 -04:00
lm_table . attach ( * misc_align , 1 , 3 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
+ + row ;
label = manage ( new Label ( _ ( " Input channel " ) ) ) ;
lm_table . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
misc_align = manage ( new Alignment ( 0.0 , 0.5 ) ) ;
misc_align - > add ( lm_input_channel_combo ) ;
2013-10-12 14:57:32 -04:00
lm_table . attach ( * misc_align , 1 , 3 , row , row + 1 , FILL , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
+ + row ;
xopt = AttachOptions ( 0 ) ;
2013-10-15 14:55:54 -04:00
lm_measure_label . set_padding ( 10 , 10 ) ;
lm_measure_button . add ( lm_measure_label ) ;
2013-10-12 14:57:32 -04:00
lm_measure_button . signal_clicked ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : latency_button_clicked ) ) ;
2013-09-19 15:03:20 -04:00
lm_use_button . signal_clicked ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : use_latency_button_clicked ) ) ;
2013-10-12 14:57:32 -04:00
lm_back_button . signal_clicked ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( notebook , & Gtk : : Notebook : : set_current_page ) , 0 ) ) ;
2013-09-19 15:03:20 -04:00
lm_use_button . set_sensitive ( false ) ;
2013-10-12 14:57:32 -04:00
/* Increase the default spacing around the labels of these three
* buttons
*/
Gtk : : Misc * l ;
if ( ( l = dynamic_cast < Gtk : : Misc * > ( lm_use_button . get_child ( ) ) ) ! = 0 ) {
l - > set_padding ( 10 , 10 ) ;
}
if ( ( l = dynamic_cast < Gtk : : Misc * > ( lm_back_button . get_child ( ) ) ) ! = 0 ) {
l - > set_padding ( 10 , 10 ) ;
}
2013-09-19 15:03:20 -04:00
preamble = manage ( new Label ) ;
preamble - > set_width_chars ( 60 ) ;
preamble - > set_line_wrap ( true ) ;
2013-10-12 14:57:32 -04:00
preamble - > set_markup ( _ ( " Once the channels are connected, click the \" Measure \" button. " ) ) ;
lm_table . attach ( * preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
row + + ;
preamble = manage ( new Label ) ;
preamble - > set_width_chars ( 60 ) ;
preamble - > set_line_wrap ( true ) ;
preamble - > set_markup ( _ ( " When satisfied with the results, click the \" Use results \" button. " ) ) ;
2013-10-12 14:57:32 -04:00
lm_table . attach ( * preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
2013-10-12 14:57:32 -04:00
+ + row ; // skip a row in the table
+ + row ; // skip a row in the table
lm_table . attach ( lm_results , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
2013-09-19 15:03:20 -04:00
2013-10-12 14:57:32 -04:00
+ + row ; // skip a row in the table
+ + row ; // skip a row in the table
lm_table . attach ( lm_measure_button , 0 , 1 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
lm_table . attach ( lm_use_button , 1 , 2 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
lm_table . attach ( lm_back_button , 2 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
lm_results . set_markup ( string_compose ( results_markup , _ ( " No measurement results yet " ) ) ) ;
2013-09-19 15:03:20 -04:00
lm_vbox . set_border_width ( 12 ) ;
lm_vbox . pack_start ( lm_table , false , false ) ;
/* pack it all up */
notebook . pages ( ) . push_back ( TabElem ( basic_vbox , _ ( " Audio " ) ) ) ;
2013-10-10 12:59:33 -04:00
// notebook.pages().push_back (TabElem (midi_vbox, _("MIDI")));
2013-09-19 15:03:20 -04:00
notebook . pages ( ) . push_back ( TabElem ( lm_vbox , _ ( " Latency " ) ) ) ;
notebook . set_border_width ( 12 ) ;
2013-10-12 14:57:32 -04:00
notebook . set_show_tabs ( false ) ;
2013-09-19 15:03:20 -04:00
notebook . show_all ( ) ;
notebook . set_name ( " SettingsNotebook " ) ;
/* packup the notebook */
2013-09-09 13:17:53 -04:00
get_vbox ( ) - > set_border_width ( 12 ) ;
get_vbox ( ) - > pack_start ( notebook ) ;
2013-09-19 15:03:20 -04:00
/* need a special function to print "all available channels" when the
* channel counts hit zero .
*/
input_channels . signal_output ( ) . connect ( sigc : : bind ( sigc : : ptr_fun ( & EngineControl : : print_channel_count ) , & input_channels ) ) ;
output_channels . signal_output ( ) . connect ( sigc : : bind ( sigc : : ptr_fun ( & EngineControl : : print_channel_count ) , & output_channels ) ) ;
2013-09-09 15:17:29 -04:00
control_app_button . signal_clicked ( ) . connect ( mem_fun ( * this , & EngineControl : : control_app_button_clicked ) ) ;
manage_control_app_sensitivity ( ) ;
2013-09-16 15:21:32 -04:00
cancel_button = add_button ( Gtk : : Stock : : CANCEL , Gtk : : RESPONSE_CANCEL ) ;
ok_button = add_button ( Gtk : : Stock : : OK , Gtk : : RESPONSE_OK ) ;
apply_button = add_button ( Gtk : : Stock : : APPLY , Gtk : : RESPONSE_APPLY ) ;
2013-09-09 13:17:53 -04:00
/* Pick up any existing audio setup configuration, if appropriate */
XMLNode * audio_setup = ARDOUR : : Config - > extra_xml ( " AudioMIDISetup " ) ;
2013-10-12 14:57:32 -04:00
2013-09-19 15:03:20 -04:00
ARDOUR : : AudioEngine : : instance ( ) - > Running . connect ( running_connection , MISSING_INVALIDATOR , boost : : bind ( & EngineControl : : engine_running , this ) , gui_context ( ) ) ;
ARDOUR : : AudioEngine : : instance ( ) - > Stopped . connect ( stopped_connection , MISSING_INVALIDATOR , boost : : bind ( & EngineControl : : engine_stopped , this ) , gui_context ( ) ) ;
ARDOUR : : AudioEngine : : instance ( ) - > Halted . connect ( stopped_connection , MISSING_INVALIDATOR , boost : : bind ( & EngineControl : : engine_stopped , this ) , gui_context ( ) ) ;
2013-09-09 21:23:12 -04:00
backend_changed ( ) ;
2013-09-09 13:17:53 -04:00
if ( audio_setup ) {
set_state ( * audio_setup ) ;
2013-09-19 15:03:20 -04:00
}
/* Connect to signals */
driver_combo . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : driver_changed ) ) ;
sample_rate_combo . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : sample_rate_changed ) ) ;
buffer_size_combo . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : buffer_size_changed ) ) ;
device_combo . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : device_changed ) ) ;
2013-10-10 16:18:27 -04:00
midi_option_combo . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : midi_option_changed ) ) ;
2013-09-19 15:03:20 -04:00
input_latency . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
output_latency . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
input_channels . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
output_channels . signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
notebook . signal_switch_page ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : on_switch_page ) ) ;
2013-10-12 14:57:32 -04:00
}
void
EngineControl : : on_response ( int response_id )
{
ArdourDialog : : on_response ( response_id ) ;
switch ( response_id ) {
case RESPONSE_APPLY :
push_state_to_backend ( true ) ;
break ;
case RESPONSE_OK :
push_state_to_backend ( true ) ;
hide ( ) ;
break ;
case RESPONSE_DELETE_EVENT : {
GdkEventButton ev ;
ev . type = GDK_BUTTON_PRESS ;
ev . button = 1 ;
on_delete_event ( ( GdkEventAny * ) & ev ) ;
break ;
}
default :
hide ( ) ;
}
}
void
EngineControl : : build_notebook ( )
{
Label * label ;
AttachOptions xopt = AttachOptions ( FILL | EXPAND ) ;
/* clear the table */
Gtkmm2ext : : container_clear ( basic_vbox ) ;
Gtkmm2ext : : container_clear ( basic_packer ) ;
2013-12-26 11:29:26 -05:00
if ( control_app_button . get_parent ( ) ) {
control_app_button . get_parent ( ) - > remove ( control_app_button ) ;
}
2013-10-12 14:57:32 -04:00
label = manage ( left_aligned_label ( _ ( " Audio System: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , 0 , 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( backend_combo , 1 , 2 , 0 , 1 , xopt , ( AttachOptions ) 0 ) ;
2013-10-15 13:15:03 -04:00
lm_button . signal_clicked . connect ( sigc : : mem_fun ( * this , & EngineControl : : calibrate_latency ) ) ;
2014-02-28 16:58:30 -05:00
lm_button . set_name ( " generic button " ) ;
2013-10-12 14:57:32 -04:00
if ( _have_control ) {
build_full_control_notebook ( ) ;
} else {
build_no_control_notebook ( ) ;
}
basic_vbox . pack_start ( basic_hbox , false , false ) ;
if ( _have_control ) {
Gtk : : HBox * hpacker = manage ( new HBox ) ;
hpacker - > set_border_width ( 12 ) ;
hpacker - > pack_start ( control_app_button , false , false ) ;
hpacker - > show ( ) ;
control_app_button . show ( ) ;
basic_vbox . pack_start ( * hpacker ) ;
}
basic_vbox . show_all ( ) ;
}
void
EngineControl : : build_full_control_notebook ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
using namespace Notebook_Helpers ;
Label * label ;
vector < string > strings ;
AttachOptions xopt = AttachOptions ( FILL | EXPAND ) ;
int row = 1 ; // row zero == backend combo
/* start packing it up */
if ( backend - > requires_driver_selection ( ) ) {
label = manage ( left_aligned_label ( _ ( " Driver: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( driver_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
}
label = manage ( left_aligned_label ( _ ( " Device: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( device_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
label = manage ( left_aligned_label ( _ ( " Sample rate: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( sample_rate_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
label = manage ( left_aligned_label ( _ ( " Buffer size: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( buffer_size_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
buffer_size_duration_label . set_alignment ( 0.0 ) ; /* left-align */
basic_packer . attach ( buffer_size_duration_label , 2 , 3 , row , row + 1 , SHRINK , ( AttachOptions ) 0 ) ;
row + + ;
input_channels . set_name ( " InputChannels " ) ;
input_channels . set_flags ( Gtk : : CAN_FOCUS ) ;
input_channels . set_digits ( 0 ) ;
input_channels . set_wrap ( false ) ;
output_channels . set_editable ( true ) ;
label = manage ( left_aligned_label ( _ ( " Input Channels: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( input_channels , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
+ + row ;
output_channels . set_name ( " OutputChannels " ) ;
output_channels . set_flags ( Gtk : : CAN_FOCUS ) ;
output_channels . set_digits ( 0 ) ;
output_channels . set_wrap ( false ) ;
output_channels . set_editable ( true ) ;
label = manage ( left_aligned_label ( _ ( " Output Channels: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( output_channels , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
+ + row ;
input_latency . set_name ( " InputLatency " ) ;
input_latency . set_flags ( Gtk : : CAN_FOCUS ) ;
input_latency . set_digits ( 0 ) ;
input_latency . set_wrap ( false ) ;
input_latency . set_editable ( true ) ;
label = manage ( left_aligned_label ( _ ( " Hardware input latency: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( input_latency , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
label = manage ( left_aligned_label ( _ ( " samples " ) ) ) ;
basic_packer . attach ( * label , 2 , 3 , row , row + 1 , SHRINK , ( AttachOptions ) 0 ) ;
+ + row ;
output_latency . set_name ( " OutputLatency " ) ;
output_latency . set_flags ( Gtk : : CAN_FOCUS ) ;
output_latency . set_digits ( 0 ) ;
output_latency . set_wrap ( false ) ;
output_latency . set_editable ( true ) ;
label = manage ( left_aligned_label ( _ ( " Hardware output latency: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( output_latency , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
label = manage ( left_aligned_label ( _ ( " samples " ) ) ) ;
basic_packer . attach ( * label , 2 , 3 , row , row + 1 , SHRINK , ( AttachOptions ) 0 ) ;
/* button spans 2 rows */
basic_packer . attach ( lm_button , 3 , 4 , row - 1 , row + 1 , xopt , xopt ) ;
+ + row ;
label = manage ( left_aligned_label ( _ ( " MIDI System " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( midi_option_combo , 1 , 2 , row , row + 1 , SHRINK , ( AttachOptions ) 0 ) ;
row + + ;
}
void
EngineControl : : build_no_control_notebook ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
using namespace Notebook_Helpers ;
Label * label ;
vector < string > strings ;
AttachOptions xopt = AttachOptions ( FILL | EXPAND ) ;
int row = 1 ; // row zero == backend combo
const string msg = string_compose ( _ ( " The %1 audio backend was configured and started externally. \n This limits your control over it. " ) , backend - > name ( ) ) ;
label = manage ( new Label ) ;
label - > set_markup ( string_compose ( " <span weight= \" bold \" foreground= \" red \" >%1</span> " , msg ) ) ;
basic_packer . attach ( * label , 0 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
if ( backend - > can_change_sample_rate_when_running ( ) ) {
label = manage ( left_aligned_label ( _ ( " Sample rate: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( sample_rate_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
}
if ( backend - > can_change_buffer_size_when_running ( ) ) {
label = manage ( left_aligned_label ( _ ( " Buffer size: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( buffer_size_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
buffer_size_duration_label . set_alignment ( 0.0 ) ; /* left-align */
basic_packer . attach ( buffer_size_duration_label , 2 , 3 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
}
connect_disconnect_button . signal_clicked ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : connect_disconnect_click ) ) ;
basic_packer . attach ( connect_disconnect_button , 0 , 2 , row , row + 1 , FILL , AttachOptions ( 0 ) ) ;
row + + ;
}
EngineControl : : ~ EngineControl ( )
{
2013-10-12 16:44:50 -04:00
ignore_changes = true ;
2013-10-12 14:57:32 -04:00
}
void
EngineControl : : disable_latency_tab ( )
{
vector < string > empty ;
set_popdown_strings ( lm_output_channel_combo , empty ) ;
set_popdown_strings ( lm_input_channel_combo , empty ) ;
lm_measure_button . set_sensitive ( false ) ;
lm_use_button . set_sensitive ( false ) ;
}
void
EngineControl : : enable_latency_tab ( )
{
vector < string > outputs ;
vector < string > inputs ;
2013-10-15 13:15:03 -04:00
ARDOUR : : AudioEngine : : instance ( ) - > get_physical_outputs ( ARDOUR : : DataType : : AUDIO , outputs ) ;
2013-10-12 14:57:32 -04:00
ARDOUR : : AudioEngine : : instance ( ) - > get_physical_inputs ( ARDOUR : : DataType : : AUDIO , inputs ) ;
2013-10-15 13:15:03 -04:00
if ( inputs . empty ( ) | | outputs . empty ( ) ) {
MessageDialog msg ( _ ( " Your selected audio configuration is playback- or capture-only. \n \n Latency calibration requires playback and capture " ) ) ;
lm_measure_button . set_sensitive ( false ) ;
notebook . set_current_page ( 0 ) ;
msg . run ( ) ;
return ;
}
if ( ! outputs . empty ( ) ) {
set_popdown_strings ( lm_output_channel_combo , outputs ) ;
lm_output_channel_combo . set_active_text ( outputs . front ( ) ) ;
lm_output_channel_combo . set_sensitive ( true ) ;
} else {
lm_output_channel_combo . set_sensitive ( false ) ;
}
if ( ! inputs . empty ( ) ) {
set_popdown_strings ( lm_input_channel_combo , inputs ) ;
lm_input_channel_combo . set_active_text ( inputs . front ( ) ) ;
lm_input_channel_combo . set_sensitive ( true ) ;
} else {
lm_input_channel_combo . set_sensitive ( false ) ;
}
2013-10-12 14:57:32 -04:00
lm_measure_button . set_sensitive ( true ) ;
}
void
EngineControl : : setup_midi_tab_for_backend ( )
{
string backend = backend_combo . get_active_text ( ) ;
Gtkmm2ext : : container_clear ( midi_vbox ) ;
midi_vbox . set_border_width ( 12 ) ;
midi_device_table . set_border_width ( 12 ) ;
if ( backend = = " JACK " ) {
setup_midi_tab_for_jack ( ) ;
}
midi_vbox . pack_start ( midi_device_table , true , true ) ;
midi_vbox . pack_start ( midi_refresh_button , false , false ) ;
midi_vbox . show_all ( ) ;
midi_refresh_button . signal_clicked ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : refresh_midi_display ) ) ;
}
void
EngineControl : : setup_midi_tab_for_jack ( )
{
}
void
EngineControl : : refresh_midi_display ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
vector < string > midi_inputs ;
vector < string > midi_outputs ;
int row = 0 ;
AttachOptions xopt = AttachOptions ( FILL | EXPAND ) ;
Gtk : : Label * l ;
Gtkmm2ext : : container_clear ( midi_device_table ) ;
backend - > get_physical_inputs ( ARDOUR : : DataType : : MIDI , midi_inputs ) ;
backend - > get_physical_outputs ( ARDOUR : : DataType : : MIDI , midi_outputs ) ;
midi_device_table . set_spacings ( 6 ) ;
midi_device_table . set_homogeneous ( true ) ;
midi_device_table . resize ( midi_inputs . size ( ) + midi_outputs . size ( ) + 3 , 1 ) ;
l = manage ( new Label ) ;
l - > set_markup ( string_compose ( " <span size= \" large \" weight= \" bold \" >%1</span> " , _ ( " MIDI Inputs " ) ) ) ;
midi_device_table . attach ( * l , 0 , 1 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
l - > set_alignment ( 0 , 0.5 ) ;
row + + ;
l - > show ( ) ;
for ( vector < string > : : iterator p = midi_inputs . begin ( ) ; p ! = midi_inputs . end ( ) ; + + p ) {
l = manage ( new Label ( ( * p ) . substr ( ( * p ) . find_last_of ( ' : ' ) + 1 ) ) ) ;
l - > set_alignment ( 0 , 0.5 ) ;
midi_device_table . attach ( * l , 0 , 1 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
l - > show ( ) ;
row + + ;
}
row + + ; // extra row of spacing
l = manage ( new Label ) ;
l - > set_markup ( string_compose ( " <span size= \" large \" weight= \" bold \" >%1</span> " , _ ( " MIDI Outputs " ) ) ) ;
midi_device_table . attach ( * l , 0 , 1 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
l - > set_alignment ( 0 , 0.5 ) ;
row + + ;
l - > show ( ) ;
for ( vector < string > : : iterator p = midi_outputs . begin ( ) ; p ! = midi_outputs . end ( ) ; + + p ) {
l = manage ( new Label ( ( * p ) . substr ( ( * p ) . find_last_of ( ' : ' ) + 1 ) ) ) ;
l - > set_alignment ( 0 , 0.5 ) ;
midi_device_table . attach ( * l , 0 , 1 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
l - > show ( ) ;
row + + ;
}
}
void
EngineControl : : update_sensitivity ( )
{
}
void
EngineControl : : backend_changed ( )
{
if ( ignore_changes ) {
return ;
}
string backend_name = backend_combo . get_active_text ( ) ;
boost : : shared_ptr < ARDOUR : : AudioBackend > backend ;
if ( ! ( backend = ARDOUR : : AudioEngine : : instance ( ) - > set_backend ( backend_name , " ardour " , " " ) ) ) {
/* eh? setting the backend failed... how ? */
return ;
}
_have_control = ARDOUR : : AudioEngine : : instance ( ) - > setup_required ( ) ;
build_notebook ( ) ;
setup_midi_tab_for_backend ( ) ;
if ( backend - > requires_driver_selection ( ) ) {
vector < string > drivers = backend - > enumerate_drivers ( ) ;
if ( ! drivers . empty ( ) ) {
{
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
set_popdown_strings ( driver_combo , drivers ) ;
driver_combo . set_active_text ( drivers . front ( ) ) ;
}
driver_changed ( ) ;
}
} else {
driver_combo . set_sensitive ( false ) ;
/* this will change the device text which will cause a call to
* device changed which will set up parameters
*/
list_devices ( ) ;
}
vector < string > midi_options = backend - > enumerate_midi_options ( ) ;
if ( midi_options . size ( ) = = 1 ) {
/* only contains the "none" option */
midi_option_combo . set_sensitive ( false ) ;
} else {
if ( _have_control ) {
set_popdown_strings ( midi_option_combo , midi_options ) ;
midi_option_combo . set_active_text ( midi_options . front ( ) ) ;
midi_option_combo . set_sensitive ( true ) ;
} else {
midi_option_combo . set_sensitive ( false ) ;
}
}
maybe_display_saved_state ( ) ;
}
bool
EngineControl : : print_channel_count ( Gtk : : SpinButton * sb )
{
uint32_t cnt = ( uint32_t ) sb - > get_value ( ) ;
if ( cnt = = 0 ) {
sb - > set_text ( _ ( " all available channels " ) ) ;
} else {
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , " %d " , cnt ) ;
sb - > set_text ( buf ) ;
}
return true ;
}
void
EngineControl : : list_devices ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
/* now fill out devices, mark sample rates, buffer sizes insensitive */
vector < ARDOUR : : AudioBackend : : DeviceStatus > all_devices = backend - > enumerate_devices ( ) ;
/* NOTE: Ardour currently does not display the "available" field of the
* returned devices .
*
* Doing so would require a different GUI widget than the combo
* box / popdown that we currently use , since it has no way to list
* items that are not selectable . Something more like a popup menu ,
* which could have unselectable items , would be appropriate .
*/
vector < string > available_devices ;
for ( vector < ARDOUR : : AudioBackend : : DeviceStatus > : : const_iterator i = all_devices . begin ( ) ; i ! = all_devices . end ( ) ; + + i ) {
available_devices . push_back ( i - > name ) ;
}
if ( ! available_devices . empty ( ) ) {
update_sensitivity ( ) ;
{
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
set_popdown_strings ( device_combo , available_devices ) ;
device_combo . set_active_text ( available_devices . front ( ) ) ;
}
device_changed ( ) ;
ok_button - > set_sensitive ( true ) ;
apply_button - > set_sensitive ( true ) ;
} else {
sample_rate_combo . set_sensitive ( false ) ;
buffer_size_combo . set_sensitive ( false ) ;
input_latency . set_sensitive ( false ) ;
output_latency . set_sensitive ( false ) ;
input_channels . set_sensitive ( false ) ;
output_channels . set_sensitive ( false ) ;
ok_button - > set_sensitive ( false ) ;
apply_button - > set_sensitive ( false ) ;
}
}
void
EngineControl : : driver_changed ( )
{
if ( ignore_changes ) {
return ;
}
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
backend - > set_driver ( driver_combo . get_active_text ( ) ) ;
list_devices ( ) ;
maybe_display_saved_state ( ) ;
}
void
EngineControl : : device_changed ( )
{
if ( ignore_changes ) {
return ;
}
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
string device_name = device_combo . get_active_text ( ) ;
vector < string > s ;
{
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
/* don't allow programmatic change to combos to cause a
recursive call to this method .
2013-09-19 15:03:20 -04:00
*/
2013-09-06 21:00:01 -04:00
2013-10-12 14:57:32 -04:00
/* sample rates */
string desired ;
vector < float > sr ;
if ( _have_control ) {
sr = backend - > available_sample_rates ( device_name ) ;
} else {
sr . push_back ( 8000.0f ) ;
sr . push_back ( 16000.0f ) ;
sr . push_back ( 32000.0f ) ;
sr . push_back ( 44100.0f ) ;
sr . push_back ( 48000.0f ) ;
sr . push_back ( 88200.0f ) ;
sr . push_back ( 96000.0f ) ;
sr . push_back ( 192000.0f ) ;
sr . push_back ( 384000.0f ) ;
}
for ( vector < float > : : const_iterator x = sr . begin ( ) ; x ! = sr . end ( ) ; + + x ) {
s . push_back ( rate_as_string ( * x ) ) ;
if ( * x = = _desired_sample_rate ) {
desired = s . back ( ) ;
}
}
if ( ! s . empty ( ) ) {
sample_rate_combo . set_sensitive ( true ) ;
set_popdown_strings ( sample_rate_combo , s ) ;
if ( desired . empty ( ) ) {
2013-10-21 11:40:46 -04:00
sample_rate_combo . set_active_text ( rate_as_string ( backend - > default_sample_rate ( ) ) ) ;
2013-10-12 14:57:32 -04:00
} else {
sample_rate_combo . set_active_text ( desired ) ;
}
} else {
sample_rate_combo . set_sensitive ( false ) ;
}
/* buffer sizes */
vector < uint32_t > bs ;
if ( _have_control ) {
bs = backend - > available_buffer_sizes ( device_name ) ;
} else if ( backend - > can_change_buffer_size_when_running ( ) ) {
bs . push_back ( 8 ) ;
bs . push_back ( 16 ) ;
bs . push_back ( 32 ) ;
bs . push_back ( 64 ) ;
bs . push_back ( 128 ) ;
bs . push_back ( 256 ) ;
bs . push_back ( 512 ) ;
bs . push_back ( 1024 ) ;
bs . push_back ( 2048 ) ;
bs . push_back ( 4096 ) ;
bs . push_back ( 8192 ) ;
}
s . clear ( ) ;
for ( vector < uint32_t > : : const_iterator x = bs . begin ( ) ; x ! = bs . end ( ) ; + + x ) {
s . push_back ( bufsize_as_string ( * x ) ) ;
}
if ( ! s . empty ( ) ) {
buffer_size_combo . set_sensitive ( true ) ;
set_popdown_strings ( buffer_size_combo , s ) ;
2013-10-21 11:40:46 -04:00
buffer_size_combo . set_active_text ( bufsize_as_string ( backend - > default_buffer_size ( ) ) ) ;
2013-10-12 14:57:32 -04:00
show_buffer_duration ( ) ;
} else {
buffer_size_combo . set_sensitive ( false ) ;
}
/* XXX theoretically need to set min + max channel counts here
*/
manage_control_app_sensitivity ( ) ;
}
/* pick up any saved state for this device */
maybe_display_saved_state ( ) ;
}
string
EngineControl : : bufsize_as_string ( uint32_t sz )
{
/* Translators: "samples" is always plural here, so no
need for plural + singular forms .
2013-08-05 13:19:23 -04:00
*/
2013-10-12 14:57:32 -04:00
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , _ ( " %u samples " ) , sz ) ;
return buf ;
}
void
EngineControl : : sample_rate_changed ( )
{
if ( ignore_changes ) {
return ;
}
/* reset the strings for buffer size to show the correct msec value
( reflecting the new sample rate ) .
2013-09-04 15:45:54 -04:00
*/
2013-10-12 14:57:32 -04:00
show_buffer_duration ( ) ;
save_state ( ) ;
2013-09-19 15:03:20 -04:00
2013-10-12 14:57:32 -04:00
}
2013-09-09 21:23:12 -04:00
2013-10-12 14:57:32 -04:00
void
EngineControl : : buffer_size_changed ( )
{
if ( ignore_changes ) {
return ;
}
2013-08-05 12:51:51 -04:00
2013-10-12 14:57:32 -04:00
show_buffer_duration ( ) ;
save_state ( ) ;
}
2013-09-04 22:58:56 -04:00
2013-10-12 14:57:32 -04:00
void
EngineControl : : show_buffer_duration ( )
{
2013-09-04 22:58:56 -04:00
2013-10-12 14:57:32 -04:00
/* buffer sizes - convert from just samples to samples + msecs for
* the displayed string
*/
2013-09-04 22:58:56 -04:00
2013-10-12 14:57:32 -04:00
string bs_text = buffer_size_combo . get_active_text ( ) ;
uint32_t samples = atoi ( bs_text ) ; /* will ignore trailing text */
uint32_t rate = get_rate ( ) ;
2013-09-17 21:09:13 -04:00
2013-10-12 14:57:32 -04:00
/* Translators: "msecs" is ALWAYS plural here, so we do not
need singular form as well .
2013-09-17 21:09:13 -04:00
*/
2013-10-12 14:57:32 -04:00
/* Developers: note the hard-coding of a double buffered model
in the ( 2 * samples ) computation of latency . we always start
the audiobackend in this configuration .
2013-08-05 12:51:51 -04:00
*/
2013-10-12 14:57:32 -04:00
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , _ ( " (%.1f msecs) " ) , ( 2 * samples ) / ( rate / 1000.0 ) ) ;
buffer_size_duration_label . set_text ( buf ) ;
}
void
EngineControl : : midi_option_changed ( )
{
if ( ! ignore_changes ) {
save_state ( ) ;
}
}
void
EngineControl : : parameter_changed ( )
{
if ( ! ignore_changes ) {
save_state ( ) ;
}
}
EngineControl : : State *
EngineControl : : get_matching_state ( const string & backend ,
const string & driver ,
const string & device )
{
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
if ( ( * i ) . backend = = backend & &
( * i ) . driver = = driver & &
( * i ) . device = = device ) {
return & ( * i ) ;
}
}
return 0 ;
}
EngineControl : : State *
EngineControl : : get_saved_state_for_currently_displayed_backend_and_device ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( backend ) {
return get_matching_state ( backend_combo . get_active_text ( ) ,
( backend - > requires_driver_selection ( ) ? ( std : : string ) driver_combo . get_active_text ( ) : string ( ) ) ,
device_combo . get_active_text ( ) ) ;
}
return get_matching_state ( backend_combo . get_active_text ( ) ,
string ( ) ,
device_combo . get_active_text ( ) ) ;
}
EngineControl : : State *
EngineControl : : save_state ( )
{
if ( ! _have_control ) {
return 0 ;
}
bool existing = true ;
State * state = get_saved_state_for_currently_displayed_backend_and_device ( ) ;
if ( ! state ) {
existing = false ;
state = new State ;
}
store_state ( * state ) ;
if ( ! existing ) {
states . push_back ( * state ) ;
}
return state ;
}
void
EngineControl : : store_state ( State & state )
{
state . backend = get_backend ( ) ;
state . driver = get_driver ( ) ;
state . device = get_device_name ( ) ;
state . sample_rate = get_rate ( ) ;
state . buffer_size = get_buffer_size ( ) ;
state . input_latency = get_input_latency ( ) ;
state . output_latency = get_output_latency ( ) ;
state . input_channels = get_input_channels ( ) ;
state . output_channels = get_output_channels ( ) ;
state . midi_option = get_midi_option ( ) ;
}
void
EngineControl : : maybe_display_saved_state ( )
{
if ( ! _have_control ) {
return ;
}
State * state = get_saved_state_for_currently_displayed_backend_and_device ( ) ;
if ( state ) {
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
if ( ! _desired_sample_rate ) {
sample_rate_combo . set_active_text ( rate_as_string ( state - > sample_rate ) ) ;
}
buffer_size_combo . set_active_text ( bufsize_as_string ( state - > buffer_size ) ) ;
/* call this explicitly because we're ignoring changes to
the controls at this point .
*/
show_buffer_duration ( ) ;
input_latency . set_value ( state - > input_latency ) ;
output_latency . set_value ( state - > output_latency ) ;
if ( ! state - > midi_option . empty ( ) ) {
midi_option_combo . set_active_text ( state - > midi_option ) ;
}
}
}
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
XMLNode &
EngineControl : : get_state ( )
{
XMLNode * root = new XMLNode ( " AudioMIDISetup " ) ;
std : : string path ;
if ( ! states . empty ( ) ) {
XMLNode * state_nodes = new XMLNode ( " EngineStates " ) ;
for ( StateList : : const_iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
XMLNode * node = new XMLNode ( " State " ) ;
node - > add_property ( " backend " , ( * i ) . backend ) ;
node - > add_property ( " driver " , ( * i ) . driver ) ;
node - > add_property ( " device " , ( * i ) . device ) ;
node - > add_property ( " sample-rate " , ( * i ) . sample_rate ) ;
node - > add_property ( " buffer-size " , ( * i ) . buffer_size ) ;
node - > add_property ( " input-latency " , ( * i ) . input_latency ) ;
node - > add_property ( " output-latency " , ( * i ) . output_latency ) ;
node - > add_property ( " input-channels " , ( * i ) . input_channels ) ;
node - > add_property ( " output-channels " , ( * i ) . output_channels ) ;
node - > add_property ( " active " , ( * i ) . active ? " yes " : " no " ) ;
node - > add_property ( " midi-option " , ( * i ) . midi_option ) ;
state_nodes - > add_child_nocopy ( * node ) ;
}
root - > add_child_nocopy ( * state_nodes ) ;
}
return * root ;
}
void
EngineControl : : set_state ( const XMLNode & root )
{
XMLNodeList clist , cclist ;
XMLNodeConstIterator citer , cciter ;
XMLNode * child ;
XMLNode * grandchild ;
XMLProperty * prop = NULL ;
if ( root . name ( ) ! = " AudioMIDISetup " ) {
return ;
}
clist = root . children ( ) ;
states . clear ( ) ;
for ( citer = clist . begin ( ) ; citer ! = clist . end ( ) ; + + citer ) {
child = * citer ;
if ( child - > name ( ) ! = " EngineStates " ) {
continue ;
}
cclist = child - > children ( ) ;
for ( cciter = cclist . begin ( ) ; cciter ! = cclist . end ( ) ; + + cciter ) {
State state ;
grandchild = * cciter ;
if ( grandchild - > name ( ) ! = " State " ) {
continue ;
}
if ( ( prop = grandchild - > property ( " backend " ) ) = = 0 ) {
continue ;
}
state . backend = prop - > value ( ) ;
if ( ( prop = grandchild - > property ( " driver " ) ) = = 0 ) {
continue ;
}
state . driver = prop - > value ( ) ;
if ( ( prop = grandchild - > property ( " device " ) ) = = 0 ) {
continue ;
}
state . device = prop - > value ( ) ;
if ( ( prop = grandchild - > property ( " sample-rate " ) ) = = 0 ) {
continue ;
}
state . sample_rate = atof ( prop - > value ( ) ) ;
if ( ( prop = grandchild - > property ( " buffer-size " ) ) = = 0 ) {
continue ;
}
state . buffer_size = atoi ( prop - > value ( ) ) ;
if ( ( prop = grandchild - > property ( " input-latency " ) ) = = 0 ) {
continue ;
}
state . input_latency = atoi ( prop - > value ( ) ) ;
if ( ( prop = grandchild - > property ( " output-latency " ) ) = = 0 ) {
continue ;
}
state . output_latency = atoi ( prop - > value ( ) ) ;
if ( ( prop = grandchild - > property ( " input-channels " ) ) = = 0 ) {
continue ;
}
state . input_channels = atoi ( prop - > value ( ) ) ;
if ( ( prop = grandchild - > property ( " output-channels " ) ) = = 0 ) {
continue ;
}
state . output_channels = atoi ( prop - > value ( ) ) ;
if ( ( prop = grandchild - > property ( " active " ) ) = = 0 ) {
continue ;
}
state . active = string_is_affirmative ( prop - > value ( ) ) ;
if ( ( prop = grandchild - > property ( " midi-option " ) ) = = 0 ) {
continue ;
}
state . midi_option = prop - > value ( ) ;
2013-09-17 10:01:24 -04:00
2013-10-12 14:57:32 -04:00
states . push_back ( state ) ;
}
}
/* now see if there was an active state and switch the setup to it */
for ( StateList : : const_iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
if ( ( * i ) . active ) {
ignore_changes + + ;
backend_combo . set_active_text ( ( * i ) . backend ) ;
driver_combo . set_active_text ( ( * i ) . driver ) ;
device_combo . set_active_text ( ( * i ) . device ) ;
sample_rate_combo . set_active_text ( rate_as_string ( ( * i ) . sample_rate ) ) ;
buffer_size_combo . set_active_text ( bufsize_as_string ( ( * i ) . buffer_size ) ) ;
input_latency . set_value ( ( * i ) . input_latency ) ;
output_latency . set_value ( ( * i ) . output_latency ) ;
midi_option_combo . set_active_text ( ( * i ) . midi_option ) ;
ignore_changes - - ;
break ;
}
}
}
int
EngineControl : : push_state_to_backend ( bool start )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
return 0 ;
}
/* figure out what is going to change */
bool restart_required = false ;
bool was_running = ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ;
bool change_driver = false ;
bool change_device = false ;
bool change_rate = false ;
bool change_bufsize = false ;
bool change_latency = false ;
bool change_channels = false ;
bool change_midi = false ;
uint32_t ochan = get_output_channels ( ) ;
uint32_t ichan = get_input_channels ( ) ;
if ( _have_control ) {
if ( started_at_least_once ) {
/* we can control the backend */
if ( backend - > requires_driver_selection ( ) ) {
if ( get_driver ( ) ! = backend - > driver_name ( ) ) {
change_driver = true ;
}
}
if ( get_device_name ( ) ! = backend - > device_name ( ) ) {
change_device = true ;
}
if ( get_rate ( ) ! = backend - > sample_rate ( ) ) {
change_rate = true ;
}
if ( get_buffer_size ( ) ! = backend - > buffer_size ( ) ) {
change_bufsize = true ;
}
if ( get_midi_option ( ) ! = backend - > midi_option ( ) ) {
change_midi = true ;
}
/* zero-requested channels means "all available" */
if ( ichan = = 0 ) {
ichan = backend - > input_channels ( ) ;
}
if ( ochan = = 0 ) {
ochan = backend - > output_channels ( ) ;
}
if ( ichan ! = backend - > input_channels ( ) ) {
change_channels = true ;
}
if ( ochan ! = backend - > output_channels ( ) ) {
change_channels = true ;
}
if ( get_input_latency ( ) ! = backend - > systemic_input_latency ( ) | |
get_output_latency ( ) ! = backend - > systemic_output_latency ( ) ) {
change_latency = true ;
}
} else {
/* backend never started, so we have to force a group
of settings .
*/
2013-10-15 22:05:10 -04:00
change_device = true ;
2013-10-15 11:08:51 -04:00
if ( backend - > requires_driver_selection ( ) ) {
2013-10-15 22:05:10 -04:00
change_driver = true ;
2013-10-15 11:08:51 -04:00
}
2013-10-12 14:57:32 -04:00
change_rate = true ;
change_bufsize = true ;
change_channels = true ;
change_latency = true ;
change_midi = true ;
}
} else {
/* we have no control over the backend, meaning that we can
* only possibly change sample rate and buffer size .
*/
if ( get_rate ( ) ! = backend - > sample_rate ( ) ) {
change_bufsize = true ;
}
if ( get_buffer_size ( ) ! = backend - > buffer_size ( ) ) {
change_bufsize = true ;
}
}
if ( ! _have_control ) {
/* We do not have control over the backend, so the best we can
* do is try to change the sample rate and / or bufsize and get
* out of here .
*/
if ( change_rate & & ! backend - > can_change_sample_rate_when_running ( ) ) {
return 1 ;
}
if ( change_bufsize & & ! backend - > can_change_buffer_size_when_running ( ) ) {
return 1 ;
}
if ( change_rate ) {
backend - > set_sample_rate ( get_rate ( ) ) ;
}
if ( change_bufsize ) {
backend - > set_buffer_size ( get_buffer_size ( ) ) ;
}
post_push ( ) ;
return 0 ;
}
/* determine if we need to stop the backend before changing parameters */
if ( change_driver | | change_device | | change_channels | | change_latency | |
( change_rate & & ! backend - > can_change_sample_rate_when_running ( ) ) | |
change_midi | |
( change_bufsize & & ! backend - > can_change_buffer_size_when_running ( ) ) ) {
restart_required = true ;
} else {
restart_required = false ;
}
if ( was_running ) {
if ( ! change_driver & & ! change_device & & ! change_channels & & ! change_latency & & ! change_midi ) {
/* no changes in any parameters that absolutely require a
* restart , so check those that might be changeable without a
* restart
*/
if ( change_rate & & ! backend - > can_change_sample_rate_when_running ( ) ) {
/* can't do this while running ... */
restart_required = true ;
}
if ( change_bufsize & & ! backend - > can_change_buffer_size_when_running ( ) ) {
/* can't do this while running ... */
restart_required = true ;
}
}
}
if ( was_running ) {
if ( restart_required ) {
if ( ARDOUR_UI : : instance ( ) - > disconnect_from_engine ( ) ) {
return - 1 ;
}
}
}
if ( change_driver & & backend - > set_driver ( get_driver ( ) ) ) {
error < < string_compose ( _ ( " Cannot set driver to %1 " ) , get_driver ( ) ) < < endmsg ;
return - 1 ;
}
if ( change_device & & backend - > set_device_name ( get_device_name ( ) ) ) {
error < < string_compose ( _ ( " Cannot set device name to %1 " ) , get_device_name ( ) ) < < endmsg ;
return - 1 ;
}
if ( change_rate & & backend - > set_sample_rate ( get_rate ( ) ) ) {
error < < string_compose ( _ ( " Cannot set sample rate to %1 " ) , get_rate ( ) ) < < endmsg ;
return - 1 ;
}
if ( change_bufsize & & backend - > set_buffer_size ( get_buffer_size ( ) ) ) {
error < < string_compose ( _ ( " Cannot set buffer size to %1 " ) , get_buffer_size ( ) ) < < endmsg ;
return - 1 ;
}
if ( change_channels | | get_input_channels ( ) = = 0 | | get_output_channels ( ) = = 0 ) {
if ( backend - > set_input_channels ( get_input_channels ( ) ) ) {
error < < string_compose ( _ ( " Cannot set input channels to %1 " ) , get_input_channels ( ) ) < < endmsg ;
return - 1 ;
}
if ( backend - > set_output_channels ( get_output_channels ( ) ) ) {
error < < string_compose ( _ ( " Cannot set output channels to %1 " ) , get_output_channels ( ) ) < < endmsg ;
return - 1 ;
}
}
if ( change_latency ) {
if ( backend - > set_systemic_input_latency ( get_input_latency ( ) ) ) {
error < < string_compose ( _ ( " Cannot set input latency to %1 " ) , get_input_latency ( ) ) < < endmsg ;
return - 1 ;
}
if ( backend - > set_systemic_output_latency ( get_output_latency ( ) ) ) {
error < < string_compose ( _ ( " Cannot set output latency to %1 " ) , get_output_latency ( ) ) < < endmsg ;
return - 1 ;
}
}
if ( change_midi ) {
backend - > set_midi_option ( get_midi_option ( ) ) ;
}
if ( start | | ( was_running & & restart_required ) ) {
if ( ARDOUR_UI : : instance ( ) - > reconnect_to_engine ( ) ) {
return - 1 ;
}
}
post_push ( ) ;
return 0 ;
}
void
EngineControl : : post_push ( )
{
/* get a pointer to the current state object, creating one if
* necessary
*/
if ( _have_control ) {
State * state = get_saved_state_for_currently_displayed_backend_and_device ( ) ;
if ( ! state ) {
state = save_state ( ) ;
assert ( state ) ;
}
/* all off */
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
( * i ) . active = false ;
}
/* mark this one active (to be used next time the dialog is
* shown )
*/
state - > active = true ;
manage_control_app_sensitivity ( ) ;
}
/* schedule a redisplay of MIDI ports */
Glib : : signal_timeout ( ) . connect ( sigc : : bind_return ( sigc : : mem_fun ( * this , & EngineControl : : refresh_midi_display ) , false ) , 1000 ) ;
}
float
EngineControl : : get_rate ( ) const
{
float r = atof ( sample_rate_combo . get_active_text ( ) ) ;
/* the string may have been translated with an abbreviation for
* thousands , so use a crude heuristic to fix this .
*/
if ( r < 1000.0 ) {
r * = 1000.0 ;
}
return r ;
}
uint32_t
EngineControl : : get_buffer_size ( ) const
{
string txt = buffer_size_combo . get_active_text ( ) ;
uint32_t samples ;
if ( sscanf ( txt . c_str ( ) , " %d " , & samples ) ! = 1 ) {
throw exception ( ) ;
}
return samples ;
}
string
EngineControl : : get_midi_option ( ) const
{
return midi_option_combo . get_active_text ( ) ;
}
uint32_t
EngineControl : : get_input_channels ( ) const
{
return ( uint32_t ) input_channels_adjustment . get_value ( ) ;
}
uint32_t
EngineControl : : get_output_channels ( ) const
{
return ( uint32_t ) output_channels_adjustment . get_value ( ) ;
}
uint32_t
EngineControl : : get_input_latency ( ) const
{
return ( uint32_t ) input_latency_adjustment . get_value ( ) ;
}
uint32_t
EngineControl : : get_output_latency ( ) const
{
return ( uint32_t ) output_latency_adjustment . get_value ( ) ;
}
string
EngineControl : : get_backend ( ) const
{
return backend_combo . get_active_text ( ) ;
}
string
EngineControl : : get_driver ( ) const
{
return driver_combo . get_active_text ( ) ;
}
string
EngineControl : : get_device_name ( ) const
{
return device_combo . get_active_text ( ) ;
}
void
EngineControl : : control_app_button_clicked ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
return ;
}
backend - > launch_control_app ( ) ;
}
void
EngineControl : : manage_control_app_sensitivity ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
return ;
}
string appname = backend - > control_app_name ( ) ;
if ( appname . empty ( ) ) {
control_app_button . set_sensitive ( false ) ;
} else {
control_app_button . set_sensitive ( true ) ;
}
}
void
EngineControl : : set_desired_sample_rate ( uint32_t sr )
{
_desired_sample_rate = sr ;
device_changed ( ) ;
}
void
EngineControl : : on_switch_page ( GtkNotebookPage * , guint page_num )
{
if ( page_num = = 0 ) {
cancel_button - > set_sensitive ( true ) ;
ok_button - > set_sensitive ( true ) ;
apply_button - > set_sensitive ( true ) ;
} else {
cancel_button - > set_sensitive ( false ) ;
ok_button - > set_sensitive ( false ) ;
apply_button - > set_sensitive ( false ) ;
}
if ( page_num = = midi_tab ) {
/* MIDI tab */
refresh_midi_display ( ) ;
}
if ( page_num = = latency_tab ) {
/* latency tab */
if ( ! ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
/* save any existing latency values */
uint32_t il = ( uint32_t ) input_latency . get_value ( ) ;
uint32_t ol = ( uint32_t ) input_latency . get_value ( ) ;
2014-04-10 13:30:25 -04:00
/* reset to zero so that our new test instance
2013-10-12 14:57:32 -04:00
will be clean of any existing latency measures .
*/
2013-09-12 16:28:51 -04:00
2013-10-12 14:57:32 -04:00
input_latency . set_value ( 0 ) ;
output_latency . set_value ( 0 ) ;
2013-09-12 16:28:51 -04:00
2013-10-12 14:57:32 -04:00
/* reset control */
2013-09-12 16:28:51 -04:00
2013-10-12 14:57:32 -04:00
input_latency . set_value ( il ) ;
output_latency . set_value ( ol ) ;
2013-09-17 10:01:24 -04:00
2013-10-12 14:57:32 -04:00
}
2013-09-12 16:28:51 -04:00
2013-10-12 14:57:32 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > prepare_for_latency_measurement ( ) ) {
disable_latency_tab ( ) ;
}
2013-09-16 15:21:32 -04:00
2013-10-12 14:57:32 -04:00
enable_latency_tab ( ) ;
2013-09-16 15:21:32 -04:00
2013-10-12 14:57:32 -04:00
} else {
2013-10-15 12:48:58 -04:00
if ( lm_running ) {
ARDOUR : : AudioEngine : : instance ( ) - > stop_latency_detection ( ) ;
}
2013-10-12 14:57:32 -04:00
}
}
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
/* latency measurement */
2013-09-12 16:28:51 -04:00
2013-10-12 14:57:32 -04:00
bool
EngineControl : : check_latency_measurement ( )
{
MTDM * mtdm = ARDOUR : : AudioEngine : : instance ( ) - > mtdm ( ) ;
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
if ( mtdm - > resolve ( ) < 0 ) {
lm_results . set_markup ( string_compose ( results_markup , _ ( " No signal detected " ) ) ) ;
return true ;
}
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
if ( mtdm - > err ( ) > 0.3 ) {
mtdm - > invert ( ) ;
mtdm - > resolve ( ) ;
}
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
char buf [ 128 ] ;
ARDOUR : : framecnt_t const sample_rate = ARDOUR : : AudioEngine : : instance ( ) - > sample_rate ( ) ;
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
if ( sample_rate = = 0 ) {
lm_results . set_markup ( string_compose ( results_markup , _ ( " Disconnected from audio engine " ) ) ) ;
ARDOUR : : AudioEngine : : instance ( ) - > stop_latency_detection ( ) ;
return false ;
}
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
uint32_t frames_total = mtdm - > del ( ) ;
uint32_t extra = frames_total - ARDOUR : : AudioEngine : : instance ( ) - > latency_signal_delay ( ) ;
2013-09-11 13:02:32 -04:00
2013-10-12 14:57:32 -04:00
snprintf ( buf , sizeof ( buf ) , " %u samples / %.3lf ms " , extra , extra * 1000.0f / sample_rate ) ;
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
bool solid = true ;
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
if ( mtdm - > err ( ) > 0.2 ) {
strcat ( buf , " " ) ;
strcat ( buf , _ ( " (signal detection error) " ) ) ;
solid = false ;
}
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
if ( mtdm - > inv ( ) ) {
strcat ( buf , " " ) ;
strcat ( buf , _ ( " (inverted - bad wiring) " ) ) ;
solid = false ;
}
2013-09-10 22:58:33 -04:00
2013-10-12 14:57:32 -04:00
if ( solid ) {
end_latency_detection ( ) ;
lm_use_button . set_sensitive ( true ) ;
have_lm_results = true ;
2013-09-10 22:58:33 -04:00
}
2013-10-12 14:57:32 -04:00
lm_results . set_markup ( string_compose ( results_markup , string_compose ( _ ( " Detected roundtrip latency: %1 " ) , buf ) ) ) ;
2013-09-10 22:58:33 -04:00
return true ;
}
2013-09-16 18:47:30 -04:00
void
EngineControl : : start_latency_detection ( )
{
ARDOUR : : AudioEngine : : instance ( ) - > set_latency_input_port ( lm_input_channel_combo . get_active_text ( ) ) ;
ARDOUR : : AudioEngine : : instance ( ) - > set_latency_output_port ( lm_output_channel_combo . get_active_text ( ) ) ;
2013-10-12 10:04:20 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > start_latency_detection ( ) = = 0 ) {
2013-10-12 14:57:32 -04:00
lm_results . set_markup ( string_compose ( results_markup , _ ( " Detecting ... " ) ) ) ;
2013-10-12 10:04:20 -04:00
latency_timeout = Glib : : signal_timeout ( ) . connect ( mem_fun ( * this , & EngineControl : : check_latency_measurement ) , 100 ) ;
2013-10-15 14:55:54 -04:00
lm_measure_label . set_text ( _ ( " Cancel " ) ) ;
2013-10-12 10:04:20 -04:00
have_lm_results = false ;
2013-10-12 14:57:32 -04:00
lm_use_button . set_sensitive ( false ) ;
2013-10-12 10:04:20 -04:00
lm_input_channel_combo . set_sensitive ( false ) ;
lm_output_channel_combo . set_sensitive ( false ) ;
2013-10-12 14:57:32 -04:00
lm_running = true ;
2013-10-12 10:04:20 -04:00
}
2013-09-16 18:47:30 -04:00
}
void
EngineControl : : end_latency_detection ( )
{
latency_timeout . disconnect ( ) ;
2013-10-12 10:04:20 -04:00
ARDOUR : : AudioEngine : : instance ( ) - > stop_latency_detection ( ) ;
2013-10-15 14:55:54 -04:00
lm_measure_label . set_text ( _ ( " Measure " ) ) ;
2013-09-16 18:47:30 -04:00
if ( ! have_lm_results ) {
2013-10-12 14:57:32 -04:00
lm_results . set_markup ( string_compose ( results_markup , _ ( " No measurement results yet " ) ) ) ;
} else {
lm_use_button . set_sensitive ( false ) ;
2013-09-16 18:47:30 -04:00
}
lm_input_channel_combo . set_sensitive ( true ) ;
lm_output_channel_combo . set_sensitive ( true ) ;
2013-10-12 14:57:32 -04:00
lm_running = false ;
2013-09-16 18:47:30 -04:00
}
2013-09-10 22:58:33 -04:00
void
2013-10-12 14:57:32 -04:00
EngineControl : : latency_button_clicked ( )
2013-09-10 22:58:33 -04:00
{
2013-10-12 14:57:32 -04:00
if ( ! lm_running ) {
2013-09-16 18:47:30 -04:00
start_latency_detection ( ) ;
2013-09-16 15:21:32 -04:00
} else {
2013-09-16 18:47:30 -04:00
end_latency_detection ( ) ;
2013-09-10 22:58:33 -04:00
}
}
2013-09-11 13:02:32 -04:00
void
EngineControl : : use_latency_button_clicked ( )
{
MTDM * mtdm = ARDOUR : : AudioEngine : : instance ( ) - > mtdm ( ) ;
if ( ! mtdm ) {
return ;
}
uint32_t frames_total = mtdm - > del ( ) ;
uint32_t extra = frames_total - ARDOUR : : AudioEngine : : instance ( ) - > latency_signal_delay ( ) ;
uint32_t one_way = extra / 2 ;
input_latency_adjustment . set_value ( one_way ) ;
output_latency_adjustment . set_value ( one_way ) ;
2013-10-12 14:57:32 -04:00
/* back to settings page */
notebook . set_current_page ( 0 ) ;
2013-09-11 13:02:32 -04:00
}
2013-09-16 18:47:30 -04:00
bool
EngineControl : : on_delete_event ( GdkEventAny * ev )
{
if ( notebook . get_current_page ( ) = = 2 ) {
/* currently on latency tab - be sure to clean up */
end_latency_detection ( ) ;
}
return ArdourDialog : : on_delete_event ( ev ) ;
}
2013-09-16 22:03:59 -04:00
2013-09-19 15:03:20 -04:00
void
EngineControl : : engine_running ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
buffer_size_combo . set_active_text ( bufsize_as_string ( backend - > buffer_size ( ) ) ) ;
sample_rate_combo . set_active_text ( rate_as_string ( backend - > sample_rate ( ) ) ) ;
2013-09-19 16:48:05 -04:00
buffer_size_combo . set_sensitive ( true ) ;
sample_rate_combo . set_sensitive ( true ) ;
2013-09-19 15:03:20 -04:00
connect_disconnect_button . set_label ( string_compose ( _ ( " Disconnect from %1 " ) , backend - > name ( ) ) ) ;
started_at_least_once = true ;
}
void
EngineControl : : engine_stopped ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
buffer_size_combo . set_sensitive ( false ) ;
connect_disconnect_button . set_label ( string_compose ( _ ( " Connect to %1 " ) , backend - > name ( ) ) ) ;
sample_rate_combo . set_sensitive ( true ) ;
buffer_size_combo . set_sensitive ( true ) ;
}
void
EngineControl : : connect_disconnect_click ( )
{
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
ARDOUR_UI : : instance ( ) - > disconnect_from_engine ( ) ;
} else {
ARDOUR_UI : : instance ( ) - > reconnect_to_engine ( ) ;
}
}
2013-10-15 13:15:03 -04:00
void
EngineControl : : calibrate_latency ( )
{
notebook . set_current_page ( latency_tab ) ;
}