2010-07-25 21:54:51 -04:00
/*
2019-08-02 17:26:43 -04:00
* Copyright ( C ) 2007 - 2012 Carl Hetherington < carl @ carlh . net >
* Copyright ( C ) 2007 - 2017 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2008 - 2012 David Robillard < d @ drobilla . net >
* Copyright ( C ) 2013 - 2014 Colin Fletcher < colin . m . fletcher @ googlemail . com >
* Copyright ( C ) 2013 - 2019 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2015 - 2016 Tim Mayberry < mojofunk @ gmail . com >
* Copyright ( C ) 2015 Ben Loftis < ben @ harrisonconsoles . com >
*
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2010-07-25 21:54:51 -04:00
2013-08-05 12:51:51 -04:00
# include <exception>
2007-10-11 18:07:47 -04:00
# include <vector>
# include <cmath>
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"
2016-09-04 20:22:39 -04:00
# include "pbd/locale_guard.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>
2019-09-26 15:12:37 -04:00
# include "widgets/tooltips.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"
2014-06-08 08:48:10 -04:00
# include "ardour/mididm.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"
2015-01-22 15:54:56 -05:00
# include "ardour/profile.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
2015-04-14 06:18:50 -04:00
# include "opts.h"
2015-08-10 00:30:04 -04:00
# include "debug.h"
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"
2016-11-30 12:13:35 -05:00
# include "ui_config.h"
2016-12-07 08:50:17 -05:00
# include "public_editor.h"
2013-09-23 21:35:17 -04:00
# include "utils.h"
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2016-11-30 16:52:06 -05:00
# include "splash.h"
2007-10-11 18:07:47 -04:00
using namespace std ;
using namespace Gtk ;
using namespace Gtkmm2ext ;
using namespace PBD ;
using namespace Glib ;
2017-07-15 11:38:28 -04:00
using namespace ArdourWidgets ;
2014-06-25 15:27:37 -04:00
using namespace ARDOUR_UI_UTILS ;
2007-10-11 18:07:47 -04:00
2015-08-10 00:30:04 -04:00
# define DEBUG_ECONTROL(msg) DEBUG_TRACE (PBD::DEBUG::EngineControl, string_compose ("%1: %2\n", __LINE__, msg));
2014-06-13 06:01:55 -04:00
static const unsigned int midi_tab = 2 ;
2013-10-10 16:18:27 -04:00
static const unsigned int latency_tab = 1 ; /* zero-based, page zero is the main setup page */
2014-06-16 11:56:52 -04:00
static const char * results_markup = X_ ( " <span weight= \" bold \" size= \" larger \" >%1</span> " ) ;
2013-10-12 14:57:32 -04:00
2007-10-11 18:07:47 -04:00
EngineControl : : EngineControl ( )
2013-09-09 13:17:53 -04:00
: ArdourDialog ( _ ( " Audio/MIDI Setup " ) )
2015-01-25 04:19:46 -05:00
, engine_status ( " " )
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 " ) )
2014-06-13 06:01:55 -04:00
, midi_devices_button ( _ ( " Midi Device Setup " ) )
2015-08-25 07:42:11 -04:00
, start_stop_button ( _ ( " Stop " ) )
2015-08-25 08:57:44 -04:00
, update_devices_button ( _ ( " Refresh Devices " ) )
2016-02-05 08:32:59 -05:00
, use_buffered_io_button ( _ ( " Use Buffered I/O " ) , ArdourButton : : led_default_elements )
2019-09-26 15:12:37 -04:00
, try_autostart_button ( _ ( " Autostart " ) , ArdourButton : : led_default_elements )
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) " ) )
2014-06-08 08:48:10 -04:00
, lm_button_audio ( _ ( " Calibrate Audio " ) )
2013-10-12 14:57:32 -04:00
, 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 )
2014-06-13 06:01:55 -04:00
, midi_back_button ( _ ( " Back to settings " ) )
2013-09-09 21:23:12 -04:00
, ignore_changes ( 0 )
2016-01-28 19:12:32 -05:00
, ignore_device_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 )
2015-03-07 05:11:50 -05:00
, queue_device_changed ( false )
2015-09-06 15:54:54 -04:00
, _have_control ( true )
2015-08-09 09:16:02 -04:00
, block_signals ( 0 )
2013-09-09 13:17:53 -04:00
{
2013-09-19 15:03:20 -04:00
using namespace Notebook_Helpers ;
2015-03-01 10:36:13 -05:00
vector < string > backend_names ;
2013-09-19 15:03:20 -04:00
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 " ) ) ;
2014-06-13 06:01:55 -04:00
/* the backend combo is the one thing that is ALWAYS visible */
vector < const ARDOUR : : AudioBackendInfo * > backends = ARDOUR : : AudioEngine : : instance ( ) - > available_backends ( ) ;
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 ( ) ;
}
for ( vector < const ARDOUR : : AudioBackendInfo * > : : const_iterator b = backends . begin ( ) ; b ! = backends . end ( ) ; + + b ) {
2015-03-01 10:36:13 -05:00
backend_names . push_back ( ( * b ) - > name ) ;
2014-06-13 06:01:55 -04:00
}
2015-03-01 10:36:13 -05:00
set_popdown_strings ( backend_combo , backend_names ) ;
2014-06-13 06:01:55 -04:00
/* setup basic packing characteristics for the table used on the main
* tab of the notebook
*/
basic_packer . set_spacings ( 6 ) ;
basic_packer . set_border_width ( 12 ) ;
basic_packer . set_homogeneous ( false ) ;
/* pack it in */
basic_hbox . pack_start ( basic_packer , false , false ) ;
/* latency measurement tab */
lm_title . set_markup ( string_compose ( " <span size= \" large \" weight= \" bold \" >%1</span> " , _ ( " Latency Measurement Tool " ) ) ) ;
row = 0 ;
lm_table . set_row_spacings ( 12 ) ;
lm_table . set_col_spacings ( 6 ) ;
lm_table . set_homogeneous ( false ) ;
lm_table . attach ( lm_title , 0 , 3 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
2014-06-16 17:36:29 -04:00
lm_preamble . set_width_chars ( 60 ) ;
lm_preamble . set_line_wrap ( true ) ;
lm_preamble . set_markup ( _ ( " <span weight= \" bold \" >Turn down the volume on your audio equipment to a very low level.</span> " ) ) ;
2014-06-13 06:01:55 -04:00
2014-06-16 17:36:29 -04:00
lm_table . attach ( lm_preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
2014-06-13 06:01:55 -04:00
row + + ;
2014-06-16 17:36:29 -04:00
Gtk : : Label * preamble ;
2014-06-13 06:01:55 -04:00
preamble = manage ( new Label ) ;
preamble - > set_width_chars ( 60 ) ;
preamble - > set_line_wrap ( true ) ;
preamble - > set_markup ( _ ( " Select two channels below and connect them using a cable. " ) ) ;
lm_table . attach ( * preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
row + + ;
2019-05-05 12:15:18 -04:00
label = manage ( new Label ( _ ( " Output channel: " ) ) ) ;
2014-06-13 06:01:55 -04:00
lm_table . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
2019-05-05 12:15:18 -04:00
lm_output_channel_list = Gtk : : ListStore : : create ( lm_output_channel_cols ) ;
lm_output_channel_combo . set_model ( lm_output_channel_list ) ;
lm_output_channel_combo . pack_start ( lm_output_channel_cols . pretty_name ) ;
2014-06-13 06:01:55 -04:00
Gtk : : Alignment * misc_align = manage ( new Alignment ( 0.0 , 0.5 ) ) ;
misc_align - > add ( lm_output_channel_combo ) ;
lm_table . attach ( * misc_align , 1 , 3 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
+ + row ;
2019-05-05 12:15:18 -04:00
label = manage ( new Label ( _ ( " Input channel: " ) ) ) ;
2014-06-13 06:01:55 -04:00
lm_table . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
2019-05-05 12:15:18 -04:00
lm_input_channel_list = Gtk : : ListStore : : create ( lm_input_channel_cols ) ;
lm_input_channel_combo . set_model ( lm_input_channel_list ) ;
lm_input_channel_combo . pack_start ( lm_input_channel_cols . pretty_name ) ;
2014-06-13 06:01:55 -04:00
misc_align = manage ( new Alignment ( 0.0 , 0.5 ) ) ;
misc_align - > add ( lm_input_channel_combo ) ;
lm_table . attach ( * misc_align , 1 , 3 , row , row + 1 , FILL , ( AttachOptions ) 0 ) ;
+ + row ;
lm_measure_label . set_padding ( 10 , 10 ) ;
lm_measure_button . add ( lm_measure_label ) ;
lm_measure_button . signal_clicked ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : latency_button_clicked ) ) ;
lm_use_button . signal_clicked ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : use_latency_button_clicked ) ) ;
2015-10-03 01:49:55 -04:00
lm_back_button_signal = lm_back_button . signal_clicked ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : latency_back_button_clicked ) ) ;
2014-06-13 06:01:55 -04:00
lm_use_button . set_sensitive ( false ) ;
/* 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 ) ;
}
preamble = manage ( new Label ) ;
preamble - > set_width_chars ( 60 ) ;
preamble - > set_line_wrap ( true ) ;
preamble - > set_markup ( _ ( " Once the channels are connected, click the \" Measure \" button. " ) ) ;
lm_table . attach ( * preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
row + + ;
preamble = manage ( new Label ) ;
preamble - > set_width_chars ( 60 ) ;
preamble - > set_line_wrap ( true ) ;
preamble - > set_markup ( _ ( " When satisfied with the results, click the \" Use results \" button. " ) ) ;
lm_table . attach ( * preamble , 0 , 3 , row , row + 1 , AttachOptions ( FILL | EXPAND ) , ( AttachOptions ) 0 ) ;
+ + 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 ) ;
+ + 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 " ) ) ) ;
lm_vbox . set_border_width ( 12 ) ;
lm_vbox . pack_start ( lm_table , false , false ) ;
midi_back_button . signal_clicked ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( notebook , & Gtk : : Notebook : : set_current_page ) , 0 ) ) ;
/* pack it all up */
notebook . pages ( ) . push_back ( TabElem ( basic_vbox , _ ( " Audio " ) ) ) ;
notebook . pages ( ) . push_back ( TabElem ( lm_vbox , _ ( " Latency " ) ) ) ;
notebook . pages ( ) . push_back ( TabElem ( midi_vbox , _ ( " MIDI " ) ) ) ;
notebook . set_border_width ( 12 ) ;
2016-10-19 17:44:54 -04:00
notebook . set_show_tabs ( false ) ;
2014-06-13 06:01:55 -04:00
notebook . show_all ( ) ;
notebook . set_name ( " SettingsNotebook " ) ;
/* packup the notebook */
get_vbox ( ) - > set_border_width ( 12 ) ;
get_vbox ( ) - > pack_start ( notebook ) ;
/* need a special function to print "all available channels" when the
* channel counts hit zero .
*/
input_channels . signal_output ( ) . connect ( sigc : : bind ( sigc : : ptr_fun ( & EngineControl : : print_channel_count ) , & input_channels ) ) ;
output_channels . signal_output ( ) . connect ( sigc : : bind ( sigc : : ptr_fun ( & EngineControl : : print_channel_count ) , & output_channels ) ) ;
midi_devices_button . signal_clicked . connect ( mem_fun ( * this , & EngineControl : : configure_midi_devices ) ) ;
midi_devices_button . set_name ( " generic button " ) ;
2014-06-13 18:06:52 -04:00
midi_devices_button . set_can_focus ( true ) ;
2014-06-13 06:01:55 -04:00
2015-08-11 09:34:07 -04:00
control_app_button . signal_clicked . connect ( mem_fun ( * this , & EngineControl : : control_app_button_clicked ) ) ;
control_app_button . set_name ( " generic button " ) ;
control_app_button . set_can_focus ( true ) ;
2014-06-13 06:01:55 -04:00
manage_control_app_sensitivity ( ) ;
2015-08-25 07:42:11 -04:00
start_stop_button . signal_clicked . connect ( mem_fun ( * this , & EngineControl : : start_stop_button_clicked ) ) ;
start_stop_button . set_sensitive ( false ) ;
start_stop_button . set_name ( " generic button " ) ;
start_stop_button . set_can_focus ( true ) ;
2016-11-30 08:44:36 -05:00
start_stop_button . set_can_default ( true ) ;
2017-03-01 16:29:54 -05:00
start_stop_button . set_act_on_release ( false ) ;
2015-08-11 09:34:07 -04:00
2015-08-25 08:57:44 -04:00
update_devices_button . signal_clicked . connect ( mem_fun ( * this , & EngineControl : : update_devices_button_clicked ) ) ;
update_devices_button . set_sensitive ( false ) ;
update_devices_button . set_name ( " generic button " ) ;
update_devices_button . set_can_focus ( true ) ;
2016-02-05 08:32:59 -05:00
use_buffered_io_button . signal_clicked . connect ( mem_fun ( * this , & EngineControl : : use_buffered_io_button_clicked ) ) ;
use_buffered_io_button . set_sensitive ( false ) ;
use_buffered_io_button . set_name ( " generic button " ) ;
use_buffered_io_button . set_can_focus ( true ) ;
2019-09-26 15:12:37 -04:00
try_autostart_button . signal_clicked . connect ( mem_fun ( * this , & EngineControl : : try_autostart_button_clicked ) ) ;
try_autostart_button . set_name ( " generic button " ) ;
try_autostart_button . set_can_focus ( true ) ;
config_parameter_changed ( " try-autostart-engine " ) ;
set_tooltip ( try_autostart_button ,
string_compose ( _ ( " Always try these settings when starting %1, if the same device is available " ) , PROGRAM_NAME ) ) ;
ARDOUR : : Config - > ParameterChanged . connect ( * this , invalidator ( * this ) , boost : : bind ( & EngineControl : : config_parameter_changed , this , _1 ) , gui_context ( ) ) ;
2014-06-13 06:01:55 -04:00
/* Pick up any existing audio setup configuration, if appropriate */
XMLNode * audio_setup = ARDOUR : : Config - > extra_xml ( " AudioMIDISetup " ) ;
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 ( ) ) ;
2015-03-06 00:24:44 -05:00
ARDOUR : : AudioEngine : : instance ( ) - > DeviceListChanged . connect ( devicelist_connection , MISSING_INVALIDATOR , boost : : bind ( & EngineControl : : device_list_changed , this ) , gui_context ( ) ) ;
2014-06-13 06:01:55 -04:00
2015-02-24 15:29:02 -05:00
if ( audio_setup ) {
2015-08-10 09:20:07 -04:00
if ( ! set_state ( * audio_setup ) ) {
set_default_state ( ) ;
}
} else {
set_default_state ( ) ;
2015-03-01 10:36:13 -05:00
}
2016-04-18 08:07:49 -04:00
update_sensitivity ( ) ;
2015-08-09 08:36:26 -04:00
connect_changed_signals ( ) ;
2015-03-01 10:36:13 -05:00
2015-08-09 08:36:26 -04:00
notebook . signal_switch_page ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : on_switch_page ) ) ;
connect_disconnect_button . signal_clicked ( ) . connect ( sigc : : mem_fun ( * this , & EngineControl : : connect_disconnect_click ) ) ;
2014-06-13 06:01:55 -04:00
2016-04-18 08:07:49 -04:00
connect_disconnect_button . set_no_show_all ( ) ;
start_stop_button . set_no_show_all ( ) ;
2015-08-09 08:36:26 -04:00
}
void
2015-08-09 09:16:02 -04:00
EngineControl : : connect_changed_signals ( )
2015-08-09 08:36:26 -04:00
{
2015-08-09 09:16:02 -04:00
backend_combo_connection = backend_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : backend_changed ) ) ;
driver_combo_connection = driver_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : driver_changed ) ) ;
sample_rate_combo_connection = sample_rate_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : sample_rate_changed ) ) ;
buffer_size_combo_connection = buffer_size_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : buffer_size_changed ) ) ;
2015-12-04 19:32:56 -05:00
nperiods_combo_connection = nperiods_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : nperiods_changed ) ) ;
2015-08-09 09:16:02 -04:00
device_combo_connection = device_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : device_changed ) ) ;
midi_option_combo_connection = midi_option_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : midi_option_changed ) ) ;
input_device_combo_connection = input_device_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : input_device_changed ) ) ;
output_device_combo_connection = output_device_combo . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : output_device_changed ) ) ;
input_latency_connection = input_latency . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
output_latency_connection = output_latency . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
input_channels_connection = input_channels . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
output_channels_connection = output_channels . signal_changed ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : parameter_changed ) ) ;
}
void
EngineControl : : block_changed_signals ( )
{
if ( block_signals + + = = 0 ) {
2015-08-09 22:58:06 -04:00
DEBUG_ECONTROL ( " Blocking changed signals " ) ;
2015-08-09 09:16:02 -04:00
backend_combo_connection . block ( ) ;
driver_combo_connection . block ( ) ;
sample_rate_combo_connection . block ( ) ;
buffer_size_combo_connection . block ( ) ;
2015-12-04 19:32:56 -05:00
nperiods_combo_connection . block ( ) ;
2015-08-09 09:16:02 -04:00
device_combo_connection . block ( ) ;
input_device_combo_connection . block ( ) ;
output_device_combo_connection . block ( ) ;
midi_option_combo_connection . block ( ) ;
input_latency_connection . block ( ) ;
output_latency_connection . block ( ) ;
input_channels_connection . block ( ) ;
output_channels_connection . block ( ) ;
}
}
void
EngineControl : : unblock_changed_signals ( )
{
if ( - - block_signals = = 0 ) {
2015-08-09 22:58:06 -04:00
DEBUG_ECONTROL ( " Unblocking changed signals " ) ;
2015-08-09 09:16:02 -04:00
backend_combo_connection . unblock ( ) ;
driver_combo_connection . unblock ( ) ;
sample_rate_combo_connection . unblock ( ) ;
buffer_size_combo_connection . unblock ( ) ;
2015-12-04 19:32:56 -05:00
nperiods_combo_connection . unblock ( ) ;
2015-08-09 09:16:02 -04:00
device_combo_connection . unblock ( ) ;
input_device_combo_connection . unblock ( ) ;
output_device_combo_connection . unblock ( ) ;
midi_option_combo_connection . unblock ( ) ;
input_latency_connection . unblock ( ) ;
output_latency_connection . unblock ( ) ;
input_channels_connection . unblock ( ) ;
output_channels_connection . unblock ( ) ;
}
}
EngineControl : : SignalBlocker : : SignalBlocker ( EngineControl & engine_control ,
const std : : string & reason )
2017-07-01 12:42:24 -04:00
: ec ( engine_control )
, m_reason ( reason )
2015-08-09 09:16:02 -04:00
{
DEBUG_ECONTROL ( string_compose ( " SignalBlocker: %1 " , m_reason ) ) ;
ec . block_changed_signals ( ) ;
}
EngineControl : : SignalBlocker : : ~ SignalBlocker ( )
{
DEBUG_ECONTROL ( string_compose ( " ~SignalBlocker: %1 " , m_reason ) ) ;
ec . unblock_changed_signals ( ) ;
2014-06-13 06:01:55 -04:00
}
2014-09-01 16:06:45 -04:00
void
EngineControl : : on_show ( )
{
ArdourDialog : : on_show ( ) ;
2015-04-07 09:23:24 -04:00
if ( ! ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) | | ! ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
// re-check _have_control (jackd running) see #6041
backend_changed ( ) ;
}
2015-01-17 13:50:48 -05:00
device_changed ( ) ;
2016-11-30 08:44:36 -05:00
start_stop_button . grab_focus ( ) ;
2014-09-01 16:06:45 -04:00
}
2016-12-07 08:50:17 -05:00
void
EngineControl : : on_map ( )
{
2018-12-05 20:23:09 -05:00
if ( ! ARDOUR_UI : : instance ( ) - > the_session ( ) & & ! PublicEditor : : _instance ) {
2016-12-07 08:50:17 -05:00
set_type_hint ( Gdk : : WINDOW_TYPE_HINT_NORMAL ) ;
} else if ( UIConfiguration : : instance ( ) . get_all_floating_windows_are_dialogs ( ) ) {
set_type_hint ( Gdk : : WINDOW_TYPE_HINT_DIALOG ) ;
} else {
set_type_hint ( Gdk : : WINDOW_TYPE_HINT_UTILITY ) ;
}
ArdourDialog : : on_map ( ) ;
}
2019-09-26 15:12:37 -04:00
void
EngineControl : : config_parameter_changed ( std : : string const & p )
{
if ( p = = " try-autostart-engine " ) {
try_autostart_button . set_active ( ARDOUR : : Config - > get_try_autostart_engine ( ) ) ;
}
}
2015-10-02 21:40:34 -04:00
bool
EngineControl : : start_engine ( )
{
2019-10-10 18:50:57 -04:00
if ( push_state_to_backend ( true ) ! = 0 ) {
MessageDialog msg ( * this , ARDOUR : : AudioEngine : : instance ( ) - > get_last_backend_error ( ) ) ;
2015-10-02 21:40:34 -04:00
msg . run ( ) ;
return false ;
}
return true ;
}
2015-10-03 00:09:45 -04:00
bool
2015-12-04 11:34:46 -05:00
EngineControl : : stop_engine ( bool for_latency )
2015-10-03 00:09:45 -04:00
{
2015-12-04 11:34:46 -05:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > stop ( for_latency ) ) {
2015-10-03 00:09:45 -04:00
MessageDialog msg ( * this ,
ARDOUR : : AudioEngine : : instance ( ) - > get_last_backend_error ( ) ) ;
msg . run ( ) ;
return false ;
}
return true ;
}
2014-06-13 06:01:55 -04:00
void
EngineControl : : build_notebook ( )
{
Label * label ;
AttachOptions xopt = AttachOptions ( FILL | EXPAND ) ;
/* clear the table */
Gtkmm2ext : : container_clear ( basic_vbox ) ;
Gtkmm2ext : : container_clear ( basic_packer ) ;
if ( control_app_button . get_parent ( ) ) {
control_app_button . get_parent ( ) - > remove ( control_app_button ) ;
}
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 ) ;
2015-08-11 09:34:07 -04:00
basic_packer . attach ( engine_status , 2 , 3 , 0 , 1 , xopt , ( AttachOptions ) 0 ) ;
engine_status . show ( ) ;
2015-08-25 07:42:11 -04:00
basic_packer . attach ( start_stop_button , 3 , 4 , 0 , 1 , xopt , xopt ) ;
2015-08-11 09:34:07 -04:00
2014-06-13 06:01:55 -04:00
lm_button_audio . signal_clicked . connect ( sigc : : mem_fun ( * this , & EngineControl : : calibrate_audio_latency ) ) ;
lm_button_audio . set_name ( " generic button " ) ;
2014-06-13 18:06:52 -04:00
lm_button_audio . set_can_focus ( true ) ;
2014-06-13 06:01:55 -04:00
if ( _have_control ) {
build_full_control_notebook ( ) ;
} else {
build_no_control_notebook ( ) ;
}
basic_vbox . pack_start ( basic_hbox , false , false ) ;
2014-10-03 09:32:12 -04:00
{
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
basic_vbox . show_all ( ) ;
}
2014-06-13 06:01:55 -04:00
}
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
2019-09-27 07:58:28 -04:00
int btn = 1 ; // row zero == start_stop_button
bool autostart_packed = false ;
2014-06-13 06:01:55 -04:00
/* 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 + + ;
}
2015-05-04 22:59:26 -04:00
if ( backend - > use_separate_input_and_output_devices ( ) ) {
label = manage ( left_aligned_label ( _ ( " Input Device: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( input_device_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
label = manage ( left_aligned_label ( _ ( " Output Device: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( output_device_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
row + + ;
// reset so it isn't used in state comparisons
device_combo . set_active_text ( " " ) ;
} else {
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 + + ;
// reset these so they don't get used in state comparisons
input_device_combo . set_active_text ( " " ) ;
output_device_combo . set_active_text ( " " ) ;
}
2014-06-13 06:01:55 -04:00
2019-09-27 07:58:28 -04:00
/* same line as Driver */
if ( backend - > can_use_buffered_io ( ) ) {
basic_packer . attach ( use_buffered_io_button , 3 , 4 , btn , btn + 1 , xopt , xopt ) ;
btn + + ;
}
/* same line as Device(s) */
if ( backend - > can_request_update_devices ( ) ) {
basic_packer . attach ( update_devices_button , 3 , 4 , btn , btn + 1 , xopt , xopt ) ;
btn + + ;
}
/* prefer "try autostart" below "Start" if possible */
if ( btn < row ) {
basic_packer . attach ( try_autostart_button , 3 , 4 , btn , btn + 1 , xopt , xopt ) ;
btn + + ;
autostart_packed = true ;
}
2014-06-13 06:01:55 -04:00
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 ) ;
2015-01-22 15:54:56 -05:00
2015-12-04 19:32:56 -05:00
int ctrl_btn_span = 1 ;
if ( backend - > can_set_period_size ( ) ) {
row + + ;
label = manage ( left_aligned_label ( _ ( " Periods: " ) ) ) ;
basic_packer . attach ( * label , 0 , 1 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
basic_packer . attach ( nperiods_combo , 1 , 2 , row , row + 1 , xopt , ( AttachOptions ) 0 ) ;
+ + ctrl_btn_span ;
}
2015-01-22 15:54:56 -05:00
2019-09-27 07:58:28 -04:00
/* button spans 2 or 3 rows: Sample rate, Buffer size, Periods */
2015-12-04 19:32:56 -05:00
basic_packer . attach ( control_app_button , 3 , 4 , row - ctrl_btn_span , row + 1 , xopt , xopt ) ;
2014-06-13 06:01:55 -04:00
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 ) ;
2015-01-22 15:54:56 -05:00
if ( ! ARDOUR : : Profile - > get_mixbus ( ) ) {
2019-05-05 12:15:18 -04:00
label = manage ( left_aligned_label ( _ ( " Input channels: " ) ) ) ;
2015-01-22 15:54:56 -05:00
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 ;
}
2015-10-05 10:17:49 -04:00
2014-06-13 06:01:55 -04:00
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 ) ;
2015-01-22 15:54:56 -05:00
if ( ! ARDOUR : : Profile - > get_mixbus ( ) ) {
2019-05-05 12:15:18 -04:00
label = manage ( left_aligned_label ( _ ( " Output channels: " ) ) ) ;
2015-01-22 15:54:56 -05:00
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 ;
}
2015-10-05 10:17:49 -04:00
2019-09-27 07:58:28 -04:00
/* Prefere next available vertical slot, 1 row */
2019-09-29 16:42:02 -04:00
if ( btn < row & & ! autostart_packed ) {
2019-09-27 07:58:28 -04:00
basic_packer . attach ( try_autostart_button , 3 , 4 , btn , btn + 1 , xopt , xopt ) ;
btn + + ;
autostart_packed = true ;
}
2014-06-13 06:01:55 -04:00
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_audio , 3 , 4 , row - 1 , row + 1 , xopt , xopt ) ;
+ + row ;
2015-03-26 22:43:33 -04:00
label = manage ( left_aligned_label ( _ ( " MIDI System: " ) ) ) ;
2014-06-13 06:01:55 -04:00
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 ) ;
basic_packer . attach ( midi_devices_button , 3 , 4 , row , row + 1 , xopt , xopt ) ;
row + + ;
2019-09-26 15:12:37 -04:00
2019-09-27 07:58:28 -04:00
if ( ! autostart_packed ) {
basic_packer . attach ( try_autostart_button , 3 , 4 , row , row + 1 , xopt , xopt ) ;
}
2014-06-13 06:01:55 -04:00
}
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
2015-06-03 13:48:43 -04:00
const string msg = string_compose ( _ ( " %1 is already running. %2 will connect to it and use the existing settings. " ) , backend - > name ( ) , PROGRAM_NAME ) ;
2014-06-13 06:01:55 -04:00
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 + + ;
}
basic_packer . attach ( connect_disconnect_button , 0 , 2 , row , row + 1 , FILL , AttachOptions ( 0 ) ) ;
row + + ;
}
EngineControl : : ~ EngineControl ( )
{
ignore_changes = true ;
}
void
EngineControl : : disable_latency_tab ( )
{
2019-05-05 12:15:18 -04:00
lm_input_channel_list - > clear ( ) ;
lm_output_channel_list - > clear ( ) ;
2014-06-13 06:01:55 -04:00
lm_measure_button . set_sensitive ( false ) ;
lm_use_button . set_sensitive ( false ) ;
}
void
EngineControl : : enable_latency_tab ( )
{
vector < string > outputs ;
vector < string > inputs ;
ARDOUR : : DataType const type = _measure_midi ? ARDOUR : : DataType : : MIDI : ARDOUR : : DataType : : AUDIO ;
ARDOUR : : AudioEngine : : instance ( ) - > get_physical_outputs ( type , outputs ) ;
ARDOUR : : AudioEngine : : instance ( ) - > get_physical_inputs ( type , inputs ) ;
2014-06-19 13:42:59 -04:00
if ( ! ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
MessageDialog msg ( _ ( " Failed to start or connect to audio-engine. \n \n Latency calibration requires a working audio interface. " ) ) ;
notebook . set_current_page ( 0 ) ;
msg . run ( ) ;
return ;
2014-06-16 17:36:29 -04:00
}
2014-06-19 13:42:59 -04:00
else if ( inputs . empty ( ) | | outputs . empty ( ) ) {
2014-06-13 06:01:55 -04:00
MessageDialog msg ( _ ( " Your selected audio configuration is playback- or capture-only. \n \n Latency calibration requires playback and capture " ) ) ;
notebook . set_current_page ( 0 ) ;
msg . run ( ) ;
return ;
}
2014-06-22 12:21:10 -04:00
lm_back_button_signal . disconnect ( ) ;
2014-06-19 13:42:59 -04:00
if ( _measure_midi ) {
2014-06-22 12:21:10 -04:00
lm_back_button_signal = lm_back_button . signal_clicked ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( notebook , & Gtk : : Notebook : : set_current_page ) , midi_tab ) ) ;
2014-07-10 14:46:15 -04:00
lm_preamble . hide ( ) ;
2014-06-13 06:01:55 -04:00
} else {
2015-10-03 01:49:55 -04:00
lm_back_button_signal = lm_back_button . signal_clicked ( ) . connect (
sigc : : mem_fun ( * this , & EngineControl : : latency_back_button_clicked ) ) ;
2014-07-10 14:46:15 -04:00
lm_preamble . show ( ) ;
2014-06-13 06:01:55 -04:00
}
2019-05-05 12:15:18 -04:00
lm_output_channel_list - > clear ( ) ;
for ( vector < string > : : const_iterator i = outputs . begin ( ) ; i ! = outputs . end ( ) ; + + i ) {
Gtk : : TreeModel : : iterator iter = lm_output_channel_list - > append ( ) ;
Gtk : : TreeModel : : Row row = * iter ;
row [ lm_output_channel_cols . port_name ] = * i ;
2019-09-20 17:30:05 -04:00
std : : string pn = ARDOUR : : AudioEngine : : instance ( ) - > get_pretty_name_by_name ( * i ) ;
if ( pn . empty ( ) ) {
pn = ( * i ) . substr ( ( * i ) . find ( ' : ' ) + 1 ) ;
}
row [ lm_output_channel_cols . pretty_name ] = pn ;
2019-05-05 12:15:18 -04:00
}
lm_output_channel_combo . set_active ( 0 ) ;
2014-06-19 13:42:59 -04:00
lm_output_channel_combo . set_sensitive ( true ) ;
2019-05-05 12:15:18 -04:00
lm_input_channel_list - > clear ( ) ;
for ( vector < string > : : const_iterator i = inputs . begin ( ) ; i ! = inputs . end ( ) ; + + i ) {
Gtk : : TreeModel : : iterator iter = lm_input_channel_list - > append ( ) ;
Gtk : : TreeModel : : Row row = * iter ;
row [ lm_input_channel_cols . port_name ] = * i ;
2019-09-20 17:30:05 -04:00
std : : string pn = ARDOUR : : AudioEngine : : instance ( ) - > get_pretty_name_by_name ( * i ) ;
if ( pn . empty ( ) ) {
pn = ( * i ) . substr ( ( * i ) . find ( ' : ' ) + 1 ) ;
}
row [ lm_input_channel_cols . pretty_name ] = pn ;
2019-05-05 12:15:18 -04:00
}
lm_input_channel_combo . set_active ( 0 ) ;
2014-06-19 13:42:59 -04:00
lm_input_channel_combo . set_sensitive ( true ) ;
2014-06-13 06:01:55 -04:00
lm_measure_button . set_sensitive ( true ) ;
}
void
EngineControl : : setup_midi_tab_for_backend ( )
{
2016-10-19 17:44:54 -04:00
string backend = backend_combo . get_active_text ( ) ;
2016-10-18 18:00:55 -04:00
Gtkmm2ext : : container_clear ( midi_vbox ) ;
midi_vbox . set_border_width ( 12 ) ;
midi_device_table . set_border_width ( 12 ) ;
2016-10-19 17:44:54 -04:00
if ( backend = = " JACK " ) {
setup_midi_tab_for_jack ( ) ;
}
2016-10-18 18:00:55 -04:00
midi_vbox . pack_start ( midi_device_table , true , true ) ;
midi_vbox . pack_start ( midi_back_button , false , false ) ;
midi_vbox . show_all ( ) ;
2016-10-18 16:56:35 -04:00
}
2015-08-11 08:43:00 -04:00
void
EngineControl : : update_sensitivity ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
2015-08-25 07:42:11 -04:00
start_stop_button . set_sensitive ( false ) ;
2015-08-11 08:43:00 -04:00
return ;
}
bool valid = true ;
size_t devices_available = 0 ;
2017-04-01 08:37:24 -04:00
bool engine_running = ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ;
2015-08-11 08:43:00 -04:00
if ( backend - > use_separate_input_and_output_devices ( ) ) {
devices_available + = get_popdown_string_count ( input_device_combo ) ;
devices_available + = get_popdown_string_count ( output_device_combo ) ;
} else {
devices_available + = get_popdown_string_count ( device_combo ) ;
}
if ( devices_available = = 0 ) {
valid = false ;
input_latency . set_sensitive ( false ) ;
output_latency . set_sensitive ( false ) ;
input_channels . set_sensitive ( false ) ;
output_channels . set_sensitive ( false ) ;
} else {
input_latency . set_sensitive ( true ) ;
output_latency . set_sensitive ( true ) ;
2017-04-01 08:37:24 -04:00
input_channels . set_sensitive ( ! engine_running ) ;
output_channels . set_sensitive ( ! engine_running ) ;
2015-08-11 08:43:00 -04:00
}
if ( get_popdown_string_count ( buffer_size_combo ) > 0 ) {
2017-04-01 08:37:24 -04:00
if ( ! engine_running ) {
2015-08-11 08:43:00 -04:00
buffer_size_combo . set_sensitive ( valid ) ;
2017-08-03 21:36:03 -04:00
} else if ( backend - > can_change_buffer_size_when_running ( ) ) {
2015-08-11 08:43:00 -04:00
buffer_size_combo . set_sensitive ( valid | | ! _have_control ) ;
} else {
buffer_size_combo . set_sensitive ( false ) ;
}
} else {
buffer_size_combo . set_sensitive ( false ) ;
valid = false ;
}
if ( get_popdown_string_count ( sample_rate_combo ) > 0 ) {
2016-09-30 10:47:57 -04:00
bool allow_to_set_rate = false ;
2017-04-01 08:37:24 -04:00
if ( ! engine_running ) {
2018-12-05 20:23:09 -05:00
if ( ! ARDOUR_UI : : instance ( ) - > the_session ( ) ) {
2016-09-30 10:47:57 -04:00
// engine is not running, no session loaded -> anything goes.
allow_to_set_rate = true ;
} else if ( _desired_sample_rate > 0 & & get_rate ( ) ! = _desired_sample_rate ) {
// only allow to change if the current setting is not the native session rate.
allow_to_set_rate = true ;
}
2015-08-11 08:43:00 -04:00
}
2016-09-30 10:47:57 -04:00
sample_rate_combo . set_sensitive ( allow_to_set_rate ) ;
2015-08-11 08:43:00 -04:00
} else {
sample_rate_combo . set_sensitive ( false ) ;
valid = false ;
}
2015-12-04 19:32:56 -05:00
if ( get_popdown_string_count ( nperiods_combo ) > 0 ) {
2017-04-01 08:37:24 -04:00
if ( ! engine_running ) {
2015-12-04 19:32:56 -05:00
nperiods_combo . set_sensitive ( true ) ;
} else {
nperiods_combo . set_sensitive ( false ) ;
}
} else {
nperiods_combo . set_sensitive ( false ) ;
}
2015-08-25 07:42:11 -04:00
if ( _have_control ) {
start_stop_button . set_sensitive ( true ) ;
start_stop_button . show ( ) ;
2017-04-01 08:37:24 -04:00
if ( engine_running ) {
2015-08-25 07:42:11 -04:00
start_stop_button . set_text ( " Stop " ) ;
2015-08-25 08:57:44 -04:00
update_devices_button . set_sensitive ( false ) ;
2016-02-05 08:32:59 -05:00
use_buffered_io_button . set_sensitive ( false ) ;
2015-08-25 07:42:11 -04:00
} else {
start_stop_button . set_text ( " Start " ) ;
2019-09-27 07:58:28 -04:00
update_devices_button . set_sensitive ( backend - > can_request_update_devices ( ) ) ;
use_buffered_io_button . set_sensitive ( backend - > can_use_buffered_io ( ) ) ;
2015-08-25 07:42:11 -04:00
}
} else {
start_stop_button . set_sensitive ( false ) ;
start_stop_button . hide ( ) ;
}
2017-04-01 08:37:24 -04:00
if ( engine_running & & _have_control ) {
2015-08-11 13:13:10 -04:00
input_device_combo . set_sensitive ( false ) ;
output_device_combo . set_sensitive ( false ) ;
device_combo . set_sensitive ( false ) ;
2015-08-11 16:04:28 -04:00
driver_combo . set_sensitive ( false ) ;
2015-08-11 09:34:07 -04:00
} else {
2015-08-11 13:13:10 -04:00
input_device_combo . set_sensitive ( true ) ;
output_device_combo . set_sensitive ( true ) ;
device_combo . set_sensitive ( true ) ;
2015-08-11 16:04:28 -04:00
if ( backend - > requires_driver_selection ( ) & & get_popdown_string_count ( driver_combo ) > 0 ) {
driver_combo . set_sensitive ( true ) ;
} else {
driver_combo . set_sensitive ( false ) ;
}
2015-08-11 09:34:07 -04:00
}
2017-04-01 08:37:24 -04:00
midi_option_combo . set_sensitive ( ! engine_running ) ;
2015-08-11 08:43:00 -04:00
}
2016-10-19 17:44:54 -04:00
void
EngineControl : : setup_midi_tab_for_jack ( )
{
}
2014-06-13 06:01:55 -04:00
void
EngineControl : : midi_latency_adjustment_changed ( Gtk : : Adjustment * a , MidiDeviceSettings device , bool for_input ) {
if ( for_input ) {
device - > input_latency = a - > get_value ( ) ;
} else {
device - > output_latency = a - > get_value ( ) ;
}
2018-12-23 15:51:09 -05:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) & & ! _measure_midi ) {
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
if ( backend - > can_change_systemic_latency_when_running ( ) & & device - > enabled ) {
if ( for_input ) {
backend - > set_systemic_midi_input_latency ( device - > name , device - > input_latency ) ;
} else {
backend - > set_systemic_midi_output_latency ( device - > name , device - > output_latency ) ;
}
}
}
2014-06-13 06:01:55 -04:00
}
2014-06-13 18:06:52 -04:00
void
EngineControl : : midi_device_enabled_toggled ( ArdourButton * b , MidiDeviceSettings device ) {
2014-06-13 06:01:55 -04:00
b - > set_active ( ! b - > get_active ( ) ) ;
device - > enabled = b - > get_active ( ) ;
2014-06-13 18:06:52 -04:00
refresh_midi_display ( device - > name ) ;
2018-12-23 15:51:09 -05:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
backend - > set_midi_device_enabled ( device - > name , device - > enabled ) ;
if ( backend - > can_change_systemic_latency_when_running ( ) & & device - > enabled ) {
backend - > set_systemic_midi_input_latency ( device - > name , device - > input_latency ) ;
backend - > set_systemic_midi_output_latency ( device - > name , device - > output_latency ) ;
}
}
2014-06-13 06:01:55 -04:00
}
void
2014-06-13 18:06:52 -04:00
EngineControl : : refresh_midi_display ( std : : string focus )
2014-06-13 06:01:55 -04:00
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
int row = 0 ;
AttachOptions xopt = AttachOptions ( FILL | EXPAND ) ;
Gtk : : Label * l ;
Gtkmm2ext : : container_clear ( midi_device_table ) ;
midi_device_table . set_spacings ( 6 ) ;
l = manage ( new Label ) ;
l - > set_markup ( string_compose ( " <span size= \" large \" weight= \" bold \" >%1</span> " , _ ( " MIDI Devices " ) ) ) ;
midi_device_table . attach ( * l , 0 , 4 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
l - > set_alignment ( 0.5 , 0.5 ) ;
row + + ;
l - > show ( ) ;
l = manage ( new Label ( _ ( " Device " ) ) ) ; l - > show ( ) ; l - > set_alignment ( 0.5 , 0.5 ) ;
midi_device_table . attach ( * l , 0 , 1 , row , row + 2 , xopt , AttachOptions ( 0 ) ) ;
2019-05-05 12:15:18 -04:00
l = manage ( new Label ( _ ( " Systemic Latency [samples] " ) ) ) ; l - > show ( ) ; l - > set_alignment ( 0.5 , 0.5 ) ;
2014-06-13 06:01:55 -04:00
midi_device_table . attach ( * l , 1 , 3 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
row + + ;
l = manage ( new Label ( _ ( " Input " ) ) ) ; l - > show ( ) ; l - > set_alignment ( 0.5 , 0.5 ) ;
midi_device_table . attach ( * l , 1 , 2 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
l = manage ( new Label ( _ ( " Output " ) ) ) ; l - > show ( ) ; l - > set_alignment ( 0.5 , 0.5 ) ;
midi_device_table . attach ( * l , 2 , 3 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ;
row + + ;
for ( vector < MidiDeviceSettings > : : const_iterator p = _midi_devices . begin ( ) ; p ! = _midi_devices . end ( ) ; + + p ) {
ArdourButton * m ;
Gtk : : Button * b ;
Gtk : : Adjustment * a ;
Gtk : : SpinButton * s ;
bool enabled = ( * p ) - > enabled ;
m = manage ( new ArdourButton ( ( * p ) - > name , ArdourButton : : led_default_elements ) ) ;
m - > set_name ( " midi device " ) ;
2014-06-13 18:06:52 -04:00
m - > set_can_focus ( Gtk : : CAN_FOCUS ) ;
2014-06-13 06:01:55 -04:00
m - > add_events ( Gdk : : BUTTON_RELEASE_MASK ) ;
m - > set_active ( enabled ) ;
2014-06-13 18:06:52 -04:00
m - > signal_clicked . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & EngineControl : : midi_device_enabled_toggled ) , m , * p ) ) ;
2014-06-13 06:01:55 -04:00
midi_device_table . attach ( * m , 0 , 1 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ; m - > show ( ) ;
2014-06-13 18:06:52 -04:00
if ( ( * p ) - > name = = focus ) {
m - > grab_focus ( ) ;
}
2014-06-13 06:01:55 -04:00
a = manage ( new Gtk : : Adjustment ( 0 , 0 , 99999 , 1 ) ) ;
s = manage ( new Gtk : : SpinButton ( * a ) ) ;
a - > set_value ( ( * p ) - > input_latency ) ;
s - > signal_value_changed ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & EngineControl : : midi_latency_adjustment_changed ) , a , * p , true ) ) ;
s - > set_sensitive ( _can_set_midi_latencies & & enabled ) ;
midi_device_table . attach ( * s , 1 , 2 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ; s - > show ( ) ;
a = manage ( new Gtk : : Adjustment ( 0 , 0 , 99999 , 1 ) ) ;
s = manage ( new Gtk : : SpinButton ( * a ) ) ;
a - > set_value ( ( * p ) - > output_latency ) ;
s - > signal_value_changed ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & EngineControl : : midi_latency_adjustment_changed ) , a , * p , false ) ) ;
s - > set_sensitive ( _can_set_midi_latencies & & enabled ) ;
midi_device_table . attach ( * s , 2 , 3 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ; s - > show ( ) ;
b = manage ( new Button ( _ ( " Calibrate " ) ) ) ;
b - > signal_clicked ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & EngineControl : : calibrate_midi_latency ) , * p ) ) ;
b - > set_sensitive ( _can_set_midi_latencies & & enabled ) ;
midi_device_table . attach ( * b , 3 , 4 , row , row + 1 , xopt , AttachOptions ( 0 ) ) ; b - > show ( ) ;
row + + ;
}
}
void
EngineControl : : backend_changed ( )
{
2015-08-10 06:02:25 -04:00
SignalBlocker blocker ( * this , " backend_changed " ) ;
2014-06-13 06:01:55 -04:00
string backend_name = backend_combo . get_active_text ( ) ;
boost : : shared_ptr < ARDOUR : : AudioBackend > backend ;
2015-09-10 11:14:38 -04:00
if ( ! ( backend = ARDOUR : : AudioEngine : : instance ( ) - > set_backend ( backend_name , downcase ( std : : string ( PROGRAM_NAME ) ) , " " ) ) ) {
2014-06-13 06:01:55 -04:00
/* eh? setting the backend failed... how ? */
2015-03-01 10:36:13 -05:00
/* A: stale config contains a backend that does not exist in current build */
2014-06-13 06:01:55 -04:00
return ;
}
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( string_compose ( " Backend name: %1 " , backend_name ) ) ;
2014-06-13 06:01:55 -04:00
_have_control = ARDOUR : : AudioEngine : : instance ( ) - > setup_required ( ) ;
build_notebook ( ) ;
setup_midi_tab_for_backend ( ) ;
_midi_devices . clear ( ) ;
if ( backend - > requires_driver_selection ( ) ) {
2015-08-10 07:28:21 -04:00
if ( set_driver_popdown_strings ( ) ) {
2014-06-13 06:01:55 -04:00
driver_changed ( ) ;
}
} else {
/* this will change the device text which will cause a call to
* device changed which will set up parameters
*/
list_devices ( ) ;
}
2015-08-09 22:49:42 -04:00
update_midi_options ( ) ;
connect_disconnect_button . hide ( ) ;
midi_option_changed ( ) ;
started_at_least_once = false ;
2015-08-11 08:43:00 -04:00
/* changing the backend implies stopping the engine
* ARDOUR : : AudioEngine ( ) may or may not emit this signal
* depending on previous engine state
*/
engine_stopped ( ) ; // set "active/inactive"
2015-10-06 08:40:51 -04:00
if ( ! _have_control ) {
// set settings from backend that we do have control over
2017-08-10 10:49:22 -04:00
set_buffersize_popdown_strings ( ) ;
2015-10-06 08:40:51 -04:00
set_active_text_if_present ( buffer_size_combo , bufsize_as_string ( backend - > buffer_size ( ) ) ) ;
}
2015-11-23 15:44:13 -05:00
if ( _have_control & & ! ignore_changes ) {
// set driver & devices
State state = get_matching_state ( backend_combo . get_active_text ( ) ) ;
if ( state ) {
2017-06-16 16:32:10 -04:00
DEBUG_ECONTROL ( " backend-changed(): found prior state for backend " ) ;
2015-11-23 15:44:13 -05:00
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
set_current_state ( state ) ;
2017-06-16 16:32:10 -04:00
} else {
DEBUG_ECONTROL ( " backend-changed(): no prior state for backend " ) ;
2015-11-23 15:44:13 -05:00
}
2017-06-16 16:32:10 -04:00
} else {
DEBUG_ECONTROL ( string_compose ( " backend-changed(): _have_control=%1 ignore_changes=%2 " , _have_control , ignore_changes ) ) ;
2015-11-23 15:44:13 -05:00
}
2015-08-09 22:49:42 -04:00
if ( ! ignore_changes ) {
maybe_display_saved_state ( ) ;
}
}
void
EngineControl : : update_midi_options ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
2014-06-13 06:01:55 -04:00
vector < string > midi_options = backend - > enumerate_midi_options ( ) ;
if ( midi_options . size ( ) = = 1 ) {
/* only contains the "none" option */
2019-07-25 08:33:08 -04:00
set_popdown_strings ( midi_option_combo , midi_options ) ;
2014-06-13 06:01:55 -04:00
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 ) ;
}
}
}
bool
EngineControl : : print_channel_count ( Gtk : : SpinButton * sb )
{
2015-01-22 15:54:56 -05:00
if ( ARDOUR : : Profile - > get_mixbus ( ) ) {
return true ;
}
2015-10-05 10:17:49 -04:00
2014-06-13 06:01:55 -04:00
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 ;
}
2015-08-10 07:28:21 -04:00
// @return true if there are drivers available
2015-07-29 01:46:26 -04:00
bool
EngineControl : : set_driver_popdown_strings ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " set_driver_popdown_strings " ) ;
2015-08-10 07:28:21 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
vector < string > drivers = backend - > enumerate_drivers ( ) ;
2015-07-29 01:46:26 -04:00
2015-08-10 07:44:29 -04:00
if ( drivers . empty ( ) ) {
2015-08-10 07:28:21 -04:00
// This is an error...?
2015-07-29 01:46:26 -04:00
return false ;
}
2015-08-10 07:44:29 -04:00
string current_driver = backend - > driver_name ( ) ;
2015-08-10 07:28:21 -04:00
DEBUG_ECONTROL ( string_compose ( " backend->driver_name: %1 " , current_driver ) ) ;
2015-08-10 07:44:29 -04:00
if ( std : : find ( drivers . begin ( ) , drivers . end ( ) , current_driver ) = =
drivers . end ( ) ) {
current_driver = drivers . front ( ) ;
2015-08-10 07:28:21 -04:00
}
2015-07-29 01:46:26 -04:00
set_popdown_strings ( driver_combo , drivers ) ;
2015-08-10 07:28:21 -04:00
DEBUG_ECONTROL (
2015-08-10 07:44:29 -04:00
string_compose ( " driver_combo.set_active_text: %1 " , current_driver ) ) ;
2015-08-10 07:28:21 -04:00
driver_combo . set_active_text ( current_driver ) ;
2015-07-29 01:46:26 -04:00
return true ;
}
2015-08-25 10:16:36 -04:00
std : : string
EngineControl : : get_default_device ( const string & current_device_name ,
const vector < string > & available_devices )
{
// If the current device is available, use it as default
if ( std : : find ( available_devices . begin ( ) ,
available_devices . end ( ) ,
current_device_name ) ! = available_devices . end ( ) ) {
return current_device_name ;
}
using namespace ARDOUR ;
string default_device_name =
AudioBackend : : get_standard_device_name ( AudioBackend : : DeviceDefault ) ;
vector < string > : : const_iterator i ;
// If there is a "Default" device available, use it
for ( i = available_devices . begin ( ) ; i ! = available_devices . end ( ) ; + + i ) {
if ( * i = = default_device_name ) {
return * i ;
}
}
string none_device_name =
AudioBackend : : get_standard_device_name ( AudioBackend : : DeviceNone ) ;
// Use the first device that isn't "None"
for ( i = available_devices . begin ( ) ; i ! = available_devices . end ( ) ; + + i ) {
if ( * i ! = none_device_name ) {
return * i ;
}
}
// Use "None" if there are no other available
return available_devices . front ( ) ;
}
2015-05-04 22:59:26 -04:00
// @return true if there are devices available
bool
EngineControl : : set_device_popdown_strings ( )
2014-06-13 06:01:55 -04:00
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " set_device_popdown_strings " ) ;
2014-06-13 06:01:55 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
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 ) ;
}
2015-08-10 07:57:45 -04:00
if ( available_devices . empty ( ) ) {
return false ;
}
2014-06-13 06:01:55 -04:00
2015-08-25 10:16:36 -04:00
set_popdown_strings ( device_combo , available_devices ) ;
2015-02-24 15:29:02 -05:00
2015-08-25 10:16:36 -04:00
std : : string default_device =
get_default_device ( backend - > device_name ( ) , available_devices ) ;
2014-09-09 06:01:09 -04:00
2015-08-10 07:57:45 -04:00
DEBUG_ECONTROL (
2015-08-25 10:16:36 -04:00
string_compose ( " set device_combo active text: %1 " , default_device ) ) ;
2014-09-09 06:01:09 -04:00
2015-08-25 10:16:36 -04:00
device_combo . set_active_text ( default_device ) ;
2015-08-10 07:57:45 -04:00
return true ;
2015-05-04 22:59:26 -04:00
}
// @return true if there are input devices available
bool
EngineControl : : set_input_device_popdown_strings ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " set_input_device_popdown_strings " ) ;
2015-05-04 22:59:26 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
vector < ARDOUR : : AudioBackend : : DeviceStatus > all_devices = backend - > enumerate_input_devices ( ) ;
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 ) ;
}
2015-08-10 07:57:45 -04:00
if ( available_devices . empty ( ) ) {
return false ;
}
2015-05-04 22:59:26 -04:00
2015-08-10 07:57:45 -04:00
set_popdown_strings ( input_device_combo , available_devices ) ;
2015-08-25 10:16:36 -04:00
std : : string default_device =
get_default_device ( backend - > input_device_name ( ) , available_devices ) ;
2015-08-10 07:57:45 -04:00
DEBUG_ECONTROL (
2015-08-25 10:16:36 -04:00
string_compose ( " set input_device_combo active text: %1 " , default_device ) ) ;
input_device_combo . set_active_text ( default_device ) ;
2015-08-10 07:57:45 -04:00
return true ;
2015-05-04 22:59:26 -04:00
}
// @return true if there are output devices available
bool
EngineControl : : set_output_device_popdown_strings ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " set_output_device_popdown_strings " ) ;
2015-05-04 22:59:26 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
vector < ARDOUR : : AudioBackend : : DeviceStatus > all_devices = backend - > enumerate_output_devices ( ) ;
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 ) ;
}
2015-08-10 07:57:45 -04:00
if ( available_devices . empty ( ) ) {
return false ;
}
2015-05-04 22:59:26 -04:00
2015-08-10 07:57:45 -04:00
set_popdown_strings ( output_device_combo , available_devices ) ;
2015-08-25 10:16:36 -04:00
std : : string default_device =
get_default_device ( backend - > output_device_name ( ) , available_devices ) ;
2015-08-10 07:57:45 -04:00
DEBUG_ECONTROL (
2015-08-25 10:16:36 -04:00
string_compose ( " set output_device_combo active text: %1 " , default_device ) ) ;
output_device_combo . set_active_text ( default_device ) ;
2015-08-10 07:57:45 -04:00
return true ;
2015-05-04 22:59:26 -04:00
}
void
EngineControl : : list_devices ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " list_devices " ) ;
2015-05-04 22:59:26 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
2014-06-13 06:01:55 -04:00
2015-05-04 22:59:26 -04:00
/* now fill out devices, mark sample rates, buffer sizes insensitive */
bool devices_available = false ;
if ( backend - > use_separate_input_and_output_devices ( ) ) {
bool input_devices_available = set_input_device_popdown_strings ( ) ;
bool output_devices_available = set_output_device_popdown_strings ( ) ;
devices_available = input_devices_available | | output_devices_available ;
} else {
devices_available = set_device_popdown_strings ( ) ;
}
if ( devices_available ) {
2015-08-09 20:11:33 -04:00
device_changed ( ) ;
2014-06-13 06:01:55 -04:00
} else {
2014-06-14 21:08:40 -04:00
device_combo . clear ( ) ;
2015-05-04 22:59:26 -04:00
input_device_combo . clear ( ) ;
output_device_combo . clear ( ) ;
2014-06-13 06:01:55 -04:00
}
2015-08-11 08:43:00 -04:00
update_sensitivity ( ) ;
2014-06-13 06:01:55 -04:00
}
void
EngineControl : : driver_changed ( )
{
2015-08-10 06:02:25 -04:00
SignalBlocker blocker ( * this , " driver_changed " ) ;
2014-06-13 06:01:55 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
backend - > set_driver ( driver_combo . get_active_text ( ) ) ;
list_devices ( ) ;
2015-11-23 15:44:13 -05:00
// TODO load LRU device(s) for backend + driver combo
2014-06-13 06:01:55 -04:00
if ( ! ignore_changes ) {
maybe_display_saved_state ( ) ;
}
}
2015-08-10 23:02:25 -04:00
vector < float >
EngineControl : : get_sample_rates_for_all_devices ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend =
ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
vector < float > all_rates ;
if ( backend - > use_separate_input_and_output_devices ( ) ) {
2015-08-11 17:47:48 -04:00
all_rates = backend - > available_sample_rates2 ( get_input_device_name ( ) , get_output_device_name ( ) ) ;
2015-08-10 23:02:25 -04:00
} else {
all_rates = backend - > available_sample_rates ( get_device_name ( ) ) ;
}
return all_rates ;
}
2015-08-11 00:13:06 -04:00
vector < float >
EngineControl : : get_default_sample_rates ( )
{
vector < float > rates ;
rates . push_back ( 8000.0f ) ;
rates . push_back ( 16000.0f ) ;
rates . push_back ( 32000.0f ) ;
rates . push_back ( 44100.0f ) ;
rates . push_back ( 48000.0f ) ;
rates . push_back ( 88200.0f ) ;
rates . push_back ( 96000.0f ) ;
rates . push_back ( 192000.0f ) ;
rates . push_back ( 384000.0f ) ;
return rates ;
}
2014-06-13 06:01:55 -04:00
void
2015-08-10 23:02:25 -04:00
EngineControl : : set_samplerate_popdown_strings ( )
2015-05-04 22:59:26 -04:00
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " set_samplerate_popdown_strings " ) ;
2015-05-04 22:59:26 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
string desired ;
vector < float > sr ;
vector < string > s ;
if ( _have_control ) {
2015-08-10 23:02:25 -04:00
sr = get_sample_rates_for_all_devices ( ) ;
2015-05-04 22:59:26 -04:00
} else {
2015-08-11 00:13:06 -04:00
sr = get_default_sample_rates ( ) ;
2015-05-04 22:59:26 -04:00
}
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 ( ) ;
}
}
2015-08-11 08:43:00 -04:00
set_popdown_strings ( sample_rate_combo , s ) ;
2015-05-04 22:59:26 -04:00
2015-08-11 08:43:00 -04:00
if ( ! s . empty ( ) ) {
2016-09-30 10:24:39 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
sample_rate_combo . set_active_text ( rate_as_string ( backend - > sample_rate ( ) ) ) ;
2018-12-05 20:23:09 -05:00
} else if ( ARDOUR_UI : : instance ( ) - > the_session ( ) ) {
2018-11-11 13:51:56 -05:00
float active_sr = ARDOUR_UI : : instance ( ) - > the_session ( ) - > nominal_sample_rate ( ) ;
if ( std : : find ( sr . begin ( ) , sr . end ( ) , active_sr ) = = sr . end ( ) ) {
active_sr = sr . front ( ) ;
}
sample_rate_combo . set_active_text ( rate_as_string ( active_sr ) ) ;
} else if ( desired . empty ( ) ) {
2015-08-10 19:57:38 -04:00
float new_active_sr = backend - > default_sample_rate ( ) ;
if ( std : : find ( sr . begin ( ) , sr . end ( ) , new_active_sr ) = = sr . end ( ) ) {
new_active_sr = sr . front ( ) ;
}
sample_rate_combo . set_active_text ( rate_as_string ( new_active_sr ) ) ;
2015-05-04 22:59:26 -04:00
} else {
sample_rate_combo . set_active_text ( desired ) ;
}
}
2015-08-11 08:43:00 -04:00
update_sensitivity ( ) ;
2015-05-04 22:59:26 -04:00
}
2015-08-10 23:02:25 -04:00
vector < uint32_t >
EngineControl : : get_buffer_sizes_for_all_devices ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend =
ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
vector < uint32_t > all_sizes ;
if ( backend - > use_separate_input_and_output_devices ( ) ) {
2015-08-11 17:47:48 -04:00
all_sizes = backend - > available_buffer_sizes2 ( get_input_device_name ( ) , get_output_device_name ( ) ) ;
2015-08-10 23:02:25 -04:00
} else {
all_sizes = backend - > available_buffer_sizes ( get_device_name ( ) ) ;
}
return all_sizes ;
}
2015-08-11 00:13:06 -04:00
vector < uint32_t >
EngineControl : : get_default_buffer_sizes ( )
{
vector < uint32_t > sizes ;
sizes . push_back ( 8 ) ;
sizes . push_back ( 16 ) ;
sizes . push_back ( 32 ) ;
sizes . push_back ( 64 ) ;
sizes . push_back ( 128 ) ;
sizes . push_back ( 256 ) ;
sizes . push_back ( 512 ) ;
sizes . push_back ( 1024 ) ;
sizes . push_back ( 2048 ) ;
sizes . push_back ( 4096 ) ;
sizes . push_back ( 8192 ) ;
return sizes ;
}
2015-05-04 22:59:26 -04:00
void
2015-08-10 23:02:25 -04:00
EngineControl : : set_buffersize_popdown_strings ( )
2014-06-13 06:01:55 -04:00
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " set_buffersize_popdown_strings " ) ;
2015-05-04 22:59:26 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
vector < uint32_t > bs ;
vector < string > s ;
2014-06-13 06:01:55 -04:00
2015-05-04 22:59:26 -04:00
if ( _have_control ) {
2015-08-10 23:02:25 -04:00
bs = get_buffer_sizes_for_all_devices ( ) ;
2015-05-04 22:59:26 -04:00
} else if ( backend - > can_change_buffer_size_when_running ( ) ) {
2015-08-11 00:13:06 -04:00
bs = get_default_buffer_sizes ( ) ;
2015-05-04 22:59:26 -04:00
}
2015-08-10 19:43:56 -04:00
2015-05-04 22:59:26 -04:00
for ( vector < uint32_t > : : const_iterator x = bs . begin ( ) ; x ! = bs . end ( ) ; + + x ) {
s . push_back ( bufsize_as_string ( * x ) ) ;
}
2017-08-03 21:36:03 -04:00
uint32_t previous_size = backend - > buffer_size ( ) ;
2015-08-24 19:47:50 -04:00
if ( ! buffer_size_combo . get_active_text ( ) . empty ( ) ) {
previous_size = get_buffer_size ( ) ;
}
2015-08-11 08:43:00 -04:00
set_popdown_strings ( buffer_size_combo , s ) ;
2015-08-10 23:02:25 -04:00
2015-05-04 22:59:26 -04:00
if ( ! s . empty ( ) ) {
2015-08-24 19:47:50 -04:00
if ( std : : find ( bs . begin ( ) , bs . end ( ) , previous_size ) ! = bs . end ( ) ) {
buffer_size_combo . set_active_text ( bufsize_as_string ( previous_size ) ) ;
} else {
2015-08-11 08:43:00 -04:00
2015-08-24 19:47:50 -04:00
buffer_size_combo . set_active_text ( s . front ( ) ) ;
uint32_t period = backend - > buffer_size ( ) ;
if ( 0 = = period & & backend - > use_separate_input_and_output_devices ( ) ) {
period = backend - > default_buffer_size ( get_input_device_name ( ) ) ;
}
if ( 0 = = period & & backend - > use_separate_input_and_output_devices ( ) ) {
period = backend - > default_buffer_size ( get_output_device_name ( ) ) ;
}
if ( 0 = = period & & ! backend - > use_separate_input_and_output_devices ( ) ) {
period = backend - > default_buffer_size ( get_device_name ( ) ) ;
}
set_active_text_if_present ( buffer_size_combo , bufsize_as_string ( period ) ) ;
}
2015-05-04 22:59:26 -04:00
show_buffer_duration ( ) ;
}
2015-08-11 08:43:00 -04:00
update_sensitivity ( ) ;
2015-05-04 22:59:26 -04:00
}
2015-12-04 19:32:56 -05:00
void
EngineControl : : set_nperiods_popdown_strings ( )
{
DEBUG_ECONTROL ( " set_nperiods_popdown_strings " ) ;
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
vector < uint32_t > np ;
vector < string > s ;
if ( backend - > can_set_period_size ( ) ) {
np = backend - > available_period_sizes ( get_driver ( ) ) ;
}
for ( vector < uint32_t > : : const_iterator x = np . begin ( ) ; x ! = np . end ( ) ; + + x ) {
2016-09-06 07:56:08 -04:00
s . push_back ( to_string ( * x ) ) ;
2015-12-04 19:32:56 -05:00
}
set_popdown_strings ( nperiods_combo , s ) ;
if ( ! s . empty ( ) ) {
2016-09-06 07:56:08 -04:00
set_active_text_if_present ( nperiods_combo , to_string ( backend - > period_size ( ) ) ) ; // XXX
2015-12-04 19:32:56 -05:00
}
update_sensitivity ( ) ;
}
2015-05-04 22:59:26 -04:00
void
EngineControl : : device_changed ( )
{
2015-08-10 06:02:25 -04:00
SignalBlocker blocker ( * this , " device_changed " ) ;
2014-06-13 06:01:55 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
2015-03-07 05:11:50 -05:00
2015-05-31 16:14:44 -04:00
string device_name_in ;
string device_name_out ; // only used if backend support separate I/O devices
if ( backend - > use_separate_input_and_output_devices ( ) ) {
device_name_in = get_input_device_name ( ) ;
device_name_out = get_output_device_name ( ) ;
} else {
device_name_in = get_device_name ( ) ;
}
/* we set the backend-device to query various device related intormation.
* This has the side effect that backend - > device_name ( ) will match
* the device_name and ' change_device ' will never be true .
* so work around this by setting . . .
*/
if ( backend - > use_separate_input_and_output_devices ( ) ) {
if ( device_name_in ! = backend - > input_device_name ( ) | | device_name_out ! = backend - > output_device_name ( ) ) {
queue_device_changed = true ;
}
} else {
if ( device_name_in ! = backend - > device_name ( ) ) {
queue_device_changed = true ;
}
2015-03-07 05:11:50 -05:00
}
2015-10-05 10:17:49 -04:00
2015-02-06 14:55:00 -05:00
//the device name must be set FIRST so ASIO can populate buffersizes and the control panel button
2015-05-31 16:14:44 -04:00
if ( backend - > use_separate_input_and_output_devices ( ) ) {
backend - > set_input_device_name ( device_name_in ) ;
backend - > set_output_device_name ( device_name_out ) ;
} else {
backend - > set_device_name ( device_name_in ) ;
}
2014-06-13 06:01:55 -04:00
{
/* don't allow programmatic change to combos to cause a
recursive call to this method .
*/
2015-05-31 16:14:44 -04:00
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
2014-06-13 06:01:55 -04:00
2015-08-10 23:02:25 -04:00
set_samplerate_popdown_strings ( ) ;
set_buffersize_popdown_strings ( ) ;
2015-12-04 19:32:56 -05:00
set_nperiods_popdown_strings ( ) ;
2015-08-11 08:43:00 -04:00
/* TODO set min + max channel counts here */
2014-06-13 06:01:55 -04:00
2015-05-04 22:59:26 -04:00
manage_control_app_sensitivity ( ) ;
}
2014-06-13 06:01:55 -04:00
2015-05-04 22:59:26 -04:00
/* pick up any saved state for this device */
2014-06-13 06:01:55 -04:00
2015-05-04 22:59:26 -04:00
if ( ! ignore_changes ) {
maybe_display_saved_state ( ) ;
}
}
2014-06-13 06:01:55 -04:00
2015-05-04 22:59:26 -04:00
void
EngineControl : : input_device_changed ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " input_device_changed " ) ;
2016-11-26 08:31:24 -05:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( backend & & backend - > match_input_output_devices_or_none ( ) ) {
const std : : string & dev_none = ARDOUR : : AudioBackend : : get_standard_device_name ( ARDOUR : : AudioBackend : : DeviceNone ) ;
if ( get_output_device_name ( ) ! = dev_none
& & get_input_device_name ( ) ! = dev_none
& & get_input_device_name ( ) ! = get_output_device_name ( ) ) {
block_changed_signals ( ) ;
if ( contains_value ( output_device_combo , get_input_device_name ( ) ) ) {
output_device_combo . set_active_text ( get_input_device_name ( ) ) ;
} else {
assert ( contains_value ( output_device_combo , dev_none ) ) ;
output_device_combo . set_active_text ( dev_none ) ;
}
unblock_changed_signals ( ) ;
}
}
2015-08-07 20:54:22 -04:00
device_changed ( ) ;
2015-05-04 22:59:26 -04:00
}
void
EngineControl : : output_device_changed ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " output_device_changed " ) ;
2016-11-26 08:31:24 -05:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( backend & & backend - > match_input_output_devices_or_none ( ) ) {
const std : : string & dev_none = ARDOUR : : AudioBackend : : get_standard_device_name ( ARDOUR : : AudioBackend : : DeviceNone ) ;
if ( get_input_device_name ( ) ! = dev_none
& & get_input_device_name ( ) ! = dev_none
& & get_input_device_name ( ) ! = get_output_device_name ( ) ) {
block_changed_signals ( ) ;
if ( contains_value ( input_device_combo , get_output_device_name ( ) ) ) {
input_device_combo . set_active_text ( get_output_device_name ( ) ) ;
} else {
assert ( contains_value ( input_device_combo , dev_none ) ) ;
input_device_combo . set_active_text ( dev_none ) ;
}
unblock_changed_signals ( ) ;
}
}
2015-08-07 20:54:22 -04:00
device_changed ( ) ;
2014-06-13 06:01:55 -04:00
}
string
EngineControl : : bufsize_as_string ( uint32_t sz )
{
2016-09-06 07:39:27 -04:00
return string_compose ( P_ ( " %1 sample " , " %1 samples " , sz ) , to_string ( sz ) ) ;
2014-06-13 06:01:55 -04:00
}
void
EngineControl : : sample_rate_changed ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " sample_rate_changed " ) ;
2014-06-13 06:01:55 -04:00
/* reset the strings for buffer size to show the correct msec value
( reflecting the new sample rate ) .
*/
show_buffer_duration ( ) ;
}
void
EngineControl : : buffer_size_changed ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " buffer_size_changed " ) ;
2017-08-03 21:36:03 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( backend & & backend - > can_change_buffer_size_when_running ( ) ) {
backend - > set_buffer_size ( get_buffer_size ( ) ) ;
}
}
2014-06-13 06:01:55 -04:00
show_buffer_duration ( ) ;
}
2015-12-04 19:32:56 -05:00
void
EngineControl : : nperiods_changed ( )
{
DEBUG_ECONTROL ( " nperiods_changed " ) ;
show_buffer_duration ( ) ;
}
2014-06-13 06:01:55 -04:00
void
EngineControl : : show_buffer_duration ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " show_buffer_duration " ) ;
2014-06-13 06:01:55 -04:00
/* buffer sizes - convert from just samples to samples + msecs for
* the displayed string
*/
string bs_text = buffer_size_combo . get_active_text ( ) ;
uint32_t samples = atoi ( bs_text ) ; /* will ignore trailing text */
uint32_t rate = get_rate ( ) ;
2015-12-04 19:32:56 -05:00
/* Except for ALSA and Dummy backends, we don't know the number of periods
* per cycle and settings .
2015-01-17 16:38:48 -05:00
*
2015-12-04 19:32:56 -05:00
* jack1 vs jack2 have different default latencies since jack2 start
* in async - mode unless - - sync is given which adds an extra cycle
* of latency . The value is not known if jackd is started externally . .
2015-01-17 16:38:48 -05:00
*
* So just display the period size , that ' s also what
* ARDOUR_UI : : update_sample_rate ( ) does for the status bar .
* ( the statusbar calls AudioEngine : : instance ( ) - > usecs_per_cycle ( )
* but still , that ' s the buffer period , not [ round - trip ] latency )
*/
2014-06-13 06:01:55 -04:00
char buf [ 32 ] ;
2015-01-17 16:38:48 -05:00
snprintf ( buf , sizeof ( buf ) , _ ( " (%.1f ms) " ) , ( samples / ( rate / 1000.0f ) ) ) ;
2014-06-13 06:01:55 -04:00
buffer_size_duration_label . set_text ( buf ) ;
}
void
EngineControl : : midi_option_changed ( )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " midi_option_changed " ) ;
2014-06-13 06:01:55 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
backend - > set_midi_option ( get_midi_option ( ) ) ;
vector < ARDOUR : : AudioBackend : : DeviceStatus > midi_devices = backend - > enumerate_midi_devices ( ) ;
_can_set_midi_latencies = backend - > can_set_systemic_midi_latencies ( ) ;
std : : vector < MidiDeviceSettings > new_devices ;
for ( vector < ARDOUR : : AudioBackend : : DeviceStatus > : : const_iterator i = midi_devices . begin ( ) ; i ! = midi_devices . end ( ) ; + + i ) {
MidiDeviceSettings mds = find_midi_device ( i - > name ) ;
if ( i - > available & & ! mds ) {
uint32_t input_latency = 0 ;
uint32_t output_latency = 0 ;
if ( _can_set_midi_latencies ) {
input_latency = backend - > systemic_midi_input_latency ( i - > name ) ;
output_latency = backend - > systemic_midi_output_latency ( i - > name ) ;
}
bool enabled = backend - > midi_device_enabled ( i - > name ) ;
MidiDeviceSettings ptr ( new MidiDeviceSetting ( i - > name , enabled , input_latency , output_latency ) ) ;
new_devices . push_back ( ptr ) ;
} else if ( i - > available ) {
new_devices . push_back ( mds ) ;
}
}
_midi_devices = new_devices ;
if ( _midi_devices . empty ( ) ) {
2019-09-27 07:58:28 -04:00
midi_devices_button . set_sensitive ( false ) ;
2014-06-13 06:01:55 -04:00
} else {
2019-09-27 07:58:28 -04:00
midi_devices_button . set_sensitive ( true ) ;
2014-06-13 06:01:55 -04:00
}
}
void
EngineControl : : parameter_changed ( )
{
}
2015-11-23 15:44:13 -05:00
EngineControl : : State
EngineControl : : get_matching_state ( const string & backend )
{
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
if ( ( * i ) - > backend = = backend ) {
return ( * i ) ;
}
}
return State ( ) ;
}
2014-06-14 22:54:39 -04:00
EngineControl : : State
2014-06-13 06:01:55 -04:00
EngineControl : : get_matching_state (
const string & backend ,
const string & driver ,
const string & device )
{
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
2014-06-14 22:54:39 -04:00
if ( ( * i ) - > backend = = backend & &
2014-06-22 22:26:53 -04:00
( ! _have_control | | ( ( * i ) - > driver = = driver & & ( * i ) - > device = = device ) ) )
{
2014-06-14 22:54:39 -04:00
return ( * i ) ;
2014-06-13 06:01:55 -04:00
}
}
2014-06-14 22:54:39 -04:00
return State ( ) ;
2014-06-13 06:01:55 -04:00
}
2015-05-04 22:59:26 -04:00
EngineControl : : State
EngineControl : : get_matching_state (
const string & backend ,
const string & driver ,
const string & input_device ,
const string & output_device )
{
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
if ( ( * i ) - > backend = = backend & &
( ! _have_control | | ( ( * i ) - > driver = = driver & & ( ( * i ) - > input_device = = input_device ) & & ( * i ) - > output_device = = output_device ) ) )
{
return ( * i ) ;
}
}
return State ( ) ;
}
2014-06-14 22:54:39 -04:00
EngineControl : : State
2014-06-13 06:01:55 -04:00
EngineControl : : get_saved_state_for_currently_displayed_backend_and_device ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( backend ) {
2015-05-04 22:59:26 -04:00
if ( backend - > use_separate_input_and_output_devices ( ) ) {
return get_matching_state ( backend_combo . get_active_text ( ) ,
( backend - > requires_driver_selection ( ) ? ( std : : string ) driver_combo . get_active_text ( ) : string ( ) ) ,
input_device_combo . get_active_text ( ) ,
output_device_combo . get_active_text ( ) ) ;
} else {
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 ( ) ) ;
}
2014-06-13 06:01:55 -04:00
}
return get_matching_state ( backend_combo . get_active_text ( ) ,
string ( ) ,
device_combo . get_active_text ( ) ) ;
}
2015-05-04 22:59:26 -04:00
bool EngineControl : : equivalent_states ( const EngineControl : : State & state1 ,
const EngineControl : : State & state2 )
{
if ( state1 - > backend = = state2 - > backend & &
state1 - > driver = = state2 - > driver & &
state1 - > device = = state2 - > device & &
state1 - > input_device = = state2 - > input_device & &
state1 - > output_device = = state2 - > output_device ) {
return true ;
}
return false ;
}
2017-04-01 09:39:02 -04:00
// sort active first, then most recently used to the beginning of the list
2015-11-23 16:44:13 -05:00
bool
EngineControl : : state_sort_cmp ( const State & a , const State & b ) {
if ( a - > active ) {
return true ;
}
else if ( b - > active ) {
return false ;
}
else {
2017-04-01 09:39:02 -04:00
return a - > lru > b - > lru ;
2015-11-23 16:44:13 -05:00
}
}
2014-06-14 22:54:39 -04:00
EngineControl : : State
2014-06-13 06:01:55 -04:00
EngineControl : : save_state ( )
{
2014-06-22 22:26:53 -04:00
State state ;
2014-06-13 06:01:55 -04:00
if ( ! _have_control ) {
2014-06-22 22:26:53 -04:00
state = get_matching_state ( backend_combo . get_active_text ( ) , string ( ) , string ( ) ) ;
if ( state ) {
2015-11-23 16:44:13 -05:00
state - > lru = time ( NULL ) ;
2014-06-22 22:26:53 -04:00
return state ;
}
state . reset ( new StateStruct ) ;
state - > backend = get_backend ( ) ;
} else {
state . reset ( new StateStruct ) ;
store_state ( state ) ;
2014-06-13 06:01:55 -04:00
}
2014-06-13 11:18:30 -04:00
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; ) {
2015-05-04 22:59:26 -04:00
if ( equivalent_states ( * i , state ) ) {
2014-06-13 11:18:30 -04:00
i = states . erase ( i ) ;
} else {
+ + i ;
}
2014-06-13 06:01:55 -04:00
}
2014-06-14 22:54:39 -04:00
states . push_back ( state ) ;
2014-06-13 11:18:30 -04:00
2015-11-23 16:44:13 -05:00
states . sort ( state_sort_cmp ) ;
2014-06-13 06:01:55 -04:00
return state ;
}
void
2014-06-14 22:54:39 -04:00
EngineControl : : store_state ( State state )
2014-06-13 06:01:55 -04:00
{
2014-06-14 22:54:39 -04:00
state - > backend = get_backend ( ) ;
state - > driver = get_driver ( ) ;
state - > device = get_device_name ( ) ;
2015-05-04 22:59:26 -04:00
state - > input_device = get_input_device_name ( ) ;
state - > output_device = get_output_device_name ( ) ;
2014-06-14 22:54:39 -04:00
state - > sample_rate = get_rate ( ) ;
state - > buffer_size = get_buffer_size ( ) ;
2015-12-04 19:32:56 -05:00
state - > n_periods = get_nperiods ( ) ;
2014-06-14 22:54:39 -04:00
state - > input_latency = get_input_latency ( ) ;
state - > output_latency = get_output_latency ( ) ;
state - > input_channels = get_input_channels ( ) ;
state - > output_channels = get_output_channels ( ) ;
state - > midi_option = get_midi_option ( ) ;
state - > midi_devices = _midi_devices ;
2016-02-05 08:32:59 -05:00
state - > use_buffered_io = get_use_buffered_io ( ) ;
2015-11-23 16:44:13 -05:00
state - > lru = time ( NULL ) ;
2014-06-13 06:01:55 -04:00
}
void
EngineControl : : maybe_display_saved_state ( )
{
2017-08-03 21:36:03 -04:00
if ( ! _have_control | | ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
2014-06-13 06:01:55 -04:00
return ;
}
2014-06-14 22:54:39 -04:00
State state = get_saved_state_for_currently_displayed_backend_and_device ( ) ;
2014-06-13 06:01:55 -04:00
if ( state ) {
2015-08-25 08:56:27 -04:00
DEBUG_ECONTROL ( " Restoring saved state " ) ;
2014-06-13 06:01:55 -04:00
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
2018-11-11 12:50:01 -05:00
if ( 0 = = _desired_sample_rate & & sample_rate_combo . get_sensitive ( ) ) {
2014-06-13 06:01:55 -04:00
sample_rate_combo . set_active_text ( rate_as_string ( state - > sample_rate ) ) ;
}
2015-03-16 10:09:16 -04:00
set_active_text_if_present ( buffer_size_combo , bufsize_as_string ( state - > buffer_size ) ) ;
2015-12-04 19:32:56 -05:00
2016-09-06 07:56:08 -04:00
set_active_text_if_present ( nperiods_combo , to_string ( state - > n_periods ) ) ;
2014-06-13 06:01:55 -04:00
/* 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 ) ;
2016-02-05 08:32:59 -05:00
use_buffered_io_button . set_active ( state - > use_buffered_io ) ;
2014-06-13 06:01:55 -04:00
if ( ! state - > midi_option . empty ( ) ) {
midi_option_combo . set_active_text ( state - > midi_option ) ;
_midi_devices = state - > midi_devices ;
2019-05-05 19:29:18 -04:00
midi_option_changed ( ) ;
2014-06-13 06:01:55 -04:00
}
2015-08-25 08:56:27 -04:00
} else {
DEBUG_ECONTROL ( " Unable to find saved state for backend and devices " ) ;
2014-06-13 06:01:55 -04:00
}
}
XMLNode &
EngineControl : : get_state ( )
{
2016-05-07 06:19:41 -04:00
LocaleGuard lg ;
2015-07-08 05:34:30 -04:00
2014-06-13 06:01:55 -04:00
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 " ) ;
2016-08-26 21:14:54 -04:00
node - > set_property ( " backend " , ( * i ) - > backend ) ;
node - > set_property ( " driver " , ( * i ) - > driver ) ;
node - > set_property ( " device " , ( * i ) - > device ) ;
node - > set_property ( " input-device " , ( * i ) - > input_device ) ;
node - > set_property ( " output-device " , ( * i ) - > output_device ) ;
node - > set_property ( " sample-rate " , ( * i ) - > sample_rate ) ;
node - > set_property ( " buffer-size " , ( * i ) - > buffer_size ) ;
node - > set_property ( " n-periods " , ( * i ) - > n_periods ) ;
node - > set_property ( " input-latency " , ( * i ) - > input_latency ) ;
node - > set_property ( " output-latency " , ( * i ) - > output_latency ) ;
node - > set_property ( " input-channels " , ( * i ) - > input_channels ) ;
node - > set_property ( " output-channels " , ( * i ) - > output_channels ) ;
node - > set_property ( " active " , ( * i ) - > active ) ;
node - > set_property ( " use-buffered-io " , ( * i ) - > use_buffered_io ) ;
node - > set_property ( " midi-option " , ( * i ) - > midi_option ) ;
int32_t lru_val = ( * i ) - > active ? time ( NULL ) : ( * i ) - > lru ;
node - > set_property ( " lru " , lru_val ) ;
2014-06-13 06:01:55 -04:00
XMLNode * midi_devices = new XMLNode ( " MIDIDevices " ) ;
2014-06-14 22:54:39 -04:00
for ( std : : vector < MidiDeviceSettings > : : const_iterator p = ( * i ) - > midi_devices . begin ( ) ; p ! = ( * i ) - > midi_devices . end ( ) ; + + p ) {
2014-06-13 06:01:55 -04:00
XMLNode * midi_device_stuff = new XMLNode ( " MIDIDevice " ) ;
2016-08-26 21:14:54 -04:00
midi_device_stuff - > set_property ( X_ ( " name " ) , ( * p ) - > name ) ;
midi_device_stuff - > set_property ( X_ ( " enabled " ) , ( * p ) - > enabled ) ;
midi_device_stuff - > set_property ( X_ ( " input-latency " ) , ( * p ) - > input_latency ) ;
midi_device_stuff - > set_property ( X_ ( " output-latency " ) , ( * p ) - > output_latency ) ;
2014-06-13 06:01:55 -04:00
midi_devices - > add_child_nocopy ( * midi_device_stuff ) ;
}
node - > add_child_nocopy ( * midi_devices ) ;
state_nodes - > add_child_nocopy ( * node ) ;
}
root - > add_child_nocopy ( * state_nodes ) ;
}
return * root ;
}
void
2015-08-10 09:20:07 -04:00
EngineControl : : set_default_state ( )
{
vector < string > backend_names ;
vector < const ARDOUR : : AudioBackendInfo * > backends = ARDOUR : : AudioEngine : : instance ( ) - > available_backends ( ) ;
for ( vector < const ARDOUR : : AudioBackendInfo * > : : const_iterator b = backends . begin ( ) ; b ! = backends . end ( ) ; + + b ) {
backend_names . push_back ( ( * b ) - > name ) ;
}
backend_combo . set_active_text ( backend_names . front ( ) ) ;
// We could set default backends per platform etc here
backend_changed ( ) ;
}
bool
2014-06-13 06:01:55 -04:00
EngineControl : : set_state ( const XMLNode & root )
{
XMLNodeList clist , cclist ;
XMLNodeConstIterator citer , cciter ;
2016-05-04 23:09:37 -04:00
XMLNode const * child ;
XMLNode const * grandchild ;
2014-06-13 06:01:55 -04:00
if ( root . name ( ) ! = " AudioMIDISetup " ) {
2015-08-10 09:20:07 -04:00
return false ;
2014-06-13 06:01:55 -04:00
}
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 ) {
2014-06-14 22:54:39 -04:00
State state ( new StateStruct ) ;
2014-06-13 06:01:55 -04:00
grandchild = * cciter ;
if ( grandchild - > name ( ) ! = " State " ) {
continue ;
}
2016-08-26 21:14:54 -04:00
if ( ! grandchild - > get_property ( " backend " , state - > backend ) ) {
2014-06-13 06:01:55 -04:00
continue ;
}
2016-08-26 21:14:54 -04:00
// If any of the required properties are not found in the state node
// then continue/skip to the next engine state
if ( ! grandchild - > get_property ( " driver " , state - > driver ) | |
! grandchild - > get_property ( " device " , state - > device ) | |
! grandchild - > get_property ( " input-device " , state - > input_device ) | |
! grandchild - > get_property ( " output-device " , state - > output_device ) | |
! grandchild - > get_property ( " sample-rate " , state - > sample_rate ) | |
! grandchild - > get_property ( " buffer-size " , state - > buffer_size ) | |
! grandchild - > get_property ( " input-latency " , state - > input_latency ) | |
! grandchild - > get_property ( " output-latency " , state - > output_latency ) | |
! grandchild - > get_property ( " input-channels " , state - > input_channels ) | |
! grandchild - > get_property ( " output-channels " , state - > output_channels ) | |
! grandchild - > get_property ( " active " , state - > active ) | |
! grandchild - > get_property ( " use-buffered-io " , state - > use_buffered_io ) | |
! grandchild - > get_property ( " midi-option " , state - > midi_option ) ) {
2014-06-13 06:01:55 -04:00
continue ;
}
2016-08-26 21:14:54 -04:00
if ( ! grandchild - > get_property ( " n-periods " , state - > n_periods ) ) {
2015-12-04 19:32:56 -05:00
// optional (new value in 4.5)
state - > n_periods = 0 ;
2014-06-13 06:01:55 -04:00
}
2014-06-14 22:54:39 -04:00
state - > midi_devices . clear ( ) ;
2014-06-13 06:01:55 -04:00
XMLNode * midinode ;
2014-06-25 15:03:47 -04:00
if ( ( midinode = ARDOUR : : find_named_node ( * grandchild , " MIDIDevices " ) ) ! = 0 ) {
2014-06-13 06:01:55 -04:00
const XMLNodeList mnc = midinode - > children ( ) ;
for ( XMLNodeList : : const_iterator n = mnc . begin ( ) ; n ! = mnc . end ( ) ; + + n ) {
2016-08-26 21:14:54 -04:00
std : : string name ;
bool enabled ;
uint32_t input_latency ;
uint32_t output_latency ;
if ( ! ( * n ) - > get_property ( X_ ( " name " ) , name ) | |
! ( * n ) - > get_property ( X_ ( " enabled " ) , enabled ) | |
! ( * n ) - > get_property ( X_ ( " input-latency " ) , input_latency ) | |
! ( * n ) - > get_property ( X_ ( " output-latency " ) , output_latency ) ) {
2014-06-13 06:01:55 -04:00
continue ;
}
2016-08-26 21:14:54 -04:00
MidiDeviceSettings ptr (
new MidiDeviceSetting ( name , enabled , input_latency , output_latency ) ) ;
2014-06-14 22:54:39 -04:00
state - > midi_devices . push_back ( ptr ) ;
2014-06-13 06:01:55 -04:00
}
}
2016-08-26 21:14:54 -04:00
int32_t lru_val ;
if ( grandchild - > get_property ( " lru " , lru_val ) ) {
state - > lru = lru_val ;
2015-11-23 16:44:13 -05:00
}
2014-06-13 06:01:55 -04:00
states . push_back ( state ) ;
}
}
/* now see if there was an active state and switch the setup to it */
2017-06-16 16:32:10 -04:00
/* purge states of backend that are not available in this built */
2014-07-04 09:50:34 -04:00
vector < const ARDOUR : : AudioBackendInfo * > backends = ARDOUR : : AudioEngine : : instance ( ) - > available_backends ( ) ;
vector < std : : string > backend_names ;
for ( vector < const ARDOUR : : AudioBackendInfo * > : : const_iterator i = backends . begin ( ) ; i ! = backends . end ( ) ; + + i ) {
backend_names . push_back ( ( * i ) - > name ) ;
}
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; ) {
if ( std : : find ( backend_names . begin ( ) , backend_names . end ( ) , ( * i ) - > backend ) = = backend_names . end ( ) ) {
i = states . erase ( i ) ;
} else {
+ + i ;
}
}
2015-11-23 16:44:13 -05:00
states . sort ( state_sort_cmp ) ;
2017-06-16 16:32:10 -04:00
/* purge old states referring to the same backend */
const time_t now = time ( NULL ) ;
for ( vector < std : : string > : : const_iterator bi = backend_names . begin ( ) ; bi ! = backend_names . end ( ) ; + + bi ) {
bool first = true ;
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; ) {
if ( ( * i ) - > backend ! = * bi ) {
+ + i ; continue ;
}
// keep at latest one for every audio-system
if ( first ) {
first = false ;
+ + i ; continue ;
}
// also keep states used in the last 90 days.
if ( ( now - ( * i ) - > lru ) < 86400 * 90 ) {
+ + i ; continue ;
}
assert ( ! ( * i ) - > active ) ;
i = states . erase ( i ) ;
}
}
2014-06-13 06:01:55 -04:00
for ( StateList : : const_iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
2014-06-14 22:54:39 -04:00
if ( ( * i ) - > active ) {
2015-08-10 09:20:07 -04:00
return set_current_state ( * i ) ;
2014-06-13 06:01:55 -04:00
}
}
2015-08-10 09:20:07 -04:00
return false ;
2014-06-13 06:01:55 -04:00
}
2015-08-10 09:20:07 -04:00
bool
2015-08-08 19:39:01 -04:00
EngineControl : : set_current_state ( const State & state )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " set_current_state " ) ;
2015-08-10 09:20:07 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend ;
2019-10-24 19:36:25 -04:00
if ( ! ( backend = ARDOUR : : AudioEngine : : instance ( ) - > set_backend ( state - > backend , downcase ( std : : string ( PROGRAM_NAME ) ) , " " ) ) ) {
2015-08-10 09:20:07 -04:00
DEBUG_ECONTROL ( string_compose ( " Unable to set backend to %1 " , state - > backend ) ) ;
// this shouldn't happen as the invalid backend names should have been
// removed from the list of states.
return false ;
}
// now reflect the change in the backend in the GUI so backend_changed will
// do the right thing
2015-08-08 19:39:01 -04:00
backend_combo . set_active_text ( state - > backend ) ;
2015-08-10 09:20:07 -04:00
2015-10-06 08:40:51 -04:00
if ( ! ARDOUR : : AudioEngine : : instance ( ) - > setup_required ( ) ) {
backend_changed ( ) ;
// we don't have control don't restore state
return true ;
}
2015-08-10 09:20:07 -04:00
if ( ! state - > driver . empty ( ) ) {
if ( ! backend - > requires_driver_selection ( ) ) {
DEBUG_ECONTROL ( " Backend should require driver selection " ) ;
// A backend has changed from having driver selection to not having
// it or someone has been manually editing a config file and messed
// it up
return false ;
}
if ( backend - > set_driver ( state - > driver ) ! = 0 ) {
DEBUG_ECONTROL ( string_compose ( " Unable to set driver %1 " , state - > driver ) ) ;
// Driver names for a backend have changed and the name in the
// config file is now invalid or support for driver is no longer
// included in the backend
return false ;
}
// no need to set the driver_combo as backend_changed will use
// backend->driver_name to set the active driver
}
if ( ! state - > device . empty ( ) ) {
if ( backend - > set_device_name ( state - > device ) ! = 0 ) {
DEBUG_ECONTROL (
string_compose ( " Unable to set device name %1 " , state - > device ) ) ;
// device is no longer available on the system
return false ;
}
// no need to set active device as it will be picked up in
// via backend_changed ()/set_device_popdown_strings
} else {
// backend supports separate input/output devices
if ( backend - > set_input_device_name ( state - > input_device ) ! = 0 ) {
DEBUG_ECONTROL ( string_compose ( " Unable to set input device name %1 " ,
state - > input_device ) ) ;
// input device is no longer available on the system
return false ;
}
if ( backend - > set_output_device_name ( state - > output_device ) ! = 0 ) {
DEBUG_ECONTROL ( string_compose ( " Unable to set output device name %1 " ,
state - > input_device ) ) ;
// output device is no longer available on the system
return false ;
}
// no need to set active devices as it will be picked up in via
// backend_changed ()/set_*_device_popdown_strings
}
2015-08-08 19:39:01 -04:00
backend_changed ( ) ;
2015-08-10 09:20:07 -04:00
// Now restore the state of the rest of the controls
// We don't use a SignalBlocker as set_current_state is currently only
// called from set_state before any signals are connected. If at some point
// a more general named state mechanism is implemented and
// set_current_state is called while signals are connected then a
// SignalBlocker will need to be instantiated before setting these.
2015-08-08 19:39:01 -04:00
device_combo . set_active_text ( state - > device ) ;
input_device_combo . set_active_text ( state - > input_device ) ;
output_device_combo . set_active_text ( state - > output_device ) ;
2018-11-11 12:50:01 -05:00
if ( 0 = = _desired_sample_rate & & sample_rate_combo . get_sensitive ( ) ) {
2016-07-23 16:07:21 -04:00
sample_rate_combo . set_active_text ( rate_as_string ( state - > sample_rate ) ) ;
}
2015-08-08 19:39:01 -04:00
set_active_text_if_present ( buffer_size_combo , bufsize_as_string ( state - > buffer_size ) ) ;
2016-09-06 07:56:08 -04:00
set_active_text_if_present ( nperiods_combo , to_string ( state - > n_periods ) ) ;
2015-08-08 19:39:01 -04:00
input_latency . set_value ( state - > input_latency ) ;
output_latency . set_value ( state - > output_latency ) ;
midi_option_combo . set_active_text ( state - > midi_option ) ;
2016-02-05 08:32:59 -05:00
use_buffered_io_button . set_active ( state - > use_buffered_io ) ;
2015-08-10 09:20:07 -04:00
return true ;
2015-08-08 19:39:01 -04:00
}
2014-06-13 06:01:55 -04:00
int
EngineControl : : push_state_to_backend ( bool start )
{
2015-08-10 00:30:04 -04:00
DEBUG_ECONTROL ( " push_state_to_backend " ) ;
2014-06-13 06:01:55 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
2016-01-28 19:12:32 -05:00
PBD : : Unwinder < uint32_t > protect_ignore_device_changes ( ignore_device_changes , ignore_device_changes + 1 ) ;
2014-06-13 06:01:55 -04:00
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 ;
2015-12-04 19:32:56 -05:00
bool change_nperiods = false ;
2014-06-13 06:01:55 -04:00
bool change_latency = false ;
bool change_channels = false ;
bool change_midi = false ;
2016-02-05 08:32:59 -05:00
bool change_buffered_io = false ;
2014-06-13 06:01:55 -04:00
uint32_t ochan = get_output_channels ( ) ;
uint32_t ichan = get_input_channels ( ) ;
if ( _have_control ) {
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( started_at_least_once ) {
2013-10-10 11:24:16 -04:00
2014-06-13 06:01:55 -04:00
/* we can control the backend */
2013-10-10 11:24:16 -04:00
2014-06-13 06:01:55 -04:00
if ( backend - > requires_driver_selection ( ) ) {
if ( get_driver ( ) ! = backend - > driver_name ( ) ) {
change_driver = true ;
}
}
2013-09-19 15:03:20 -04:00
2015-05-04 22:59:26 -04:00
if ( backend - > use_separate_input_and_output_devices ( ) ) {
if ( get_input_device_name ( ) ! = backend - > input_device_name ( ) ) {
change_device = true ;
}
if ( get_output_device_name ( ) ! = backend - > output_device_name ( ) ) {
change_device = true ;
}
} else {
if ( get_device_name ( ) ! = backend - > device_name ( ) ) {
change_device = true ;
}
}
if ( queue_device_changed ) {
2014-06-13 06:01:55 -04:00
change_device = true ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( get_rate ( ) ! = backend - > sample_rate ( ) ) {
change_rate = true ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( get_buffer_size ( ) ! = backend - > buffer_size ( ) ) {
change_bufsize = true ;
}
2013-09-19 15:03:20 -04:00
2015-12-05 07:55:37 -05:00
if ( backend - > can_set_period_size ( ) & & get_popdown_string_count ( nperiods_combo ) > 0
& & get_nperiods ( ) ! = backend - > period_size ( ) ) {
2015-12-04 19:32:56 -05:00
change_nperiods = true ;
}
2014-06-13 06:01:55 -04:00
if ( get_midi_option ( ) ! = backend - > midi_option ( ) ) {
change_midi = true ;
}
2013-09-19 15:03:20 -04:00
2016-02-05 08:32:59 -05:00
if ( backend - > can_use_buffered_io ( ) ) {
if ( get_use_buffered_io ( ) ! = backend - > get_use_buffered_io ( ) ) {
change_buffered_io = true ;
}
}
2014-06-13 06:01:55 -04:00
/* zero-requested channels means "all available" */
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( ichan = = 0 ) {
ichan = backend - > input_channels ( ) ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( ochan = = 0 ) {
ochan = backend - > output_channels ( ) ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( ichan ! = backend - > input_channels ( ) ) {
change_channels = true ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( ochan ! = backend - > output_channels ( ) ) {
change_channels = true ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( get_input_latency ( ) ! = backend - > systemic_input_latency ( ) | |
get_output_latency ( ) ! = backend - > systemic_output_latency ( ) ) {
change_latency = true ;
}
} else {
/* backend never started, so we have to force a group
of settings .
*/
change_device = true ;
if ( backend - > requires_driver_selection ( ) ) {
change_driver = true ;
}
change_rate = true ;
change_bufsize = true ;
change_channels = true ;
change_latency = true ;
change_midi = true ;
2016-05-21 09:54:52 -04:00
change_buffered_io = backend - > can_use_buffered_io ( ) ;
change_channels = true ;
2015-12-05 07:55:37 -05:00
change_nperiods = backend - > can_set_period_size ( ) & & get_popdown_string_count ( nperiods_combo ) > 0 ;
2014-06-13 06:01:55 -04:00
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
} else {
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
/* we have no control over the backend, meaning that we can
* only possibly change sample rate and buffer size .
*/
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( get_rate ( ) ! = backend - > sample_rate ( ) ) {
change_bufsize = true ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( get_buffer_size ( ) ! = backend - > buffer_size ( ) ) {
change_bufsize = true ;
}
}
2013-09-19 15:03:20 -04:00
2015-03-07 05:11:50 -05:00
queue_device_changed = false ;
2014-06-13 06:01:55 -04:00
if ( ! _have_control ) {
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
/* 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 .
*/
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( change_rate & & ! backend - > can_change_sample_rate_when_running ( ) ) {
return 1 ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( change_bufsize & & ! backend - > can_change_buffer_size_when_running ( ) ) {
return 1 ;
}
2013-10-12 14:57:32 -04:00
2014-06-13 06:01:55 -04:00
if ( change_rate ) {
backend - > set_sample_rate ( get_rate ( ) ) ;
}
2013-10-12 14:57:32 -04:00
2014-06-13 06:01:55 -04:00
if ( change_bufsize ) {
backend - > set_buffer_size ( get_buffer_size ( ) ) ;
}
if ( start ) {
if ( ARDOUR : : AudioEngine : : instance ( ) - > start ( ) ) {
error < < string_compose ( _ ( " Could not start backend engine %1 " ) , backend - > name ( ) ) < < endmsg ;
return - 1 ;
}
}
post_push ( ) ;
return 0 ;
2013-10-12 14:57:32 -04:00
}
2014-06-13 06:01:55 -04:00
/* determine if we need to stop the backend before changing parameters */
2015-12-04 19:32:56 -05:00
if ( change_driver | | change_device | | change_channels | | change_nperiods | |
2015-12-04 11:34:46 -05:00
( change_latency & & ! backend - > can_change_systemic_latency_when_running ( ) ) | |
2014-06-13 06:01:55 -04:00
( change_rate & & ! backend - > can_change_sample_rate_when_running ( ) ) | |
2016-05-21 09:54:52 -04:00
change_midi | | change_buffered_io | |
2014-06-13 06:01:55 -04:00
( change_bufsize & & ! backend - > can_change_buffer_size_when_running ( ) ) ) {
restart_required = true ;
} else {
restart_required = false ;
2013-10-12 14:57:32 -04:00
}
2015-12-04 19:32:56 -05:00
2014-06-13 06:01:55 -04:00
if ( was_running ) {
if ( restart_required ) {
2015-10-03 00:09:45 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > stop ( ) ) {
2014-06-13 06:01:55 -04:00
return - 1 ;
}
}
}
2013-10-12 14:57:32 -04:00
2014-06-13 06:01:55 -04:00
if ( change_driver & & backend - > set_driver ( get_driver ( ) ) ) {
error < < string_compose ( _ ( " Cannot set driver to %1 " ) , get_driver ( ) ) < < endmsg ;
return - 1 ;
}
2015-05-04 22:59:26 -04:00
if ( backend - > use_separate_input_and_output_devices ( ) ) {
if ( change_device & & backend - > set_input_device_name ( get_input_device_name ( ) ) ) {
error < < string_compose ( _ ( " Cannot set input device name to %1 " ) , get_input_device_name ( ) ) < < endmsg ;
return - 1 ;
}
if ( change_device & & backend - > set_output_device_name ( get_output_device_name ( ) ) ) {
error < < string_compose ( _ ( " Cannot set output device name to %1 " ) , get_output_device_name ( ) ) < < endmsg ;
return - 1 ;
}
} else {
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 ;
}
2014-06-13 06:01:55 -04:00
}
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 ;
}
2015-12-04 19:32:56 -05:00
if ( change_nperiods & & backend - > set_peridod_size ( get_nperiods ( ) ) ) {
error < < string_compose ( _ ( " Cannot set periods to %1 " ) , get_nperiods ( ) ) < < endmsg ;
return - 1 ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
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 ;
}
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( change_midi ) {
backend - > set_midi_option ( get_midi_option ( ) ) ;
}
2013-09-19 15:03:20 -04:00
2016-02-05 08:32:59 -05:00
if ( change_buffered_io ) {
backend - > set_use_buffered_io ( use_buffered_io_button . get_active ( ) ) ;
}
2014-06-13 06:01:55 -04:00
if ( 1 /* TODO */ ) {
for ( vector < MidiDeviceSettings > : : const_iterator p = _midi_devices . begin ( ) ; p ! = _midi_devices . end ( ) ; + + p ) {
if ( _measure_midi ) {
2019-05-05 18:13:47 -04:00
/* Disable other MIDI devices while measuring.
* This is a hack to only show ports from the selected device */
2014-06-13 06:01:55 -04:00
if ( * p = = _measure_midi ) {
backend - > set_midi_device_enabled ( ( * p ) - > name , true ) ;
} else {
backend - > set_midi_device_enabled ( ( * p ) - > name , false ) ;
}
continue ;
}
backend - > set_midi_device_enabled ( ( * p ) - > name , ( * p ) - > enabled ) ;
if ( backend - > can_set_systemic_midi_latencies ( ) ) {
backend - > set_systemic_midi_input_latency ( ( * p ) - > name , ( * p ) - > input_latency ) ;
backend - > set_systemic_midi_output_latency ( ( * p ) - > name , ( * p ) - > output_latency ) ;
}
}
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( start | | ( was_running & & restart_required ) ) {
2015-10-02 21:40:34 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > start ( ) ) {
2014-06-13 06:01:55 -04:00
return - 1 ;
}
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
post_push ( ) ;
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
return 0 ;
}
2013-09-09 13:17:53 -04:00
2014-06-13 06:01:55 -04:00
void
EngineControl : : post_push ( )
{
/* get a pointer to the current state object, creating one if
* necessary
*/
2013-09-09 13:17:53 -04:00
2014-06-22 22:26:53 -04:00
State state = get_saved_state_for_currently_displayed_backend_and_device ( ) ;
2014-06-13 06:01:55 -04:00
2014-06-22 22:26:53 -04:00
if ( ! state ) {
state = save_state ( ) ;
assert ( state ) ;
2015-03-21 20:28:33 -04:00
} else {
store_state ( state ) ;
2014-06-22 22:26:53 -04:00
}
2014-06-13 06:01:55 -04:00
2015-11-23 16:44:13 -05:00
states . sort ( state_sort_cmp ) ;
2014-06-22 22:26:53 -04:00
/* all off */
2014-06-13 06:01:55 -04:00
2014-06-22 22:26:53 -04:00
for ( StateList : : iterator i = states . begin ( ) ; i ! = states . end ( ) ; + + i ) {
( * i ) - > active = false ;
}
2014-06-13 06:01:55 -04:00
2014-06-22 22:26:53 -04:00
/* mark this one active (to be used next time the dialog is
* shown )
*/
2014-06-13 06:01:55 -04:00
2014-06-22 22:26:53 -04:00
state - > active = true ;
2014-06-13 06:01:55 -04:00
2014-06-22 22:26:53 -04:00
if ( _have_control ) { // XXX
2014-06-13 06:01:55 -04:00
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 .
2013-09-19 15:03:20 -04:00
*/
2014-06-13 06:01:55 -04:00
if ( r < 1000.0 ) {
r * = 1000.0 ;
}
return r ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
uint32_t
EngineControl : : get_buffer_size ( ) const
{
string txt = buffer_size_combo . get_active_text ( ) ;
uint32_t samples ;
2013-09-09 15:17:29 -04:00
2014-06-13 06:01:55 -04:00
if ( sscanf ( txt . c_str ( ) , " %d " , & samples ) ! = 1 ) {
2015-03-16 10:09:16 -04:00
fprintf ( stderr , " Find a trout and repeatedly slap the nearest C++ who throws exceptions without catching them. \n " ) ;
fprintf ( stderr , " Ardour will likely crash now, giving you time to get the trout. \n " ) ;
2014-06-13 06:01:55 -04:00
throw exception ( ) ;
}
2013-09-09 13:17:53 -04:00
2014-06-13 06:01:55 -04:00
return samples ;
}
2013-09-09 13:17:53 -04:00
2015-12-04 19:32:56 -05:00
uint32_t
EngineControl : : get_nperiods ( ) const
{
string txt = nperiods_combo . get_active_text ( ) ;
return atoi ( txt . c_str ( ) ) ;
}
2014-06-13 06:01:55 -04:00
string
EngineControl : : get_midi_option ( ) const
{
return midi_option_combo . get_active_text ( ) ;
}
2013-10-12 14:57:32 -04:00
2016-02-05 08:32:59 -05:00
bool
EngineControl : : get_use_buffered_io ( ) const
{
return use_buffered_io_button . get_active ( ) ;
}
2014-06-13 06:01:55 -04:00
uint32_t
EngineControl : : get_input_channels ( ) const
{
2015-01-22 15:54:56 -05:00
if ( ARDOUR : : Profile - > get_mixbus ( ) ) {
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) return 0 ;
return backend - > input_channels ( ) ;
}
2014-06-13 06:01:55 -04:00
return ( uint32_t ) input_channels_adjustment . get_value ( ) ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
uint32_t
EngineControl : : get_output_channels ( ) const
{
2015-01-22 15:54:56 -05:00
if ( ARDOUR : : Profile - > get_mixbus ( ) ) {
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) return 0 ;
return backend - > input_channels ( ) ;
}
2014-06-13 06:01:55 -04:00
return ( uint32_t ) output_channels_adjustment . get_value ( ) ;
}
2013-09-09 21:23:12 -04:00
2014-06-13 06:01:55 -04:00
uint32_t
EngineControl : : get_input_latency ( ) const
{
return ( uint32_t ) input_latency_adjustment . get_value ( ) ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
uint32_t
EngineControl : : get_output_latency ( ) const
{
return ( uint32_t ) output_latency_adjustment . get_value ( ) ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
string
EngineControl : : get_backend ( ) const
{
return backend_combo . get_active_text ( ) ;
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
string
EngineControl : : get_driver ( ) const
{
2015-08-12 10:19:01 -04:00
if ( driver_combo . get_parent ( ) ) {
2014-06-13 11:18:30 -04:00
return driver_combo . get_active_text ( ) ;
} else {
return " " ;
}
2014-06-13 06:01:55 -04:00
}
string
EngineControl : : get_device_name ( ) const
{
return device_combo . get_active_text ( ) ;
}
2015-05-04 22:59:26 -04:00
string
EngineControl : : get_input_device_name ( ) const
{
return input_device_combo . get_active_text ( ) ;
}
string
EngineControl : : get_output_device_name ( ) const
{
return output_device_combo . get_active_text ( ) ;
}
2014-06-13 06:01:55 -04:00
void
EngineControl : : control_app_button_clicked ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
return ;
2014-06-01 15:43:03 -04:00
}
2014-06-13 06:01:55 -04:00
backend - > launch_control_app ( ) ;
}
2013-09-06 21:00:01 -04:00
2019-10-10 18:50:57 -04:00
void
2019-10-11 15:53:48 -04:00
EngineControl : : on_response ( int r )
2019-10-10 18:50:57 -04:00
{
2019-10-29 20:20:55 -04:00
/* Do not run ArdourDialog::on_response() which will hide us. Leave
* that to whoever invoked us , if they wish to hide us after " start " .
*
* StartupFSM does hide us after response ( ) ; Window > Audio / MIDI Setup
* does not .
2019-10-10 18:50:57 -04:00
*/
2019-10-29 20:20:55 -04:00
pop_splash ( ) ;
Gtk : : Dialog : : on_response ( r ) ;
2019-10-10 18:50:57 -04:00
}
2015-08-11 09:34:07 -04:00
void
2015-08-25 07:42:11 -04:00
EngineControl : : start_stop_button_clicked ( )
2015-08-11 09:34:07 -04:00
{
2015-08-25 07:42:11 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
return ;
}
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
ARDOUR : : AudioEngine : : instance ( ) - > stop ( ) ;
} else {
2019-10-10 18:50:57 -04:00
/* whoever displayed this dialog is expected to do its own
check on whether or not the engine is running .
*/
2015-10-02 21:40:34 -04:00
start_engine ( ) ;
2015-08-25 07:42:11 -04:00
}
2019-10-10 18:50:57 -04:00
response ( RESPONSE_OK ) ;
2015-08-11 09:34:07 -04:00
}
2015-08-25 08:57:44 -04:00
void
EngineControl : : update_devices_button_clicked ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
return ;
}
if ( backend - > update_devices ( ) ) {
device_list_changed ( ) ;
}
}
2019-09-26 15:12:37 -04:00
void
EngineControl : : try_autostart_button_clicked ( )
{
ARDOUR : : Config - > set_try_autostart_engine ( ! try_autostart_button . get_active ( ) ) ;
try_autostart_button . set_active ( ARDOUR : : Config - > get_try_autostart_engine ( ) ) ;
}
2016-02-05 08:32:59 -05:00
void
EngineControl : : use_buffered_io_button_clicked ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( ! backend ) {
return ;
}
bool set_buffered_io = ! use_buffered_io_button . get_active ( ) ;
use_buffered_io_button . set_active ( set_buffered_io ) ;
backend - > set_use_buffered_io ( set_buffered_io ) ;
}
2014-06-13 06:01:55 -04:00
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 ;
2016-04-18 11:37:14 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( )
& & ARDOUR : : AudioEngine : : instance ( ) - > sample_rate ( ) ! = sr ) {
2016-04-18 09:18:36 -04:00
stop_engine ( ) ;
}
2014-06-13 06:01:55 -04:00
device_changed ( ) ;
}
2013-09-04 15:45:54 -04:00
2014-06-13 06:01:55 -04:00
void
EngineControl : : on_switch_page ( GtkNotebookPage * , guint page_num )
{
if ( page_num = = 0 ) {
_measure_midi . reset ( ) ;
2015-08-11 08:43:00 -04:00
update_sensitivity ( ) ;
2014-06-13 06:01:55 -04:00
}
2013-09-19 15:03:20 -04:00
2014-06-13 06:01:55 -04:00
if ( page_num = = midi_tab ) {
/* MIDI tab */
refresh_midi_display ( ) ;
2019-05-05 18:13:47 -04:00
/* undo special case from push_state_to_backend() when measuring midi latency */
if ( _measure_midi & & ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
if ( backend - > can_change_systemic_latency_when_running ( ) ) {
for ( vector < MidiDeviceSettings > : : const_iterator p = _midi_devices . begin ( ) ; p ! = _midi_devices . end ( ) ; + + p ) {
backend - > set_midi_device_enabled ( ( * p ) - > name , ( * p ) - > enabled ) ;
}
}
}
_measure_midi . reset ( ) ;
2014-06-13 06:01:55 -04:00
}
2013-09-09 21:23:12 -04:00
2014-06-13 06:01:55 -04:00
if ( page_num = = latency_tab ) {
/* latency tab */
2013-09-04 22:58:56 -04:00
2014-06-13 06:01:55 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
2015-12-04 11:34:46 -05:00
stop_engine ( true ) ;
2014-06-13 06:01:55 -04:00
}
2013-09-04 22:58:56 -04:00
2014-06-13 06:01:55 -04:00
{
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ;
2013-09-04 22:58:56 -04:00
2014-06-13 06:01:55 -04:00
/* save any existing latency values */
2013-09-17 21:09:13 -04:00
2014-06-13 06:01:55 -04:00
uint32_t il = ( uint32_t ) input_latency . get_value ( ) ;
uint32_t ol = ( uint32_t ) input_latency . get_value ( ) ;
2013-09-10 22:58:33 -04:00
2014-06-13 06:01:55 -04:00
/* reset to zero so that our new test instance
will be clean of any existing latency measures .
2013-09-12 16:28:51 -04:00
2014-06-13 06:01:55 -04:00
NB . this should really be done by the backend
when stated for latency measurement .
*/
2013-09-12 16:28:51 -04:00
2014-06-13 06:01:55 -04:00
input_latency . set_value ( 0 ) ;
output_latency . set_value ( 0 ) ;
2014-06-01 15:43:48 -04:00
2014-06-13 06:01:55 -04:00
push_state_to_backend ( false ) ;
2013-09-12 16:28:51 -04:00
2014-06-13 06:01:55 -04:00
/* reset control */
2013-09-17 10:01:24 -04:00
2014-06-13 06:01:55 -04:00
input_latency . set_value ( il ) ;
output_latency . set_value ( ol ) ;
2013-09-12 16:28:51 -04:00
2014-06-13 06:01:55 -04:00
}
// This should be done in push_state_to_backend()
if ( ARDOUR : : AudioEngine : : instance ( ) - > prepare_for_latency_measurement ( ) ) {
disable_latency_tab ( ) ;
}
2013-09-16 15:21:32 -04:00
2014-06-13 06:01:55 -04:00
enable_latency_tab ( ) ;
2013-09-16 15:21:32 -04:00
2014-06-13 06:01:55 -04:00
} else {
if ( lm_running ) {
2014-06-15 06:59:27 -04:00
end_latency_detection ( ) ;
2014-06-13 06:01:55 -04:00
}
}
}
2013-09-10 22:58:33 -04:00
2014-06-13 06:01:55 -04:00
/* latency measurement */
2013-09-12 16:28:51 -04:00
2014-06-08 08:48:10 -04:00
bool
EngineControl : : check_audio_latency_measurement ( )
{
MTDM * mtdm = ARDOUR : : AudioEngine : : instance ( ) - > mtdm ( ) ;
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -04:00
if ( mtdm - > resolve ( ) < 0 ) {
lm_results . set_markup ( string_compose ( results_markup , _ ( " No signal detected " ) ) ) ;
return true ;
2016-01-14 13:25:23 -05:00
}
if ( mtdm - > get_peak ( ) > 0.707f ) {
// get_peak() resets the peak-hold in the detector.
// this GUI callback is at 10Hz and so will be fine (test-signal is at higher freq)
lm_results . set_markup ( string_compose ( results_markup , _ ( " Input signal is > -3dBFS. Lower the signal level (output gain, input gain) on the audio-interface. " ) ) ) ;
return true ;
2014-06-08 08:48:10 -04:00
}
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -04:00
if ( mtdm - > err ( ) > 0.3 ) {
mtdm - > invert ( ) ;
mtdm - > resolve ( ) ;
}
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -04:00
char buf [ 256 ] ;
2017-09-18 12:39:17 -04:00
ARDOUR : : samplecnt_t const sample_rate = ARDOUR : : AudioEngine : : instance ( ) - > sample_rate ( ) ;
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -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
2017-09-18 12:39:17 -04:00
int samples_total = mtdm - > del ( ) ;
int extra = samples_total - ARDOUR : : AudioEngine : : instance ( ) - > latency_signal_delay ( ) ;
2013-09-11 13:02:32 -04:00
2014-06-08 08:48:10 -04:00
snprintf ( buf , sizeof ( buf ) , " %s%d samples (%.3lf ms) \n %s%d samples (%.3lf ms) " ,
_ ( " Detected roundtrip latency: " ) ,
2017-09-18 12:39:17 -04:00
samples_total , samples_total * 1000.0f / sample_rate ,
2014-06-08 08:48:10 -04:00
_ ( " Systemic latency: " ) ,
extra , extra * 1000.0f / sample_rate ) ;
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -04:00
bool solid = true ;
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -04:00
if ( mtdm - > err ( ) > 0.2 ) {
strcat ( buf , " " ) ;
strcat ( buf , _ ( " (signal detection error) " ) ) ;
solid = false ;
}
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -04:00
if ( mtdm - > inv ( ) ) {
strcat ( buf , " " ) ;
strcat ( buf , _ ( " (inverted - bad wiring) " ) ) ;
solid = false ;
}
2013-09-10 22:58:33 -04:00
2015-01-25 04:18:33 -05:00
lm_results . set_markup ( string_compose ( results_markup , buf ) ) ;
2014-06-08 08:48:10 -04:00
if ( solid ) {
2014-06-19 13:42:59 -04:00
have_lm_results = true ;
2014-06-08 08:48:10 -04:00
end_latency_detection ( ) ;
lm_use_button . set_sensitive ( true ) ;
2014-06-19 13:42:59 -04:00
return false ;
2014-06-08 08:48:10 -04:00
}
return true ;
}
bool
EngineControl : : check_midi_latency_measurement ( )
{
ARDOUR : : MIDIDM * mididm = ARDOUR : : AudioEngine : : instance ( ) - > mididm ( ) ;
if ( ! mididm - > have_signal ( ) | | mididm - > latency ( ) = = 0 ) {
lm_results . set_markup ( string_compose ( results_markup , _ ( " No signal detected " ) ) ) ;
return true ;
}
char buf [ 256 ] ;
2017-09-18 12:39:17 -04:00
ARDOUR : : samplecnt_t const sample_rate = ARDOUR : : AudioEngine : : instance ( ) - > sample_rate ( ) ;
2014-06-08 08:48:10 -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 ;
}
2017-09-18 12:39:17 -04:00
ARDOUR : : samplecnt_t samples_total = mididm - > latency ( ) ;
ARDOUR : : samplecnt_t extra = samples_total - ARDOUR : : AudioEngine : : instance ( ) - > latency_signal_delay ( ) ;
2014-06-08 08:48:10 -04:00
snprintf ( buf , sizeof ( buf ) , " %s% " PRId64 " samples (%.1lf ms) dev: %.2f[spl] \n %s% " PRId64 " samples (%.1lf ms) " ,
_ ( " Detected roundtrip latency: " ) ,
2017-09-18 12:39:17 -04:00
samples_total , samples_total * 1000.0f / sample_rate , mididm - > deviation ( ) ,
2014-06-08 08:48:10 -04:00
_ ( " Systemic latency: " ) ,
extra , extra * 1000.0f / sample_rate ) ;
bool solid = true ;
if ( ! mididm - > ok ( ) ) {
strcat ( buf , " " ) ;
strcat ( buf , _ ( " (averaging) " ) ) ;
solid = false ;
}
if ( mididm - > deviation ( ) > 50.0 ) {
strcat ( buf , " " ) ;
strcat ( buf , _ ( " (too large jitter) " ) ) ;
solid = false ;
} else if ( mididm - > deviation ( ) > 10.0 ) {
strcat ( buf , " " ) ;
strcat ( buf , _ ( " (large jitter) " ) ) ;
}
2013-09-10 22:58:33 -04:00
2014-06-08 08:48:10 -04:00
if ( solid ) {
2014-06-19 13:42:59 -04:00
have_lm_results = true ;
2014-06-08 08:48:10 -04:00
end_latency_detection ( ) ;
2014-06-13 06:01:55 -04:00
lm_use_button . set_sensitive ( true ) ;
2015-01-25 04:18:33 -05:00
lm_results . set_markup ( string_compose ( results_markup , buf ) ) ;
2014-06-16 13:44:23 -04:00
return false ;
} else if ( mididm - > processed ( ) > 400 ) {
have_lm_results = false ;
end_latency_detection ( ) ;
lm_results . set_markup ( string_compose ( results_markup , _ ( " Timeout - large MIDI jitter. " ) ) ) ;
return false ;
2014-06-08 08:48:10 -04:00
}
lm_results . set_markup ( string_compose ( results_markup , buf ) ) ;
return true ;
2013-09-10 22:58:33 -04:00
}
2013-09-16 18:47:30 -04:00
void
EngineControl : : start_latency_detection ( )
{
2019-05-05 12:15:18 -04:00
ARDOUR : : AudioEngine : : instance ( ) - > set_latency_input_port ( lm_input_channel_combo . get_active ( ) - > get_value ( lm_input_channel_cols . port_name ) ) ;
ARDOUR : : AudioEngine : : instance ( ) - > set_latency_output_port ( lm_output_channel_combo . get_active ( ) - > get_value ( lm_output_channel_cols . port_name ) ) ;
2013-10-12 10:04:20 -04:00
2014-06-13 06:01:55 -04:00
if ( ARDOUR : : AudioEngine : : instance ( ) - > start_latency_detection ( _measure_midi ? true : false ) = = 0 ) {
2013-10-12 14:57:32 -04:00
lm_results . set_markup ( string_compose ( results_markup , _ ( " Detecting ... " ) ) ) ;
2014-06-08 08:48:10 -04:00
if ( _measure_midi ) {
latency_timeout = Glib : : signal_timeout ( ) . connect ( mem_fun ( * this , & EngineControl : : check_midi_latency_measurement ) , 100 ) ;
} else {
latency_timeout = Glib : : signal_timeout ( ) . connect ( mem_fun ( * this , & EngineControl : : check_audio_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_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 ( ) ;
2014-06-08 08:48:10 -04:00
}
2013-09-10 22:58:33 -04:00
}
2013-09-11 13:02:32 -04:00
2015-10-03 01:49:55 -04:00
void
EngineControl : : latency_back_button_clicked ( )
{
2017-04-27 13:45:56 -04:00
ARDOUR : : AudioEngine : : instance ( ) - > stop_latency_detection ( ) ;
2015-10-03 01:49:55 -04:00
notebook . set_current_page ( 0 ) ;
}
2013-09-11 13:02:32 -04:00
void
EngineControl : : use_latency_button_clicked ( )
{
2017-04-27 15:10:10 -04:00
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
2014-06-08 08:48:10 -04:00
if ( _measure_midi ) {
2014-06-08 11:19:10 -04:00
ARDOUR : : MIDIDM * mididm = ARDOUR : : AudioEngine : : instance ( ) - > mididm ( ) ;
if ( ! mididm ) {
return ;
}
2017-09-18 12:39:17 -04:00
ARDOUR : : samplecnt_t samples_total = mididm - > latency ( ) ;
ARDOUR : : samplecnt_t extra = samples_total - ARDOUR : : AudioEngine : : instance ( ) - > latency_signal_delay ( ) ;
uint32_t one_way = max ( ( ARDOUR : : samplecnt_t ) 0 , extra / 2 ) ;
2014-06-13 06:01:55 -04:00
_measure_midi - > input_latency = one_way ;
_measure_midi - > output_latency = one_way ;
2017-04-27 15:10:10 -04:00
if ( backend - > can_change_systemic_latency_when_running ( ) ) {
backend - > set_systemic_midi_input_latency ( _measure_midi - > name , one_way ) ;
backend - > set_systemic_midi_output_latency ( _measure_midi - > name , one_way ) ;
}
2014-06-13 06:01:55 -04:00
notebook . set_current_page ( midi_tab ) ;
2014-06-08 11:19:10 -04:00
} else {
2014-06-08 08:48:10 -04:00
MTDM * mtdm = ARDOUR : : AudioEngine : : instance ( ) - > mtdm ( ) ;
2013-09-11 13:02:32 -04:00
2014-06-08 08:48:10 -04:00
if ( ! mtdm ) {
return ;
}
2013-09-11 13:02:32 -04:00
2014-06-13 06:01:55 -04:00
double one_way = rint ( ( mtdm - > del ( ) - ARDOUR : : AudioEngine : : instance ( ) - > latency_signal_delay ( ) ) / 2.0 ) ;
one_way = std : : max ( 0. , one_way ) ;
2013-09-11 13:02:32 -04:00
2014-06-08 08:48:10 -04:00
input_latency_adjustment . set_value ( one_way ) ;
output_latency_adjustment . set_value ( one_way ) ;
2017-04-27 15:10:10 -04:00
if ( backend - > can_change_systemic_latency_when_running ( ) ) {
backend - > set_systemic_input_latency ( one_way ) ;
backend - > set_systemic_output_latency ( one_way ) ;
}
2013-10-12 14:57:32 -04:00
2014-06-13 06:01:55 -04:00
/* back to settings page */
notebook . set_current_page ( 0 ) ;
}
2019-09-22 23:45:30 -04:00
}
2013-09-16 18:47:30 -04:00
bool
EngineControl : : on_delete_event ( GdkEventAny * ev )
{
2019-09-22 23:45:30 -04:00
if ( lm_running | | notebook . get_current_page ( ) = = 2 ) {
/* currently measuring latency - be sure to clean up */
2013-09-16 18:47:30 -04:00
end_latency_detection ( ) ;
}
2019-09-22 23:45:30 -04:00
2013-09-16 18:47:30 -04:00
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 ) ;
2015-03-16 10:09:16 -04:00
set_active_text_if_present ( buffer_size_combo , bufsize_as_string ( backend - > buffer_size ( ) ) ) ;
2013-09-19 15:03:20 -04:00
sample_rate_combo . set_active_text ( rate_as_string ( backend - > sample_rate ( ) ) ) ;
2015-12-04 19:32:56 -05:00
if ( backend - > can_set_period_size ( ) ) {
2016-09-06 07:56:08 -04:00
set_active_text_if_present ( nperiods_combo , to_string ( backend - > period_size ( ) ) ) ;
2015-12-04 19:32:56 -05:00
}
2013-09-19 15:03:20 -04:00
connect_disconnect_button . set_label ( string_compose ( _ ( " Disconnect from %1 " ) , backend - > name ( ) ) ) ;
2015-01-17 15:02:00 -05:00
connect_disconnect_button . show ( ) ;
2013-09-19 15:03:20 -04:00
started_at_least_once = true ;
2015-08-11 13:44:14 -04:00
if ( _have_control ) {
engine_status . set_markup ( string_compose ( " <span foreground= \" green \" >%1</span> " , _ ( " Running " ) ) ) ;
} else {
engine_status . set_markup ( string_compose ( " <span foreground= \" green \" >%1</span> " , _ ( " Connected " ) ) ) ;
}
2015-08-11 08:43:00 -04:00
update_sensitivity ( ) ;
2013-09-19 15:03:20 -04:00
}
void
EngineControl : : engine_stopped ( )
{
boost : : shared_ptr < ARDOUR : : AudioBackend > backend = ARDOUR : : AudioEngine : : instance ( ) - > current_backend ( ) ;
assert ( backend ) ;
connect_disconnect_button . set_label ( string_compose ( _ ( " Connect to %1 " ) , backend - > name ( ) ) ) ;
2015-01-17 15:02:00 -05:00
connect_disconnect_button . show ( ) ;
2013-09-19 15:03:20 -04:00
2015-08-25 07:42:11 -04:00
if ( _have_control ) {
engine_status . set_markup ( string_compose ( " <span foreground= \" red \" >%1</span> " , _ ( " Stopped " ) ) ) ;
} else {
engine_status . set_markup ( X_ ( " " ) ) ;
}
2015-08-11 08:43:00 -04:00
update_sensitivity ( ) ;
2013-09-19 15:03:20 -04:00
}
2014-06-13 06:01:55 -04:00
2015-03-06 00:24:44 -05:00
void
EngineControl : : device_list_changed ( )
{
2016-01-28 19:12:32 -05:00
if ( ignore_device_changes ) {
return ;
}
2015-03-21 20:28:33 -04:00
PBD : : Unwinder < uint32_t > protect_ignore_changes ( ignore_changes , ignore_changes + 1 ) ; // ??
2018-12-23 13:51:17 -05:00
if ( ! ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
list_devices ( ) ;
}
2018-12-23 15:51:09 -05:00
2015-03-07 03:00:18 -05:00
midi_option_changed ( ) ;
2018-12-23 15:51:09 -05:00
if ( notebook . get_current_page ( ) = = midi_tab ) {
if ( _midi_devices . empty ( ) ) {
notebook . set_current_page ( 0 ) ;
} else {
refresh_midi_display ( ) ;
}
}
2015-03-06 00:24:44 -05:00
}
2013-09-19 15:03:20 -04:00
void
2014-06-13 06:01:55 -04:00
EngineControl : : connect_disconnect_click ( )
2013-09-19 15:03:20 -04:00
{
if ( ARDOUR : : AudioEngine : : instance ( ) - > running ( ) ) {
2015-10-03 00:09:45 -04:00
stop_engine ( ) ;
2013-09-19 15:03:20 -04:00
} else {
2018-12-05 20:23:09 -05:00
if ( ! ARDOUR_UI : : instance ( ) - > the_session ( ) ) {
2017-04-20 17:16:09 -04:00
pop_splash ( ) ;
2016-11-30 08:44:36 -05:00
hide ( ) ;
2017-04-20 17:15:13 -04:00
ARDOUR : : GUIIdle ( ) ;
2016-11-30 08:44:36 -05:00
}
2015-10-03 00:09:45 -04:00
start_engine ( ) ;
2018-12-05 20:23:09 -05:00
if ( ! ARDOUR_UI : : instance ( ) - > the_session ( ) ) {
2019-10-08 23:30:00 -04:00
ArdourDialog : : response ( RESPONSE_OK ) ;
2016-11-30 08:44:36 -05:00
}
2013-09-19 15:03:20 -04:00
}
}
2013-10-15 13:15:03 -04:00
void
2014-06-08 08:48:10 -04:00
EngineControl : : calibrate_audio_latency ( )
{
2014-06-15 06:59:27 -04:00
_measure_midi . reset ( ) ;
have_lm_results = false ;
lm_use_button . set_sensitive ( false ) ;
lm_results . set_markup ( string_compose ( results_markup , _ ( " No measurement results yet " ) ) ) ;
2014-06-08 08:48:10 -04:00
notebook . set_current_page ( latency_tab ) ;
}
void
2014-06-13 06:01:55 -04:00
EngineControl : : calibrate_midi_latency ( MidiDeviceSettings s )
2013-10-15 13:15:03 -04:00
{
2014-06-13 06:01:55 -04:00
_measure_midi = s ;
2014-06-15 06:59:27 -04:00
have_lm_results = false ;
lm_use_button . set_sensitive ( false ) ;
lm_results . set_markup ( string_compose ( results_markup , _ ( " No measurement results yet " ) ) ) ;
2013-10-15 13:15:03 -04:00
notebook . set_current_page ( latency_tab ) ;
}
2014-06-13 06:01:55 -04:00
void
EngineControl : : configure_midi_devices ( )
{
notebook . set_current_page ( midi_tab ) ;
}