2 * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
3 * Copyright (C) 2005-2017 Tim Mayberry <mojofunk@gmail.com>
4 * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
6 * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
7 * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
8 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
9 * Copyright (C) 2008-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11 * Copyright (C) 2013-2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
12 * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
13 * Copyright (C) 2013-2016 Nick Mainsbridge <mainsbridge@gmail.com>
14 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
15 * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
16 * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net>
17 * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include "gtk2ardour-config.h"
36 #include "gtk2ardour-version.h"
46 #ifndef PLATFORM_WINDOWS
47 #include <sys/resource.h>
51 #include <sys/types.h>
52 #include <sys/sysctl.h>
62 #include "pbd/gstdio_compat.h"
64 #include <gtkmm/accelmap.h>
65 #include <gtkmm/messagedialog.h>
66 #include <gtkmm/stock.h>
67 #include <gtkmm/uimanager.h>
69 #include "pbd/error.h"
70 #include "pbd/basename.h"
71 #include "pbd/compose.h"
72 #include "pbd/convert.h"
73 #include "pbd/failed_constructor.h"
74 #include "pbd/file_archive.h"
75 #include "pbd/enumwriter.h"
76 #include "pbd/memento_command.h"
77 #include "pbd/openuri.h"
78 #include "pbd/stl_delete.h"
79 #include "pbd/types_convert.h"
80 #include "pbd/unwind.h"
81 #include "pbd/file_utils.h"
82 #include "pbd/localtime_r.h"
83 #include "pbd/pthread_utils.h"
84 #include "pbd/replace_all.h"
85 #include "pbd/scoped_file_descriptor.h"
86 #include "pbd/xml++.h"
88 #include "gtkmm2ext/application.h"
89 #include "gtkmm2ext/bindings.h"
90 #include "gtkmm2ext/gtk_ui.h"
91 #include "gtkmm2ext/utils.h"
92 #include "gtkmm2ext/window_title.h"
94 #include "widgets/fastmeter.h"
95 #include "widgets/prompter.h"
96 #include "widgets/tooltips.h"
98 #include "ardour/ardour.h"
99 #include "ardour/audio_backend.h"
100 #include "ardour/audio_track.h"
101 #include "ardour/audioengine.h"
102 #include "ardour/audiofilesource.h"
103 #include "ardour/automation_watch.h"
104 #include "ardour/disk_reader.h"
105 #include "ardour/disk_writer.h"
106 #include "ardour/filename_extensions.h"
107 #include "ardour/filesystem_paths.h"
108 #include "ardour/ltc_file_reader.h"
109 #include "ardour/monitor_control.h"
110 #include "ardour/midi_track.h"
111 #include "ardour/port.h"
112 #include "ardour/plugin_manager.h"
113 #include "ardour/process_thread.h"
114 #include "ardour/profile.h"
115 #include "ardour/recent_sessions.h"
116 #include "ardour/record_enable_control.h"
117 #include "ardour/revision.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_route.h"
120 #include "ardour/session_state_utils.h"
121 #include "ardour/session_utils.h"
122 #include "ardour/source_factory.h"
123 #include "ardour/transport_master.h"
124 #include "ardour/transport_master_manager.h"
125 #include "ardour/system_exec.h"
126 #include "ardour/track.h"
127 #include "ardour/vca_manager.h"
128 #include "ardour/utils.h"
130 #include "LuaBridge/LuaBridge.h"
132 #ifdef WINDOWS_VST_SUPPORT
135 #ifdef AUDIOUNIT_SUPPORT
136 #include "ardour/audio_unit.h"
139 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
144 #include "temporal/time.h"
146 typedef uint64_t microseconds_t;
150 #include "enums_convert.h"
152 #include "add_route_dialog.h"
153 #include "ambiguous_file_dialog.h"
154 #include "ardour_ui.h"
155 #include "audio_clock.h"
156 #include "audio_region_view.h"
157 #include "big_clock_window.h"
158 #include "big_transport_window.h"
159 #include "bundle_manager.h"
160 #include "duplicate_routes_dialog.h"
162 #include "engine_dialog.h"
163 #include "export_video_dialog.h"
164 #include "export_video_infobox.h"
165 #include "gain_meter.h"
166 #include "global_port_matrix.h"
167 #include "gui_object.h"
168 #include "gui_thread.h"
169 #include "idleometer.h"
170 #include "keyboard.h"
171 #include "keyeditor.h"
172 #include "location_ui.h"
173 #include "lua_script_manager.h"
174 #include "luawindow.h"
175 #include "main_clock.h"
176 #include "missing_file_dialog.h"
177 #include "missing_plugin_dialog.h"
178 #include "mixer_ui.h"
179 #include "meterbridge.h"
180 #include "meter_patterns.h"
181 #include "mouse_cursors.h"
184 #include "pingback.h"
185 #include "plugin_dspload_window.h"
186 #include "processor_box.h"
187 #include "public_editor.h"
188 #include "rc_option_editor.h"
189 #include "route_time_axis.h"
190 #include "route_params_ui.h"
191 #include "save_as_dialog.h"
192 #include "save_template_dialog.h"
193 #include "script_selector.h"
194 #include "session_archive_dialog.h"
195 #include "session_dialog.h"
196 #include "session_metadata_dialog.h"
197 #include "session_option_editor.h"
198 #include "speaker_dialog.h"
201 #include "template_dialog.h"
202 #include "time_axis_view_item.h"
203 #include "time_info_box.h"
205 #include "transport_masters_dialog.h"
207 #include "utils_videotl.h"
208 #include "video_server_dialog.h"
209 #include "add_video_dialog.h"
210 #include "transcode_video_dialog.h"
212 #include "pbd/i18n.h"
214 using namespace ARDOUR;
215 using namespace ARDOUR_UI_UTILS;
217 using namespace Gtkmm2ext;
218 using namespace ArdourWidgets;
221 using namespace Editing;
223 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
225 sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
226 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
229 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
231 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
232 "Would you like these files to be copied and used for %1 %2.x?\n\n"
233 "(This will require you to restart %1.)"),
234 PROGRAM_NAME, PROGRAM_VERSION, version),
235 false, /* no markup */
238 true /* modal, though it hardly matters since it is the only window */
241 msg.set_default_response (Gtk::RESPONSE_YES);
244 return (msg.run() == Gtk::RESPONSE_YES);
248 libxml_generic_error_func (void* /* parsing_context*/,
256 vsnprintf (buf, sizeof (buf), msg, ap);
257 error << buf << endmsg;
262 libxml_structured_error_func (void* /* parsing_context*/,
270 replace_all (msg, "\n", "");
273 if (err->file && err->line) {
274 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
277 error << ':' << err->int2;
282 error << X_("XML error: ") << msg << endmsg;
288 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
289 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
290 , session_load_in_progress (false)
291 , gui_object_state (new GUIObjectState)
292 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
293 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
294 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
296 , ignore_dual_punch (false)
297 , main_window_visibility (0)
302 , _mixer_on_top (false)
303 , _initial_verbose_plugin_scan (false)
304 , _shared_popup_menu (0)
305 , secondary_clock_spacer (0)
306 , auto_input_button (ArdourButton::led_default_elements)
308 , auto_return_button (ArdourButton::led_default_elements)
309 , follow_edits_button (ArdourButton::led_default_elements)
310 , auditioning_alert_button (_("Audition"))
311 , solo_alert_button (_("Solo"))
312 , feedback_alert_button (_("Feedback"))
313 , error_alert_button ( ArdourButton::just_led_default_elements )
314 , editor_meter_peak_display()
316 , _numpad_locate_happening (false)
317 , _session_is_new (false)
318 , last_key_press_time (0)
322 , rc_option_editor (0)
323 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
324 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
325 , about (X_("about"), _("About"))
326 , location_ui (X_("locations"), S_("Ranges|Locations"))
327 , route_params (X_("inspector"), _("Tracks and Busses"))
328 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
329 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
330 , lua_script_window (X_("script-manager"), _("Script Manager"))
331 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
332 , plugin_dsp_load_window (X_("plugin-dsp-load"), _("Plugin DSP Load"))
333 , transport_masters_window (X_("transport-masters"), _("Transport Masters"))
334 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
335 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
336 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
337 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
338 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
339 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
340 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
341 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
342 , video_server_process (0)
344 , have_configure_timeout (false)
345 , last_configure_time (0)
347 , have_disk_speed_dialog_displayed (false)
348 , _status_bar_visibility (X_("status-bar"))
349 , _feedback_exists (false)
350 , _log_not_acknowledged (LogLevelNone)
351 , duplicate_routes_dialog (0)
352 , editor_visibility_button (S_("Window|Editor"))
353 , mixer_visibility_button (S_("Window|Mixer"))
354 , prefs_visibility_button (S_("Window|Preferences"))
356 Gtkmm2ext::init (localedir);
358 UIConfiguration::instance().post_gui_init ();
360 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
362 /* "touch" the been-here-before path now that config has been migrated */
363 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
365 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
367 /* configuration was modified, exit immediately */
368 _exit (EXIT_SUCCESS);
372 if (string (VERSIONSTRING).find (".pre") != string::npos) {
373 /* check this is not being run from ./ardev etc. */
374 if (!running_from_source_tree ()) {
375 pre_release_dialog ();
379 if (theArdourUI == 0) {
383 /* track main window visibility */
385 main_window_visibility = new VisibilityTracker (_main_window);
387 /* stop libxml from spewing to stdout/stderr */
389 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
390 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
392 /* Set this up early */
394 ActionManager::init ();
396 /* we like keyboards */
398 keyboard = new ArdourKeyboard(*this);
400 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
402 keyboard->set_state (*node, Stateful::loading_state_version);
405 /* actions do not need to be defined when we load keybindings. They
406 * will be lazily discovered. But bindings do need to exist when we
407 * create windows/tabs with their own binding sets.
410 keyboard->setup_keybindings ();
412 if ((global_bindings = Bindings::get_bindings (X_("Global"))) == 0) {
413 error << _("Global keybindings are missing") << endmsg;
418 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
419 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
420 UIConfiguration::instance().map_parameters (pc);
422 transport_ctrl.setup (this);
424 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
425 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
427 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
429 /* handle dialog requests */
431 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
433 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
435 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
437 /* handle Audio/MIDI setup when session requires it */
439 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
441 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
443 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
445 /* handle sr mismatch with a dialog - cross-thread from engine */
446 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
448 /* handle requests to quit (coming from JACK session) */
450 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
452 /* tell the user about feedback */
454 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
455 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
457 /* handle requests to deal with missing files */
459 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
461 /* and ambiguous files */
463 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
465 /* also plugin scan messages */
466 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
467 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
469 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
471 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
474 theme_changed.connect (sigc::mem_fun(*this, &ARDOUR_UI::on_theme_changed));
475 UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::on_theme_changed));
476 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::on_theme_changed));
478 /* lets get this party started */
480 setup_gtk_ardour_enums ();
483 SessionEvent::create_per_thread_pool ("GUI", 4096);
485 UIConfiguration::instance().reset_dpi ();
487 TimeAxisViewItem::set_constant_heights ();
489 /* The following must happen after ARDOUR::init() so that Config is set up */
491 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
494 key_editor.set_state (*ui_xml, 0);
495 session_option_editor.set_state (*ui_xml, 0);
496 speaker_config_window.set_state (*ui_xml, 0);
497 about.set_state (*ui_xml, 0);
498 add_route_dialog.set_state (*ui_xml, 0);
499 add_video_dialog.set_state (*ui_xml, 0);
500 route_params.set_state (*ui_xml, 0);
501 bundle_manager.set_state (*ui_xml, 0);
502 location_ui.set_state (*ui_xml, 0);
503 big_clock_window.set_state (*ui_xml, 0);
504 big_transport_window.set_state (*ui_xml, 0);
505 audio_port_matrix.set_state (*ui_xml, 0);
506 midi_port_matrix.set_state (*ui_xml, 0);
507 export_video_dialog.set_state (*ui_xml, 0);
508 lua_script_window.set_state (*ui_xml, 0);
509 idleometer.set_state (*ui_xml, 0);
510 plugin_dsp_load_window.set_state (*ui_xml, 0);
511 transport_masters_window.set_state (*ui_xml, 0);
514 /* Separate windows */
516 WM::Manager::instance().register_window (&key_editor);
517 WM::Manager::instance().register_window (&session_option_editor);
518 WM::Manager::instance().register_window (&speaker_config_window);
519 WM::Manager::instance().register_window (&about);
520 WM::Manager::instance().register_window (&add_route_dialog);
521 WM::Manager::instance().register_window (&add_video_dialog);
522 WM::Manager::instance().register_window (&route_params);
523 WM::Manager::instance().register_window (&audio_midi_setup);
524 WM::Manager::instance().register_window (&export_video_dialog);
525 WM::Manager::instance().register_window (&lua_script_window);
526 WM::Manager::instance().register_window (&bundle_manager);
527 WM::Manager::instance().register_window (&location_ui);
528 WM::Manager::instance().register_window (&big_clock_window);
529 WM::Manager::instance().register_window (&big_transport_window);
530 WM::Manager::instance().register_window (&audio_port_matrix);
531 WM::Manager::instance().register_window (&midi_port_matrix);
532 WM::Manager::instance().register_window (&idleometer);
533 WM::Manager::instance().register_window (&plugin_dsp_load_window);
534 WM::Manager::instance().register_window (&transport_masters_window);
536 /* do not retain position for add route dialog */
537 add_route_dialog.set_state_mask (WindowProxy::Size);
539 /* Trigger setting up the color scheme and loading the GTK RC file */
541 UIConfiguration::instance().load_rc_file (false);
543 _process_thread = new ProcessThread ();
544 _process_thread->init ();
550 ARDOUR_UI::pre_release_dialog ()
552 ArdourDialog d (_("Pre-Release Warning"), true, false);
553 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
555 Label* label = manage (new Label);
556 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
557 There are still several issues and bugs to be worked on,\n\
558 as well as general workflow improvements, before this can be considered\n\
559 release software. So, a few guidelines:\n\
561 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
562 though it may be so, depending on your workflow.\n\
563 2) Please wait for a helpful writeup of new features.\n\
564 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
565 4) <b>Please do NOT file bugs for this alpha-development versions at this point in time</b>.\n\
566 There is no bug triaging before the initial development concludes and\n\
567 reporting issue for incomplete, ongoing work-in-progress is mostly useless.\n\
568 5) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
569 can get there directly from within the program via the Help->Chat menu option.\n\
570 6) Please <b>DO</b> submit patches for issues after discussing them on IRC.\n\
572 Full information on all the above can be found on the support page at\n\
574 http://ardour.org/support\n\
575 "), PROGRAM_NAME, VERSIONSTRING));
577 d.get_vbox()->set_border_width (12);
578 d.get_vbox()->pack_start (*label, false, false, 12);
579 d.get_vbox()->show_all ();
584 GlobalPortMatrixWindow*
585 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
590 return new GlobalPortMatrixWindow (_session, type);
594 ARDOUR_UI::attach_to_engine ()
596 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this, _1), gui_context());
597 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
601 ARDOUR_UI::engine_stopped ()
603 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
604 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
605 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
606 update_sample_rate (0);
611 ARDOUR_UI::engine_running (uint32_t cnt)
618 _session->reset_xrun_count ();
620 update_disk_space ();
622 update_sample_rate (AudioEngine::instance()->sample_rate());
623 update_timecode_format ();
624 update_peak_thread_work ();
625 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
626 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
630 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
632 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
633 /* we can't rely on the original string continuing to exist when we are called
634 again in the GUI thread, so make a copy and note that we need to
637 char *copy = strdup (reason);
638 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
642 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
643 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
645 update_sample_rate (0);
649 /* if the reason is a non-empty string, it means that the backend was shutdown
650 rather than just Ardour.
653 if (strlen (reason)) {
654 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
656 msgstr = string_compose (_("\
657 The audio backend has either been shutdown or it\n\
658 disconnected %1 because %1\n\
659 was not fast enough. Try to restart\n\
660 the audio backend and save the session."), PROGRAM_NAME);
663 MessageDialog msg (_main_window, msgstr);
664 pop_back_splash (msg);
668 free (const_cast<char*> (reason));
673 ARDOUR_UI::post_engine ()
675 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
677 #ifdef AUDIOUNIT_SUPPORT
679 if (AUPluginInfo::au_get_crashlog(au_msg)) {
680 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
681 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
682 info << au_msg << endmsg;
686 /* connect to important signals */
688 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
689 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
690 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
691 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
692 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
694 if (setup_windows ()) {
695 throw failed_constructor ();
698 transport_ctrl.map_actions ();
700 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
701 XMLNode* n = Config->extra_xml (X_("UI"));
703 _status_bar_visibility.set_state (*n);
706 check_memory_locking();
708 /* this is the first point at which all the possible actions are
709 * available, because some of the available actions are dependent on
710 * aspects of the engine/backend.
713 if (ARDOUR_COMMAND_LINE::show_key_actions) {
715 Bindings::save_all_bindings_as_html (sstr);
717 if (sstr.str().empty()) {
724 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
726 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
732 #ifdef PLATFORM_WINDOWS
738 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
739 #ifndef PLATFORM_WINDOWS
742 g_unlink (file_name);
744 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
750 #ifndef PLATFORM_WINDOWS
754 PBD::open_uri (string_compose ("file:///%1", file_name));
756 halt_connection.disconnect ();
757 AudioEngine::instance()->stop ();
762 if (ARDOUR_COMMAND_LINE::show_actions) {
765 vector<string> paths;
766 vector<string> labels;
767 vector<string> tooltips;
769 vector<Glib::RefPtr<Gtk::Action> > actions;
770 string ver_in = revision;
771 string ver = ver_in.substr(0, ver_in.find("-"));
774 output << "\n<h2>Menu actions</h2>" << endl;
775 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
776 output << " surfaces or scripts.\n</p>\n" << endl;
777 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
778 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
779 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
780 output << "<table class=\"dl\">\n <thead>" << endl;
781 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
782 output << " </thead>\n <tbody>" << endl;
784 ActionManager::get_all_actions (paths, labels, tooltips, keys, actions);
786 vector<string>::iterator p;
787 vector<string>::iterator l;
789 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
790 output << " <tr><th><kbd class=\"osc\">" << *p << "</kbd></th><td>" << *l << "</td></tr>" << endl;
792 output << " </tbody>\n </table>" << endl;
794 // output this mess to a browser for easiest X-platform use
795 // it is not pretty HTML, but it works and it's main purpose
796 // is to create raw html to fit in Ardour's manual with no editing
801 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
803 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
809 #ifdef PLATFORM_WINDOWS
815 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
816 #ifndef PLATFORM_WINDOWS
819 g_unlink (file_name);
821 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
827 #ifndef PLATFORM_WINDOWS
831 PBD::open_uri (string_compose ("file:///%1", file_name));
833 halt_connection.disconnect ();
834 AudioEngine::instance()->stop ();
838 /* this being a GUI and all, we want peakfiles */
840 AudioFileSource::set_build_peakfiles (true);
841 AudioFileSource::set_build_missing_peakfiles (true);
843 /* set default clock modes */
845 primary_clock->set_mode (AudioClock::Timecode);
846 secondary_clock->set_mode (AudioClock::BBT);
848 /* start the time-of-day-clock */
851 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
852 update_wall_clock ();
853 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
858 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
859 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
860 Config->map_parameters (pc);
862 UIConfiguration::instance().map_parameters (pc);
866 ARDOUR_UI::~ARDOUR_UI ()
868 UIConfiguration::instance().save_state();
870 ARDOUR_UI_UTILS::inhibit_screensaver (false);
874 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
875 // don't bother at 'real' exit. the OS cleans up for us.
876 delete big_clock; big_clock = 0;
877 delete primary_clock; primary_clock = 0;
878 delete secondary_clock; secondary_clock = 0;
879 delete _process_thread; _process_thread = 0;
880 delete time_info_box; time_info_box = 0;
881 delete meterbridge; meterbridge = 0;
882 delete luawindow; luawindow = 0;
883 delete editor; editor = 0;
884 delete mixer; mixer = 0;
885 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
887 delete gui_object_state; gui_object_state = 0;
888 delete _shared_popup_menu ; _shared_popup_menu = 0;
889 delete main_window_visibility;
890 FastMeter::flush_pattern_cache ();
891 ArdourFader::flush_pattern_cache ();
895 /* Small trick to flush main-thread event pool.
896 * Other thread-pools are destroyed at pthread_exit(),
897 * but tmain thread termination is too late to trigger Pool::~Pool()
899 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
900 delete ev->event_pool();
905 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
907 if (Splash::instance()) {
908 Splash::instance()->pop_back_for (win);
913 ARDOUR_UI::configure_timeout ()
915 if (last_configure_time == 0) {
916 /* no configure events yet */
920 /* force a gap of 0.5 seconds since the last configure event
923 if (get_microseconds() - last_configure_time < 500000) {
926 have_configure_timeout = false;
927 save_ardour_state ();
933 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
935 if (have_configure_timeout) {
936 last_configure_time = get_microseconds();
938 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
939 have_configure_timeout = true;
946 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
950 if (node.get_property ("roll", str)){
951 roll_controllable->set_id (str);
953 if (node.get_property ("stop", str)) {
954 stop_controllable->set_id (str);
956 if (node.get_property ("goto-start", str)) {
957 goto_start_controllable->set_id (str);
959 if (node.get_property ("goto-end", str)) {
960 goto_end_controllable->set_id (str);
962 if (node.get_property ("auto-loop", str)) {
963 auto_loop_controllable->set_id (str);
965 if (node.get_property ("play-selection", str)) {
966 play_selection_controllable->set_id (str);
968 if (node.get_property ("rec", str)) {
969 rec_controllable->set_id (str);
971 if (node.get_property ("shuttle", str)) {
972 shuttle_box.controllable()->set_id (str);
977 ARDOUR_UI::get_transport_controllable_state ()
979 XMLNode* node = new XMLNode(X_("TransportControllables"));
981 node->set_property (X_("roll"), roll_controllable->id());
982 node->set_property (X_("stop"), stop_controllable->id());
983 node->set_property (X_("goto-start"), goto_start_controllable->id());
984 node->set_property (X_("goto-end"), goto_end_controllable->id());
985 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
986 node->set_property (X_("play-selection"), play_selection_controllable->id());
987 node->set_property (X_("rec"), rec_controllable->id());
988 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
994 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
997 _session->save_state (snapshot_name);
1002 ARDOUR_UI::autosave_session ()
1004 if (g_main_depth() > 1) {
1005 /* inside a recursive main loop,
1006 give up because we may not be able to
1012 if (!Config->get_periodic_safety_backups()) {
1017 _session->maybe_write_autosave();
1024 ARDOUR_UI::session_dirty_changed ()
1031 ARDOUR_UI::update_autosave ()
1033 if (_session && _session->dirty()) {
1034 if (_autosave_connection.connected()) {
1035 _autosave_connection.disconnect();
1038 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1039 Config->get_periodic_safety_backup_interval() * 1000);
1042 if (_autosave_connection.connected()) {
1043 _autosave_connection.disconnect();
1049 ARDOUR_UI::check_announcements ()
1052 string _annc_filename;
1055 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1056 #elif defined PLATFORM_WINDOWS
1057 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1059 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1061 _annc_filename.append (VERSIONSTRING);
1063 _announce_string = "";
1065 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1066 FILE* fin = g_fopen (path.c_str(), "rb");
1068 while (!feof (fin)) {
1071 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1074 _announce_string.append (tmp, len);
1079 pingback (VERSIONSTRING, path);
1084 _hide_splash (gpointer arg)
1086 ((ARDOUR_UI*)arg)->hide_splash();
1091 ARDOUR_UI::starting ()
1093 Application* app = Application::instance ();
1094 const char *nsm_url;
1095 bool brand_new_user = ArdourStartup::required ();
1097 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1098 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1100 if (ARDOUR_COMMAND_LINE::check_announcements) {
1101 check_announcements ();
1106 /* we need to create this early because it may need to set the
1107 * audio backend end up.
1111 audio_midi_setup.get (true);
1113 std::cerr << "audio-midi engine setup failed."<< std::endl;
1117 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1118 nsm = new NSM_Client;
1119 if (!nsm->init (nsm_url)) {
1120 /* the ardour executable may have different names:
1122 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1123 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1124 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1126 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1128 const char *process_name = g_getenv ("ARDOUR_SELF");
1129 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1132 // wait for announce reply from nsm server
1133 for ( i = 0; i < 5000; ++i) {
1137 if (nsm->is_active()) {
1142 error << _("NSM server did not announce itself") << endmsg;
1145 // wait for open command from nsm server
1146 for ( i = 0; i < 5000; ++i) {
1148 Glib::usleep (1000);
1149 if (nsm->client_id ()) {
1155 error << _("NSM: no client ID provided") << endmsg;
1159 if (_session && nsm) {
1160 _session->set_nsm_state( nsm->is_active() );
1162 error << _("NSM: no session created") << endmsg;
1166 // nsm requires these actions disabled
1167 vector<string> action_names;
1168 action_names.push_back("SaveAs");
1169 action_names.push_back("Rename");
1170 action_names.push_back("New");
1171 action_names.push_back("Open");
1172 action_names.push_back("Recent");
1173 action_names.push_back("Close");
1175 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1176 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1178 act->set_sensitive (false);
1185 error << _("NSM: initialization failed") << endmsg;
1191 if (brand_new_user) {
1192 _initial_verbose_plugin_scan = true;
1197 _initial_verbose_plugin_scan = false;
1198 switch (s.response ()) {
1199 case Gtk::RESPONSE_OK:
1206 // TODO: maybe IFF brand_new_user
1207 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1208 std::string dspd (Config->get_default_session_parent_dir());
1209 Searchpath ds (ARDOUR::ardour_data_search_path());
1210 ds.add_subdirectory_to_paths ("sessions");
1211 vector<string> demos;
1212 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1214 ARDOUR::RecentSessions rs;
1215 ARDOUR::read_recent_sessions (rs);
1217 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1218 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1219 std::string name = basename_nosuffix (basename_nosuffix (*i));
1220 std::string path = Glib::build_filename (dspd, name);
1221 /* skip if session-dir already exists */
1222 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1225 /* skip sessions that are already in 'recent'.
1226 * eg. a new user changed <session-default-dir> shorly after installation
1228 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1229 if ((*r).first == name) {
1234 PBD::FileArchive ar (*i);
1235 if (0 == ar.inflate (dspd)) {
1236 store_recent_sessions (name, path);
1237 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1243 #ifdef NO_PLUGIN_STATE
1245 ARDOUR::RecentSessions rs;
1246 ARDOUR::read_recent_sessions (rs);
1248 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1250 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1252 /* already used Ardour, have sessions ... warn about plugin state */
1254 ArdourDialog d (_("Free/Demo Version Warning"), true);
1256 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1257 CheckButton c (_("Don't warn me about this again"));
1259 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1260 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1261 _("It will not restore OR save any plugin settings"),
1262 _("If you load an existing session with plugin settings\n"
1263 "they will not be used and will be lost."),
1264 _("To get full access to updates without this limitation\n"
1265 "consider becoming a subscriber for a low cost every month.")));
1266 l.set_justify (JUSTIFY_CENTER);
1268 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1270 d.get_vbox()->pack_start (l, true, true);
1271 d.get_vbox()->pack_start (b, false, false, 12);
1272 d.get_vbox()->pack_start (c, false, false, 12);
1274 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1275 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1279 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1281 if (d.run () != RESPONSE_OK) {
1282 _exit (EXIT_SUCCESS);
1287 /* go get a session */
1289 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1291 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1292 std::cerr << "Cannot get session parameters."<< std::endl;
1299 WM::Manager::instance().show_visible ();
1301 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1302 * editor window, and we may want stuff to be hidden.
1304 _status_bar_visibility.update ();
1306 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1308 /* all other dialogs are created conditionally */
1314 ARDOUR_UI::check_memory_locking ()
1316 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1317 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1321 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1323 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1325 struct rlimit limits;
1327 long pages, page_size;
1329 size_t pages_len=sizeof(pages);
1330 if ((page_size = getpagesize()) < 0 ||
1331 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1333 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1338 ram = (int64_t) pages * (int64_t) page_size;
1341 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1345 if (limits.rlim_cur != RLIM_INFINITY) {
1347 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1351 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1352 "This might cause %1 to run out of memory before your system "
1353 "runs out of memory. \n\n"
1354 "You can view the memory limit with 'ulimit -l', "
1355 "and it is normally controlled by %2"),
1358 X_("/etc/login.conf")
1360 X_(" /etc/security/limits.conf")
1364 msg.set_default_response (RESPONSE_OK);
1366 VBox* vbox = msg.get_vbox();
1368 CheckButton cb (_("Do not show this window again"));
1369 hbox.pack_start (cb, true, false);
1370 vbox->pack_start (hbox);
1375 pop_back_splash (msg);
1379 if (cb.get_active()) {
1380 XMLNode node (X_("no-memory-warning"));
1381 Config->add_instant_xml (node);
1386 #endif // !__APPLE__
1391 ARDOUR_UI::queue_finish ()
1393 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1397 ARDOUR_UI::idle_finish ()
1400 return false; /* do not call again */
1407 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1409 if (_session->dirty()) {
1410 vector<string> actions;
1411 actions.push_back (_("Don't quit"));
1412 actions.push_back (_("Just quit"));
1413 actions.push_back (_("Save and quit"));
1414 switch (ask_about_saving_session(actions)) {
1419 /* use the default name */
1420 if (save_state_canfail ("")) {
1421 /* failed - don't quit */
1422 MessageDialog msg (_main_window,
1423 string_compose (_("\
1424 %1 was unable to save your session.\n\n\
1425 If you still wish to quit, please use the\n\n\
1426 \"Just quit\" option."), PROGRAM_NAME));
1427 pop_back_splash(msg);
1437 second_connection.disconnect ();
1438 point_one_second_connection.disconnect ();
1439 point_zero_something_second_connection.disconnect();
1440 fps_connection.disconnect();
1443 delete ARDOUR_UI::instance()->video_timeline;
1444 ARDOUR_UI::instance()->video_timeline = NULL;
1445 stop_video_server();
1447 /* Save state before deleting the session, as that causes some
1448 windows to be destroyed before their visible state can be
1451 save_ardour_state ();
1453 if (key_editor.get (false)) {
1454 key_editor->disconnect ();
1457 close_all_dialogs ();
1460 _session->set_clean ();
1465 halt_connection.disconnect ();
1466 AudioEngine::instance()->stop ();
1467 #ifdef WINDOWS_VST_SUPPORT
1468 fst_stop_threading();
1474 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1476 ArdourDialog window (_("Unsaved Session"));
1477 Gtk::HBox dhbox; // the hbox for the image and text
1478 Gtk::Label prompt_label;
1479 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1483 assert (actions.size() >= 3);
1485 window.add_button (actions[0], RESPONSE_REJECT);
1486 window.add_button (actions[1], RESPONSE_APPLY);
1487 window.add_button (actions[2], RESPONSE_ACCEPT);
1489 window.set_default_response (RESPONSE_ACCEPT);
1491 Gtk::Button noquit_button (msg);
1492 noquit_button.set_name ("EditorGTKButton");
1496 if (_session->snap_name() == _session->name()) {
1497 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1498 _session->snap_name());
1500 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1501 _session->snap_name());
1504 prompt_label.set_text (prompt);
1505 prompt_label.set_name (X_("PrompterLabel"));
1506 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1508 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1509 dhbox.set_homogeneous (false);
1510 dhbox.pack_start (*dimage, false, false, 5);
1511 dhbox.pack_start (prompt_label, true, false, 5);
1512 window.get_vbox()->pack_start (dhbox);
1514 window.set_name (_("Prompter"));
1515 window.set_modal (true);
1516 window.set_resizable (false);
1519 prompt_label.show();
1524 ResponseType r = (ResponseType) window.run();
1529 case RESPONSE_ACCEPT: // save and get out of here
1531 case RESPONSE_APPLY: // get out of here
1542 ARDOUR_UI::every_second ()
1545 update_disk_space ();
1546 update_timecode_format ();
1547 update_peak_thread_work ();
1549 if (nsm && nsm->is_active ()) {
1552 if (!_was_dirty && _session->dirty ()) {
1556 else if (_was_dirty && !_session->dirty ()){
1564 ARDOUR_UI::every_point_one_seconds ()
1566 if (editor) editor->build_region_boundary_cache();
1570 ARDOUR_UI::every_point_zero_something_seconds ()
1572 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1574 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1575 float mpeak = editor_meter->update_meters();
1576 if (mpeak > editor_meter_max_peak) {
1577 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1578 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1585 ARDOUR_UI::set_fps_timeout_connection ()
1587 unsigned int interval = 40;
1588 if (!_session) return;
1589 if (_session->timecode_frames_per_second() != 0) {
1590 /* ideally we'll use a select() to sleep and not accumulate
1591 * idle time to provide a regular periodic signal.
1592 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1593 * However, that'll require a dedicated thread and cross-thread
1594 * signals to the GUI Thread..
1596 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1597 * _session->sample_rate() / _session->nominal_sample_rate()
1598 / _session->timecode_frames_per_second()
1600 #ifdef PLATFORM_WINDOWS
1601 // the smallest windows scheduler time-slice is ~15ms.
1602 // periodic GUI timeouts shorter than that will cause
1603 // WaitForSingleObject to spinlock (100% of one CPU Core)
1604 // and gtk never enters idle mode.
1605 // also changing timeBeginPeriod(1) does not affect that in
1606 // any beneficial way, so we just limit the max rate for now.
1607 interval = std::max(30u, interval); // at most ~33Hz.
1609 interval = std::max(8u, interval); // at most 120Hz.
1612 fps_connection.disconnect();
1613 Timers::set_fps_interval (interval);
1617 ARDOUR_UI::update_sample_rate (samplecnt_t)
1621 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1623 if (!AudioEngine::instance()->running()) {
1625 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1629 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1632 /* no sample rate available */
1633 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1636 if (fmod (rate, 1000.0) != 0.0) {
1637 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1638 (float) rate / 1000.0f,
1639 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1641 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1643 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1647 sample_rate_label.set_markup (buf);
1651 ARDOUR_UI::update_format ()
1654 format_label.set_text ("");
1659 s << _("File:") << X_(" <span foreground=\"green\">");
1661 switch (_session->config.get_native_file_header_format ()) {
1696 switch (_session->config.get_native_file_data_format ()) {
1710 format_label.set_markup (s.str ());
1714 ARDOUR_UI::update_cpu_load ()
1716 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1717 double const c = AudioEngine::instance()->get_dsp_load ();
1719 const char* const bg = c > 90 ? " background=\"red\"" : "";
1723 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1725 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1727 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1730 dsp_load_label.set_markup (buf);
1733 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1735 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1737 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1740 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1744 ARDOUR_UI::update_peak_thread_work ()
1747 const int c = SourceFactory::peak_work_queue_length ();
1749 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1750 peak_thread_work_label.set_markup (buf);
1752 peak_thread_work_label.set_markup (X_(""));
1757 ARDOUR_UI::count_recenabled_streams (Route& route)
1759 Track* track = dynamic_cast<Track*>(&route);
1760 if (track && track->rec_enable_control()->get_value()) {
1761 rec_enabled_streams += track->n_inputs().n_total();
1766 ARDOUR_UI::format_disk_space_label (float remain_sec)
1768 if (remain_sec < 0) {
1769 disk_space_label.set_text (_("N/A"));
1770 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1776 int sec = floor (remain_sec);
1777 int hrs = sec / 3600;
1778 int mins = (sec / 60) % 60;
1779 int secs = sec % 60;
1780 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1781 ArdourWidgets::set_tooltip (disk_space_label, buf);
1783 if (remain_sec > 86400) {
1784 disk_space_label.set_text (_("Rec: >24h"));
1786 } else if (remain_sec > 32400 /* 9 hours */) {
1787 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1788 } else if (remain_sec > 5940 /* 99 mins */) {
1789 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1791 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1793 disk_space_label.set_text (buf);
1798 ARDOUR_UI::update_disk_space()
1800 if (_session == 0) {
1801 format_disk_space_label (-1);
1805 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1806 samplecnt_t fr = _session->sample_rate();
1809 /* skip update - no SR available */
1810 format_disk_space_label (-1);
1815 /* Available space is unknown */
1816 format_disk_space_label (-1);
1817 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1818 format_disk_space_label (max_samplecnt);
1820 rec_enabled_streams = 0;
1821 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1823 samplecnt_t samples = opt_samples.get_value_or (0);
1825 if (rec_enabled_streams) {
1826 samples /= rec_enabled_streams;
1829 format_disk_space_label (samples / (float)fr);
1835 ARDOUR_UI::update_timecode_format ()
1841 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1842 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1844 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1845 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1850 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1851 matching ? X_("green") : X_("red"),
1852 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1854 snprintf (buf, sizeof (buf), "TC: n/a");
1857 timecode_format_label.set_markup (buf);
1861 ARDOUR_UI::update_wall_clock ()
1865 static int last_min = -1;
1868 tm_now = localtime (&now);
1869 if (last_min != tm_now->tm_min) {
1871 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1872 wall_clock_label.set_text (buf);
1873 last_min = tm_now->tm_min;
1880 ARDOUR_UI::open_recent_session ()
1882 bool can_return = (_session != 0);
1884 SessionDialog recent_session_dialog;
1888 ResponseType r = (ResponseType) recent_session_dialog.run ();
1891 case RESPONSE_ACCEPT:
1895 recent_session_dialog.hide();
1898 exit (EXIT_FAILURE);
1902 recent_session_dialog.hide();
1906 std::string path = recent_session_dialog.session_folder();
1907 std::string state = recent_session_dialog.session_name (should_be_new);
1909 if (should_be_new == true) {
1913 _session_is_new = false;
1915 if (load_session (path, state) == 0) {
1924 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1926 if (!AudioEngine::instance()->running()) {
1927 MessageDialog msg (parent, string_compose (
1928 _("%1 is not connected to any audio backend.\n"
1929 "You cannot open or close sessions in this condition"),
1931 pop_back_splash (msg);
1939 ARDOUR_UI::open_session ()
1941 if (!check_audioengine (_main_window)) {
1945 /* ardour sessions are folders */
1946 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1947 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1948 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1949 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1952 string session_parent_dir = Glib::path_get_dirname(_session->path());
1953 open_session_selector.set_current_folder(session_parent_dir);
1955 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1958 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1960 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1961 string default_session_folder = Config->get_default_session_parent_dir();
1962 open_session_selector.add_shortcut_folder (default_session_folder);
1964 catch (Glib::Error const& e) {
1965 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1968 FileFilter session_filter;
1969 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1970 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1971 open_session_selector.add_filter (session_filter);
1973 FileFilter archive_filter;
1974 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1975 archive_filter.set_name (_("Session Archives"));
1977 open_session_selector.add_filter (archive_filter);
1979 open_session_selector.set_filter (session_filter);
1981 int response = open_session_selector.run();
1982 open_session_selector.hide ();
1984 if (response == Gtk::RESPONSE_CANCEL) {
1988 string session_path = open_session_selector.get_filename();
1992 if (session_path.length() > 0) {
1993 int rv = ARDOUR::inflate_session (session_path,
1994 Config->get_default_session_parent_dir(), path, name);
1996 _session_is_new = false;
1997 load_session (path, name);
2000 MessageDialog msg (_main_window,
2001 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2004 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2005 _session_is_new = isnew;
2006 load_session (path, name);
2012 ARDOUR_UI::session_add_mixed_track (
2013 const ChanCount& input,
2014 const ChanCount& output,
2015 RouteGroup* route_group,
2017 const string& name_template,
2019 PluginInfoPtr instrument,
2020 Plugin::PresetRecord* pset,
2021 ARDOUR::PresentationInfo::order_t order)
2025 if (Profile->get_mixbus ()) {
2030 list<boost::shared_ptr<MidiTrack> > tracks;
2031 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2033 if (tracks.size() != how_many) {
2034 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2039 display_insufficient_ports_message ();
2045 ARDOUR_UI::session_add_midi_bus (
2046 RouteGroup* route_group,
2048 const string& name_template,
2050 PluginInfoPtr instrument,
2051 Plugin::PresetRecord* pset,
2052 ARDOUR::PresentationInfo::order_t order)
2054 if (_session == 0) {
2055 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2059 if (Profile->get_mixbus ()) {
2065 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2066 if (routes.size() != how_many) {
2067 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2072 display_insufficient_ports_message ();
2078 ARDOUR_UI::session_add_midi_route (
2080 RouteGroup* route_group,
2082 const string& name_template,
2084 PluginInfoPtr instrument,
2085 Plugin::PresetRecord* pset,
2086 ARDOUR::PresentationInfo::order_t order)
2088 ChanCount one_midi_channel;
2089 one_midi_channel.set (DataType::MIDI, 1);
2092 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2094 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2099 ARDOUR_UI::session_add_audio_route (
2101 int32_t input_channels,
2102 int32_t output_channels,
2103 ARDOUR::TrackMode mode,
2104 RouteGroup* route_group,
2106 string const & name_template,
2108 ARDOUR::PresentationInfo::order_t order)
2110 list<boost::shared_ptr<AudioTrack> > tracks;
2117 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2119 if (tracks.size() != how_many) {
2120 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2126 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2128 if (routes.size() != how_many) {
2129 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2136 display_insufficient_ports_message ();
2141 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2142 (*i)->set_strict_io (true);
2144 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2145 (*i)->set_strict_io (true);
2151 ARDOUR_UI::session_add_foldback_bus (int32_t channels, uint32_t how_many, string const & name_template)
2158 routes = _session->new_audio_route (channels, channels, 0, how_many, name_template, PresentationInfo::FoldbackBus, -1);
2160 if (routes.size() != how_many) {
2161 error << string_compose (P_("could not create %1 new foldback bus", "could not create %1 new foldback busses", how_many), how_many)
2167 display_insufficient_ports_message ();
2173 ARDOUR_UI::display_insufficient_ports_message ()
2175 MessageDialog msg (_main_window,
2176 string_compose (_("There are insufficient ports available\n\
2177 to create a new track or bus.\n\
2178 You should save %1, exit and\n\
2179 restart with more ports."), PROGRAM_NAME));
2180 pop_back_splash (msg);
2185 ARDOUR_UI::transport_goto_start ()
2188 _session->goto_start();
2190 /* force displayed area in editor to start no matter
2191 what "follow playhead" setting is.
2195 editor->center_screen (_session->current_start_sample ());
2201 ARDOUR_UI::transport_goto_zero ()
2204 _session->request_locate (0);
2206 /* force displayed area in editor to start no matter
2207 what "follow playhead" setting is.
2211 editor->reset_x_origin (0);
2217 ARDOUR_UI::transport_goto_wallclock ()
2219 if (_session && editor) {
2223 samplepos_t samples;
2226 localtime_r (&now, &tmnow);
2228 samplecnt_t sample_rate = _session->sample_rate();
2230 if (sample_rate == 0) {
2231 /* no frame rate available */
2235 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2236 samples += tmnow.tm_min * (60 * sample_rate);
2237 samples += tmnow.tm_sec * sample_rate;
2239 _session->request_locate (samples, _session->transport_rolling ());
2241 /* force displayed area in editor to start no matter
2242 what "follow playhead" setting is.
2246 editor->center_screen (samples);
2252 ARDOUR_UI::transport_goto_end ()
2255 samplepos_t const sample = _session->current_end_sample();
2256 _session->request_locate (sample);
2258 /* force displayed area in editor to start no matter
2259 what "follow playhead" setting is.
2263 editor->center_screen (sample);
2269 ARDOUR_UI::transport_stop ()
2275 if (_session->is_auditioning()) {
2276 _session->cancel_audition ();
2280 _session->request_stop (false, true);
2283 /** Check if any tracks are record enabled. If none are, record enable all of them.
2284 * @return true if track record-enabled status was changed, false otherwise.
2287 ARDOUR_UI::trx_record_enable_all_tracks ()
2293 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2294 bool none_record_enabled = true;
2296 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2297 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2300 if (t->rec_enable_control()->get_value()) {
2301 none_record_enabled = false;
2306 if (none_record_enabled) {
2307 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2310 return none_record_enabled;
2314 ARDOUR_UI::transport_record (bool roll)
2317 switch (_session->record_status()) {
2318 case Session::Disabled:
2319 if (_session->ntracks() == 0) {
2320 MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
2324 if (Profile->get_trx()) {
2325 roll = trx_record_enable_all_tracks ();
2327 _session->maybe_enable_record ();
2332 case Session::Recording:
2334 _session->request_stop();
2336 _session->disable_record (false, true);
2340 case Session::Enabled:
2341 _session->disable_record (false, true);
2347 ARDOUR_UI::transport_roll ()
2353 if (_session->is_auditioning()) {
2357 if (_session->config.get_external_sync()) {
2358 switch (TransportMasterManager::instance().current()->type()) {
2362 /* transport controlled by the master */
2367 bool rolling = _session->transport_rolling();
2369 if (_session->get_play_loop()) {
2371 /* If loop playback is not a mode, then we should cancel
2372 it when this action is requested. If it is a mode
2373 we just leave it in place.
2376 if (!Config->get_loop_is_mode()) {
2377 /* XXX it is not possible to just leave seamless loop and keep
2378 playing at present (nov 4th 2009)
2380 if (!Config->get_seamless_loop()) {
2381 /* stop loop playback and stop rolling */
2382 _session->request_play_loop (false, true);
2383 } else if (rolling) {
2384 /* stop loop playback but keep rolling */
2385 _session->request_play_loop (false, false);
2389 } else if (_session->get_play_range () ) {
2390 /* stop playing a range if we currently are */
2391 _session->request_play_range (0, true);
2395 _session->request_transport_speed (1.0f);
2400 ARDOUR_UI::get_smart_mode() const
2402 return ( editor->get_smart_mode() );
2407 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2413 if (_session->is_auditioning()) {
2414 _session->cancel_audition ();
2418 if (_session->config.get_external_sync()) {
2419 switch (TransportMasterManager::instance().current()->type()) {
2423 /* transport controlled by the master */
2428 bool rolling = _session->transport_rolling();
2429 bool affect_transport = true;
2431 if (rolling && roll_out_of_bounded_mode) {
2432 /* drop out of loop/range playback but leave transport rolling */
2433 if (_session->get_play_loop()) {
2434 if (_session->actively_recording()) {
2436 /* just stop using the loop, then actually stop
2439 _session->request_play_loop (false, affect_transport);
2442 if (Config->get_seamless_loop()) {
2443 /* the disk buffers contain copies of the loop - we can't
2444 just keep playing, so stop the transport. the user
2445 can restart as they wish.
2447 affect_transport = true;
2449 /* disk buffers are normal, so we can keep playing */
2450 affect_transport = false;
2452 _session->request_play_loop (false, affect_transport);
2454 } else if (_session->get_play_range ()) {
2455 affect_transport = false;
2456 _session->request_play_range (0, true);
2460 if (affect_transport) {
2462 _session->request_stop (with_abort, true);
2464 } else if (!with_abort) { /* with_abort == true means the
2465 * command was intended to stop
2466 * transport, not start.
2469 /* the only external sync condition we can be in here
2470 * would be Engine (JACK) sync, in which case we still
2474 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_sample() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2475 _session->request_play_range (&editor->get_selection().time, true);
2476 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2478 _session->request_transport_speed (1.0f);
2484 ARDOUR_UI::toggle_session_auto_loop ()
2490 Location * looploc = _session->locations()->auto_loop_location();
2496 if (_session->get_play_loop()) {
2498 /* looping enabled, our job is to disable it */
2500 _session->request_play_loop (false);
2504 /* looping not enabled, our job is to enable it.
2506 loop-is-NOT-mode: this action always starts the transport rolling.
2507 loop-IS-mode: this action simply sets the loop play mechanism, but
2508 does not start transport.
2510 if (Config->get_loop_is_mode()) {
2511 _session->request_play_loop (true, false);
2513 _session->request_play_loop (true, true);
2517 //show the loop markers
2518 looploc->set_hidden (false, this);
2522 ARDOUR_UI::transport_play_selection ()
2528 editor->play_selection ();
2532 ARDOUR_UI::transport_play_preroll ()
2537 editor->play_with_preroll ();
2541 ARDOUR_UI::transport_rec_preroll ()
2546 editor->rec_with_preroll ();
2550 ARDOUR_UI::transport_rec_count_in ()
2555 editor->rec_with_count_in ();
2559 ARDOUR_UI::transport_rewind (int option)
2561 float current_transport_speed;
2564 current_transport_speed = _session->transport_speed();
2566 if (current_transport_speed >= 0.0f) {
2569 _session->request_transport_speed (-1.0f);
2572 _session->request_transport_speed (-4.0f);
2575 _session->request_transport_speed (-0.5f);
2580 _session->request_transport_speed (current_transport_speed * 1.5f);
2586 ARDOUR_UI::transport_forward (int option)
2592 float current_transport_speed = _session->transport_speed();
2594 if (current_transport_speed <= 0.0f) {
2597 _session->request_transport_speed (1.0f);
2600 _session->request_transport_speed (4.0f);
2603 _session->request_transport_speed (0.5f);
2608 _session->request_transport_speed (current_transport_speed * 1.5f);
2613 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2619 boost::shared_ptr<Route> r;
2621 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2623 boost::shared_ptr<Track> t;
2625 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2626 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2632 ARDOUR_UI::map_transport_state ()
2635 layered_button.set_sensitive (false);
2639 shuttle_box.map_transport_state ();
2641 float sp = _session->transport_speed();
2644 layered_button.set_sensitive (!_session->actively_recording ());
2646 layered_button.set_sensitive (true);
2647 update_disk_space ();
2649 if (UIConfiguration::instance().get_screen_saver_mode () == InhibitWhileRecording) {
2650 inhibit_screensaver (_session->actively_recording ());
2655 ARDOUR_UI::blink_handler (bool blink_on)
2657 sync_blink (blink_on);
2659 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2662 error_blink (blink_on);
2663 solo_blink (blink_on);
2664 audition_blink (blink_on);
2665 feedback_blink (blink_on);
2669 ARDOUR_UI::update_clocks ()
2671 if (!_session) return;
2673 if (editor && !editor->dragging_playhead()) {
2674 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2679 ARDOUR_UI::start_clocking ()
2681 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2682 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2684 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2689 ARDOUR_UI::stop_clocking ()
2691 clock_signal_connection.disconnect ();
2695 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2699 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2701 label->set_text (buf);
2702 bar->set_fraction (fraction);
2704 /* process events, redraws, etc. */
2706 while (gtk_events_pending()) {
2707 gtk_main_iteration ();
2710 return true; /* continue with save-as */
2714 ARDOUR_UI::save_session_as ()
2720 if (_session->dirty()) {
2721 vector<string> actions;
2722 actions.push_back (_("Abort save-as"));
2723 actions.push_back (_("Don't save now, just save-as"));
2724 actions.push_back (_("Save it first"));
2725 switch (ask_about_saving_session(actions)) {
2730 if (save_state_canfail ("")) {
2731 MessageDialog msg (_main_window,
2732 string_compose (_("\
2733 %1 was unable to save your session.\n\n\
2734 If you still wish to proceed, please use the\n\n\
2735 \"Don't save now\" option."), PROGRAM_NAME));
2736 pop_back_splash(msg);
2742 _session->remove_pending_capture_state ();
2747 if (!save_as_dialog) {
2748 save_as_dialog = new SaveAsDialog;
2751 save_as_dialog->set_name (_session->name());
2753 int response = save_as_dialog->run ();
2755 save_as_dialog->hide ();
2758 case Gtk::RESPONSE_OK:
2767 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2768 sa.new_name = save_as_dialog->new_name ();
2769 sa.switch_to = save_as_dialog->switch_to();
2770 sa.copy_media = save_as_dialog->copy_media();
2771 sa.copy_external = save_as_dialog->copy_external();
2772 sa.include_media = save_as_dialog->include_media ();
2774 /* Only bother with a progress dialog if we're going to copy
2775 media into the save-as target. Without that choice, this
2776 will be very fast because we're only talking about a few kB's to
2777 perhaps a couple of MB's of data.
2780 ArdourDialog progress_dialog (_("Save As"), true);
2783 if (sa.include_media && sa.copy_media) {
2785 Gtk::Label* label = manage (new Gtk::Label());
2786 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2788 progress_dialog.get_vbox()->pack_start (*label);
2789 progress_dialog.get_vbox()->pack_start (*progress_bar);
2791 progress_bar->show ();
2793 /* this signal will be emitted from within this, the calling thread,
2794 * after every file is copied. It provides information on percentage
2795 * complete (in terms of total data to copy), the number of files
2796 * copied so far, and the total number to copy.
2799 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2801 progress_dialog.show_all ();
2802 progress_dialog.present ();
2805 if (_session->save_as (sa)) {
2807 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2811 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2812 * the trick is this: if the new session was copy with media included,
2813 * then Session::save_as() will have already done a neat trick to avoid
2814 * us having to unload and load the new state. But if the media was not
2815 * included, then this is required (it avoids us having to otherwise
2816 * drop all references to media (sources).
2819 if (!sa.include_media && sa.switch_to) {
2820 unload_session (false);
2821 load_session (sa.final_session_folder_name, sa.new_name);
2826 ARDOUR_UI::archive_session ()
2834 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2836 SessionArchiveDialog sad;
2837 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2838 int response = sad.run ();
2840 if (response != Gtk::RESPONSE_OK) {
2845 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2846 MessageDialog msg (_("Session Archiving failed."));
2852 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2856 struct tm local_time;
2859 localtime_r (&n, &local_time);
2860 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2861 if (switch_to_it && _session->dirty ()) {
2862 save_state_canfail ("");
2865 save_state (timebuf, switch_to_it);
2870 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2874 prompter.get_result (snapname);
2876 bool do_save = (snapname.length() != 0);
2879 char illegal = Session::session_name_is_legal(snapname);
2881 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2882 "snapshot names may not contain a '%1' character"), illegal));
2888 vector<std::string> p;
2889 get_state_files_in_directory (_session->session_directory().root_path(), p);
2890 vector<string> n = get_file_names_no_extension (p);
2892 if (find (n.begin(), n.end(), snapname) != n.end()) {
2894 do_save = overwrite_file_dialog (prompter,
2895 _("Confirm Snapshot Overwrite"),
2896 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2900 save_state (snapname, switch_to_it);
2910 /** Ask the user for the name of a new snapshot and then take it.
2914 ARDOUR_UI::snapshot_session (bool switch_to_it)
2916 if (switch_to_it && _session->dirty()) {
2917 vector<string> actions;
2918 actions.push_back (_("Abort saving snapshot"));
2919 actions.push_back (_("Don't save now, just snapshot"));
2920 actions.push_back (_("Save it first"));
2921 switch (ask_about_saving_session(actions)) {
2926 if (save_state_canfail ("")) {
2927 MessageDialog msg (_main_window,
2928 string_compose (_("\
2929 %1 was unable to save your session.\n\n\
2930 If you still wish to proceed, please use the\n\n\
2931 \"Don't save now\" option."), PROGRAM_NAME));
2932 pop_back_splash(msg);
2938 _session->remove_pending_capture_state ();
2943 Prompter prompter (true);
2944 prompter.set_name ("Prompter");
2945 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2947 prompter.set_title (_("Snapshot and switch"));
2948 prompter.set_prompt (_("New session name"));
2950 prompter.set_title (_("Take Snapshot"));
2951 prompter.set_prompt (_("Name of new snapshot"));
2955 prompter.set_initial_text (_session->snap_name());
2957 Glib::DateTime tm (g_date_time_new_now_local ());
2958 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2961 bool finished = false;
2963 switch (prompter.run()) {
2964 case RESPONSE_ACCEPT:
2966 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2977 /** Ask the user for a new session name and then rename the session to it.
2981 ARDOUR_UI::rename_session ()
2987 Prompter prompter (true);
2990 prompter.set_name ("Prompter");
2991 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2992 prompter.set_title (_("Rename Session"));
2993 prompter.set_prompt (_("New session name"));
2996 switch (prompter.run()) {
2997 case RESPONSE_ACCEPT:
2999 prompter.get_result (name);
3001 bool do_rename = (name.length() != 0);
3004 char illegal = Session::session_name_is_legal (name);
3007 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3008 "session names may not contain a '%1' character"), illegal));
3013 switch (_session->rename (name)) {
3015 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3016 msg.set_position (WIN_POS_MOUSE);
3024 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3025 msg.set_position (WIN_POS_MOUSE);
3041 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3043 if (!_session || _session->deletion_in_progress()) {
3047 XMLNode* node = new XMLNode (X_("UI"));
3049 WM::Manager::instance().add_state (*node);
3051 node->add_child_nocopy (gui_object_state->get_state());
3053 _session->add_extra_xml (*node);
3055 if (export_video_dialog) {
3056 _session->add_extra_xml (export_video_dialog->get_state());
3059 save_state_canfail (name, switch_to_it);
3063 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3068 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3073 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3078 ARDOUR_UI::primary_clock_value_changed ()
3081 _session->request_locate (primary_clock->current_time ());
3086 ARDOUR_UI::big_clock_value_changed ()
3089 _session->request_locate (big_clock->current_time ());
3094 ARDOUR_UI::secondary_clock_value_changed ()
3097 _session->request_locate (secondary_clock->current_time ());
3101 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3103 if (response == RESPONSE_ACCEPT) {
3104 const string name = d->get_template_name ();
3105 const string desc = d->get_description ();
3107 int failed = _session->save_template (name, desc);
3109 if (failed == -2) { /* file already exists. */
3110 bool overwrite = overwrite_file_dialog (*d,
3111 _("Confirm Template Overwrite"),
3112 _("A template already exists with that name. Do you want to overwrite it?"));
3115 _session->save_template (name, desc, true);
3127 ARDOUR_UI::save_template ()
3129 if (!check_audioengine (_main_window)) {
3133 const std::string desc = SessionMetadata::Metadata()->description ();
3134 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3135 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3139 void ARDOUR_UI::manage_templates ()
3146 ARDOUR_UI::edit_metadata ()
3148 SessionMetadataEditor dialog;
3149 dialog.set_session (_session);
3150 dialog.grab_focus ();
3155 ARDOUR_UI::import_metadata ()
3157 SessionMetadataImporter dialog;
3158 dialog.set_session (_session);
3163 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3165 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3167 MessageDialog msg (str,
3169 Gtk::MESSAGE_WARNING,
3170 Gtk::BUTTONS_YES_NO,
3174 msg.set_name (X_("OpenExistingDialog"));
3175 msg.set_title (_("Open Existing Session"));
3176 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3177 msg.set_position (Gtk::WIN_POS_CENTER);
3178 pop_back_splash (msg);
3180 switch (msg.run()) {
3189 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3191 BusProfile bus_profile;
3194 bus_profile.master_out_channels = 2;
3196 /* get settings from advanced section of NSD */
3197 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3200 // NULL profile: no master, no monitor
3201 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3209 ARDOUR_UI::load_from_application_api (const std::string& path)
3211 /* OS X El Capitan (and probably later) now somehow passes the command
3212 line arguments to an app via the openFile delegate protocol. Ardour
3213 already does its own command line processing, and having both
3214 pathways active causes crashes. So, if the command line was already
3215 set, do nothing here.
3218 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3222 ARDOUR_COMMAND_LINE::session_name = path;
3224 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3226 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3228 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3229 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3230 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3231 * -> SessionDialog is not displayed
3234 if (_session_dialog) {
3235 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3236 std::string session_path = path;
3237 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3238 session_path = Glib::path_get_dirname (session_path);
3240 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3241 _session_dialog->set_provided_session (session_name, session_path);
3242 _session_dialog->response (RESPONSE_NONE);
3243 _session_dialog->hide();
3248 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3249 /* /path/to/foo => /path/to/foo, foo */
3250 rv = load_session (path, basename_nosuffix (path));
3252 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3253 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3256 // if load_session fails -> pop up SessionDialog.
3258 ARDOUR_COMMAND_LINE::session_name = "";
3260 if (get_session_parameters (true, false)) {
3261 exit (EXIT_FAILURE);
3266 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3268 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3270 string session_name;
3271 string session_path;
3272 string template_name;
3274 bool likely_new = false;
3275 bool cancel_not_quit;
3277 /* deal with any existing DIRTY session now, rather than later. don't
3278 * treat a non-dirty session this way, so that it stays visible
3279 * as we bring up the new session dialog.
3282 if (_session && ARDOUR_UI::instance()->video_timeline) {
3283 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3286 /* if there is already a session, relabel the button
3287 on the SessionDialog so that we don't Quit directly
3289 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3291 if (_session && _session->dirty()) {
3292 if (unload_session (false)) {
3293 /* unload cancelled by user */
3296 ARDOUR_COMMAND_LINE::session_name = "";
3299 if (!load_template.empty()) {
3300 should_be_new = true;
3301 template_name = load_template;
3304 session_path = ARDOUR_COMMAND_LINE::session_name;
3306 if (!session_path.empty()) {
3308 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3310 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3312 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3313 /* session/snapshot file, change path to be dir */
3314 session_path = Glib::path_get_dirname (session_path);
3318 /* session (file or folder) does not exist ... did the
3319 * user give us a path or just a name?
3322 if (session_path.find (G_DIR_SEPARATOR) == string::npos) {
3323 /* user gave session name with no path info, use
3324 default session folder.
3326 session_name = ARDOUR_COMMAND_LINE::session_name;
3327 session_path = Glib::build_filename (Config->get_default_session_parent_dir (), session_name);
3329 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3334 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3336 _session_dialog = &session_dialog;
3339 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3341 /* if they named a specific statefile, use it, otherwise they are
3342 just giving a session folder, and we want to use it as is
3343 to find the session.
3346 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3348 if (suffix != string::npos) {
3349 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3350 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3351 session_name = Glib::path_get_basename (session_name);
3353 session_path = ARDOUR_COMMAND_LINE::session_name;
3354 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3359 session_dialog.clear_given ();
3362 if (session_name.empty()) {
3363 /* need the dialog to get the name (at least) from the user */
3364 switch (session_dialog.run()) {
3365 case RESPONSE_ACCEPT:
3368 /* this is used for async * app->ShouldLoad(). */
3369 continue; // while loop
3372 if (quit_on_cancel) {
3373 ARDOUR_UI::finish ();
3374 Gtkmm2ext::Application::instance()->cleanup();
3376 pthread_cancel_all ();
3377 return -1; // caller is responsible to call exit()
3383 session_dialog.hide ();
3386 /* if we run the startup dialog again, offer more than just "new session" */
3388 should_be_new = false;
3390 session_name = session_dialog.session_name (likely_new);
3391 session_path = session_dialog.session_folder ();
3398 int rv = ARDOUR::inflate_session (session_name,
3399 Config->get_default_session_parent_dir(), session_path, session_name);
3401 MessageDialog msg (session_dialog,
3402 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3407 session_dialog.set_provided_session (session_name, session_path);
3411 // XXX check archive, inflate
3412 string::size_type suffix = session_name.find (statefile_suffix);
3414 if (suffix != string::npos) {
3415 session_name = session_name.substr (0, suffix);
3418 /* this shouldn't happen, but we catch it just in case it does */
3420 if (session_name.empty()) {
3424 if (session_dialog.use_session_template()) {
3425 template_name = session_dialog.session_template_name();
3426 _session_is_new = true;
3429 if (session_name[0] == G_DIR_SEPARATOR ||
3430 #ifdef PLATFORM_WINDOWS
3431 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3433 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3434 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3439 /* absolute path or cwd-relative path specified for session name: infer session folder
3440 from what was given.
3443 session_path = Glib::path_get_dirname (session_name);
3444 session_name = Glib::path_get_basename (session_name);
3448 session_path = session_dialog.session_folder();
3450 char illegal = Session::session_name_is_legal (session_name);
3453 MessageDialog msg (session_dialog,
3454 string_compose (_("To ensure compatibility with various systems\n"
3455 "session names may not contain a '%1' character"),
3458 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3463 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3466 if (likely_new && !nsm) {
3468 std::string existing = Glib::build_filename (session_path, session_name);
3470 if (!ask_about_loading_existing_session (existing)) {
3471 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3476 _session_is_new = false;
3481 pop_back_splash (session_dialog);
3482 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3484 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3488 char illegal = Session::session_name_is_legal(session_name);
3491 pop_back_splash (session_dialog);
3492 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3493 "session names may not contain a '%1' character"), illegal));
3495 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3499 _session_is_new = true;
3502 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3504 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3505 meta_session_setup (template_name.substr (11));
3507 } else if (likely_new && template_name.empty()) {
3509 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3513 ret = load_session (session_path, session_name, template_name);
3516 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3517 exit (EXIT_FAILURE);
3520 /* clear this to avoid endless attempts to load the
3524 ARDOUR_COMMAND_LINE::session_name = "";
3528 _session_dialog = NULL;
3534 ARDOUR_UI::close_session()
3536 if (!check_audioengine (_main_window)) {
3540 if (unload_session (true)) {
3544 ARDOUR_COMMAND_LINE::session_name = "";
3546 if (get_session_parameters (true, false)) {
3547 exit (EXIT_FAILURE);
3551 /** @param snap_name Snapshot name (without .ardour suffix).
3552 * @return -2 if the load failed because we are not connected to the AudioEngine.
3555 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3557 /* load_session calls flush_pending() which allows
3558 * GUI interaction and potentially loading another session
3559 * (that was easy via snapshot sidebar).
3560 * Recursing into load_session() from load_session() and recusive
3561 * event loops causes all kind of crashes.
3563 assert (!session_load_in_progress);
3564 if (session_load_in_progress) {
3567 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3569 Session *new_session;
3574 unload_status = unload_session ();
3576 if (unload_status < 0) {
3578 } else if (unload_status > 0) {
3584 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3587 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3590 /* this one is special */
3592 catch (AudioEngine::PortRegistrationFailure const& err) {
3594 MessageDialog msg (err.what(),
3597 Gtk::BUTTONS_CLOSE);
3599 msg.set_title (_("Port Registration Error"));
3600 msg.set_secondary_text (_("Click the Close button to try again."));
3601 msg.set_position (Gtk::WIN_POS_CENTER);
3602 pop_back_splash (msg);
3605 int response = msg.run ();
3610 case RESPONSE_CANCEL:
3611 exit (EXIT_FAILURE);
3617 catch (SessionException const& e) {
3618 MessageDialog msg (string_compose(
3619 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3620 path, snap_name, e.what()),
3625 msg.set_title (_("Loading Error"));
3626 msg.set_position (Gtk::WIN_POS_CENTER);
3627 pop_back_splash (msg);
3639 MessageDialog msg (string_compose(
3640 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3646 msg.set_title (_("Loading Error"));
3647 msg.set_position (Gtk::WIN_POS_CENTER);
3648 pop_back_splash (msg);
3660 list<string> const u = new_session->unknown_processors ();
3662 MissingPluginDialog d (_session, u);
3667 if (!new_session->writable()) {
3668 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3673 msg.set_title (_("Read-only Session"));
3674 msg.set_position (Gtk::WIN_POS_CENTER);
3675 pop_back_splash (msg);
3682 /* Now the session been created, add the transport controls */
3683 new_session->add_controllable(roll_controllable);
3684 new_session->add_controllable(stop_controllable);
3685 new_session->add_controllable(goto_start_controllable);
3686 new_session->add_controllable(goto_end_controllable);
3687 new_session->add_controllable(auto_loop_controllable);
3688 new_session->add_controllable(play_selection_controllable);
3689 new_session->add_controllable(rec_controllable);
3691 set_session (new_session);
3694 _session->set_clean ();
3697 #ifdef WINDOWS_VST_SUPPORT
3698 fst_stop_threading();
3702 Timers::TimerSuspender t;
3706 #ifdef WINDOWS_VST_SUPPORT
3707 fst_start_threading();
3711 if (!mix_template.empty ()) {
3712 /* if mix_template is given, assume this is a new session */
3713 string metascript = Glib::build_filename (mix_template, "template.lua");
3714 meta_session_setup (metascript);
3719 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3720 * which is queued by set_session().
3721 * If session-loading fails we hide it explicitly.
3722 * This covers both cases in a central place.
3731 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3733 Session *new_session;
3736 x = unload_session ();
3744 _session_is_new = true;
3747 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3750 catch (SessionException const& e) {
3751 cerr << "Here are the errors associated with this failed session:\n";
3753 cerr << "---------\n";
3754 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3755 msg.set_title (_("Loading Error"));
3756 msg.set_position (Gtk::WIN_POS_CENTER);
3757 pop_back_splash (msg);
3762 cerr << "Here are the errors associated with this failed session:\n";
3764 cerr << "---------\n";
3765 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3766 msg.set_title (_("Loading Error"));
3767 msg.set_position (Gtk::WIN_POS_CENTER);
3768 pop_back_splash (msg);
3773 /* Give the new session the default GUI state, if such things exist */
3776 n = Config->instant_xml (X_("Editor"));
3778 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3779 new_session->add_instant_xml (*n, false);
3781 n = Config->instant_xml (X_("Mixer"));
3783 new_session->add_instant_xml (*n, false);
3786 n = Config->instant_xml (X_("Preferences"));
3788 new_session->add_instant_xml (*n, false);
3791 /* Put the playhead at 0 and scroll fully left */
3792 n = new_session->instant_xml (X_("Editor"));
3794 n->set_property (X_("playhead"), X_("0"));
3795 n->set_property (X_("left-frame"), X_("0"));
3798 set_session (new_session);
3800 new_session->save_state(new_session->name());
3806 static void _lua_print (std::string s) {
3808 std::cout << "LuaInstance: " << s << "\n";
3810 PBD::info << "LuaInstance: " << s << endmsg;
3813 std::map<std::string, std::string>
3814 ARDOUR_UI::route_setup_info (const std::string& script_path)
3816 std::map<std::string, std::string> rv;
3818 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3823 lua.Print.connect (&_lua_print);
3826 lua_State* L = lua.getState();
3827 LuaInstance::register_classes (L);
3828 LuaBindings::set_session (L, _session);
3829 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3830 lua_setglobal (L, "Editor");
3832 lua.do_command ("function ardour () end");
3833 lua.do_file (script_path);
3836 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3837 if (!fn.isFunction ()) {
3840 luabridge::LuaRef rs = fn ();
3841 if (!rs.isTable ()) {
3844 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3845 if (!i.key().isString()) {
3848 std::string key = i.key().tostring();
3849 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3850 rv[key] = i.value().tostring();
3853 } catch (luabridge::LuaException const& e) {
3854 cerr << "LuaException:" << e.what () << endl;
3860 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3862 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3865 assert (add_route_dialog);
3868 if ((count = add_route_dialog->count()) <= 0) {
3873 lua.Print.connect (&_lua_print);
3876 lua_State* L = lua.getState();
3877 LuaInstance::register_classes (L);
3878 LuaBindings::set_session (L, _session);
3879 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3880 lua_setglobal (L, "Editor");
3882 lua.do_command ("function ardour () end");
3883 lua.do_file (script_path);
3885 luabridge::LuaRef args (luabridge::newTable (L));
3887 args["name"] = add_route_dialog->name_template ();
3888 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3889 args["group"] = add_route_dialog->route_group ();
3890 args["strict_io"] = add_route_dialog->use_strict_io ();
3891 args["instrument"] = add_route_dialog->requested_instrument ();
3892 args["track_mode"] = add_route_dialog->mode ();
3893 args["channels"] = add_route_dialog->channel_count ();
3894 args["how_many"] = count;
3897 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3898 if (fn.isFunction()) {
3901 } catch (luabridge::LuaException const& e) {
3902 cerr << "LuaException:" << e.what () << endl;
3904 display_insufficient_ports_message ();
3909 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3911 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3916 lua.Print.connect (&_lua_print);
3919 lua_State* L = lua.getState();
3920 LuaInstance::register_classes (L);
3921 LuaBindings::set_session (L, _session);
3922 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3923 lua_setglobal (L, "Editor");
3925 lua.do_command ("function ardour () end");
3926 lua.do_file (script_path);
3929 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3930 if (fn.isFunction()) {
3933 } catch (luabridge::LuaException const& e) {
3934 cerr << "LuaException:" << e.what () << endl;
3936 display_insufficient_ports_message ();
3941 ARDOUR_UI::launch_chat ()
3943 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3945 dialog.set_title (_("About the Chat"));
3946 dialog.set_secondary_text (_("When you're inside the chat just ask your question and wait for an answer. The chat is occupied by real people with real lives so many of them are passively online and might not read your question before minutes or hours later.\nSo please be patient and wait for an answer.\n\nYou should just leave the chat window open and check back regularly until someone has answered your question."));
3948 switch (dialog.run()) {
3950 open_uri("http://webchat.freenode.net/?channels=ardour");
3958 ARDOUR_UI::launch_manual ()
3960 PBD::open_uri (Config->get_tutorial_manual_url());
3964 ARDOUR_UI::launch_reference ()
3966 PBD::open_uri (Config->get_reference_manual_url());
3970 ARDOUR_UI::launch_tracker ()
3972 PBD::open_uri ("http://tracker.ardour.org");
3976 ARDOUR_UI::launch_subscribe ()
3978 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3982 ARDOUR_UI::launch_cheat_sheet ()
3985 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3987 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3992 ARDOUR_UI::launch_website ()
3994 PBD::open_uri ("http://ardour.org");
3998 ARDOUR_UI::launch_website_dev ()
4000 PBD::open_uri ("http://ardour.org/development.html");
4004 ARDOUR_UI::launch_forums ()
4006 PBD::open_uri ("https://community.ardour.org/forums");
4010 ARDOUR_UI::launch_howto_report ()
4012 PBD::open_uri ("http://ardour.org/reporting_bugs");
4016 ARDOUR_UI::loading_message (const std::string& msg)
4018 if (ARDOUR_COMMAND_LINE::no_splash) {
4026 splash->message (msg);
4030 ARDOUR_UI::show_splash ()
4034 splash = new Splash;
4044 ARDOUR_UI::hide_splash ()
4051 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4055 removed = rep.paths.size();
4058 MessageDialog msgd (_main_window,
4059 _("No files were ready for clean-up"),
4063 msgd.set_title (_("Clean-up"));
4064 msgd.set_secondary_text (_("If this seems surprising, \n\
4065 check for any existing snapshots.\n\
4066 These may still include regions that\n\
4067 require some unused files to continue to exist."));
4073 ArdourDialog results (_("Clean-up"), true, false);
4075 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4076 CleanupResultsModelColumns() {
4080 Gtk::TreeModelColumn<std::string> visible_name;
4081 Gtk::TreeModelColumn<std::string> fullpath;
4085 CleanupResultsModelColumns results_columns;
4086 Glib::RefPtr<Gtk::ListStore> results_model;
4087 Gtk::TreeView results_display;
4089 results_model = ListStore::create (results_columns);
4090 results_display.set_model (results_model);
4091 results_display.append_column (list_title, results_columns.visible_name);
4093 results_display.set_name ("CleanupResultsList");
4094 results_display.set_headers_visible (true);
4095 results_display.set_headers_clickable (false);
4096 results_display.set_reorderable (false);
4098 Gtk::ScrolledWindow list_scroller;
4101 Gtk::HBox dhbox; // the hbox for the image and text
4102 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4103 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4105 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4107 const string dead_directory = _session->session_directory().dead_path();
4110 %1 - number of files removed
4111 %2 - location of "dead"
4112 %3 - size of files affected
4113 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4116 const char* bprefix;
4117 double space_adjusted = 0;
4119 if (rep.space < 1000) {
4121 space_adjusted = rep.space;
4122 } else if (rep.space < 1000000) {
4123 bprefix = _("kilo");
4124 space_adjusted = floorf((float)rep.space / 1000.0);
4125 } else if (rep.space < 1000000 * 1000) {
4126 bprefix = _("mega");
4127 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4129 bprefix = _("giga");
4130 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4134 txt.set_markup (string_compose (P_("\
4135 The following file was deleted from %2,\n\
4136 releasing %3 %4bytes of disk space", "\
4137 The following %1 files were deleted from %2,\n\
4138 releasing %3 %4bytes of disk space", removed),
4139 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4141 txt.set_markup (string_compose (P_("\
4142 The following file was not in use and \n\
4143 has been moved to: %2\n\n\
4144 After a restart of %5\n\n\
4145 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4146 will release an additional %3 %4bytes of disk space.\n", "\
4147 The following %1 files were not in use and \n\
4148 have been moved to: %2\n\n\
4149 After a restart of %5\n\n\
4150 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4151 will release an additional %3 %4bytes of disk space.\n", removed),
4152 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4155 dhbox.pack_start (*dimage, true, false, 5);
4156 dhbox.pack_start (txt, true, false, 5);
4158 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4159 TreeModel::Row row = *(results_model->append());
4160 row[results_columns.visible_name] = *i;
4161 row[results_columns.fullpath] = *i;
4164 list_scroller.add (results_display);
4165 list_scroller.set_size_request (-1, 150);
4166 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4168 dvbox.pack_start (dhbox, true, false, 5);
4169 dvbox.pack_start (list_scroller, true, false, 5);
4170 ddhbox.pack_start (dvbox, true, false, 5);
4172 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4173 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4174 results.set_default_response (RESPONSE_CLOSE);
4175 results.set_position (Gtk::WIN_POS_MOUSE);
4177 results_display.show();
4178 list_scroller.show();
4185 //results.get_vbox()->show();
4186 results.set_resizable (false);
4193 ARDOUR_UI::cleanup ()
4195 if (_session == 0) {
4196 /* shouldn't happen: menu item is insensitive */
4201 MessageDialog checker (_("Are you sure you want to clean-up?"),
4203 Gtk::MESSAGE_QUESTION,
4206 checker.set_title (_("Clean-up"));
4208 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4209 ALL undo/redo information will be lost if you clean-up.\n\
4210 Clean-up will move all unused files to a \"dead\" location."));
4212 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4213 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4214 checker.set_default_response (RESPONSE_CANCEL);
4216 checker.set_name (_("CleanupDialog"));
4217 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4218 checker.set_position (Gtk::WIN_POS_MOUSE);
4220 switch (checker.run()) {
4221 case RESPONSE_ACCEPT:
4228 ARDOUR::CleanupReport rep;
4230 editor->prepare_for_cleanup ();
4232 /* do not allow flush until a session is reloaded */
4233 ActionManager::get_action (X_("Main"), X_("FlushWastebasket"))->set_sensitive (false);
4235 if (_session->cleanup_sources (rep)) {
4236 editor->finish_cleanup ();
4240 editor->finish_cleanup ();
4242 display_cleanup_results (rep, _("Cleaned Files"), false);
4246 ARDOUR_UI::flush_trash ()
4248 if (_session == 0) {
4249 /* shouldn't happen: menu item is insensitive */
4253 ARDOUR::CleanupReport rep;
4255 if (_session->cleanup_trash_sources (rep)) {
4259 display_cleanup_results (rep, _("deleted file"), true);
4263 ARDOUR_UI::cleanup_peakfiles ()
4265 if (_session == 0) {
4266 /* shouldn't happen: menu item is insensitive */
4270 if (! _session->can_cleanup_peakfiles ()) {
4274 // get all region-views in this session
4276 TrackViewList empty;
4278 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4279 std::list<RegionView*> views = rs.by_layer();
4281 // remove displayed audio-region-views waveforms
4282 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4283 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4284 if (!arv) { continue ; }
4285 arv->delete_waves();
4288 // cleanup peak files:
4289 // - stop pending peakfile threads
4290 // - close peakfiles if any
4291 // - remove peak dir in session
4292 // - setup peakfiles (background thread)
4293 _session->cleanup_peakfiles ();
4295 // re-add waves to ARV
4296 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4297 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4298 if (!arv) { continue ; }
4299 arv->create_waves();
4303 PresentationInfo::order_t
4304 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4306 if (editor->get_selection().tracks.empty()) {
4307 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4310 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4313 we want the new routes to have their order keys set starting from
4314 the highest order key in the selection + 1 (if available).
4317 if (place == RouteDialogs::AfterSelection) {
4318 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4320 order_hint = rtav->route()->presentation_info().order();
4323 } else if (place == RouteDialogs::BeforeSelection) {
4324 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4326 order_hint = rtav->route()->presentation_info().order();
4328 } else if (place == RouteDialogs::First) {
4331 /* leave order_hint at max_order */
4338 ARDOUR_UI::start_duplicate_routes ()
4340 if (!duplicate_routes_dialog) {
4341 duplicate_routes_dialog = new DuplicateRouteDialog;
4344 if (duplicate_routes_dialog->restart (_session)) {
4348 duplicate_routes_dialog->present ();
4352 ARDOUR_UI::add_route ()
4354 if (!add_route_dialog.get (false)) {
4355 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4362 if (add_route_dialog->is_visible()) {
4363 /* we're already doing this */
4367 add_route_dialog->set_position (WIN_POS_MOUSE);
4368 add_route_dialog->present();
4372 ARDOUR_UI::add_route_dialog_response (int r)
4375 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4379 if (!AudioEngine::instance()->running ()) {
4381 case AddRouteDialog::Add:
4382 case AddRouteDialog::AddAndClose:
4387 add_route_dialog->ArdourDialog::on_response (r);
4388 ARDOUR_UI_UTILS::engine_is_running ();
4395 case AddRouteDialog::Add:
4396 add_route_dialog->reset_name_edited ();
4398 case AddRouteDialog::AddAndClose:
4399 add_route_dialog->ArdourDialog::on_response (r);
4402 add_route_dialog->ArdourDialog::on_response (r);
4406 std::string template_path = add_route_dialog->get_template_path();
4407 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4408 meta_route_setup (template_path.substr (11));
4412 if ((count = add_route_dialog->count()) <= 0) {
4416 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4417 const string name_template = add_route_dialog->name_template ();
4418 DisplaySuspender ds;
4420 if (!template_path.empty ()) {
4421 if (add_route_dialog->name_template_is_default ()) {
4422 _session->new_route_from_template (count, order, template_path, string ());
4424 _session->new_route_from_template (count, order, template_path, name_template);
4429 ChanCount input_chan= add_route_dialog->channels ();
4430 ChanCount output_chan;
4431 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4432 RouteGroup* route_group = add_route_dialog->route_group ();
4433 AutoConnectOption oac = Config->get_output_auto_connect();
4434 bool strict_io = add_route_dialog->use_strict_io ();
4436 if (oac & AutoConnectMaster) {
4437 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4438 output_chan.set (DataType::MIDI, 0);
4440 output_chan = input_chan;
4443 /* XXX do something with name template */
4445 Session::ProcessorChangeBlocker pcb (_session);
4447 switch (add_route_dialog->type_wanted()) {
4448 case AddRouteDialog::AudioTrack:
4449 session_add_audio_route (true, input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4451 case AddRouteDialog::MidiTrack:
4452 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4454 case AddRouteDialog::MixedTrack:
4455 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4457 case AddRouteDialog::AudioBus:
4458 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4460 case AddRouteDialog::MidiBus:
4461 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4463 case AddRouteDialog::VCAMaster:
4464 _session->vca_manager().create_vca (count, name_template);
4466 case AddRouteDialog::FoldbackBus:
4467 session_add_foldback_bus (input_chan.n_audio(), count, name_template);
4473 ARDOUR_UI::stop_video_server (bool ask_confirm)
4475 if (!video_server_process && ask_confirm) {
4476 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4478 if (video_server_process) {
4480 ArdourDialog confirm (_("Stop Video-Server"), true);
4481 Label m (_("Do you really want to stop the Video Server?"));
4482 confirm.get_vbox()->pack_start (m, true, true);
4483 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4484 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4485 confirm.show_all ();
4486 if (confirm.run() == RESPONSE_CANCEL) {
4490 delete video_server_process;
4491 video_server_process =0;
4496 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4498 ARDOUR_UI::start_video_server( float_window, true);
4502 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4508 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4509 if (video_server_process) {
4510 popup_error(_("The Video Server is already started."));
4512 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4518 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4520 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4522 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4524 video_server_dialog->set_transient_for (*float_window);
4527 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4528 video_server_dialog->hide();
4530 ResponseType r = (ResponseType) video_server_dialog->run ();
4531 video_server_dialog->hide();
4532 if (r != RESPONSE_ACCEPT) { return false; }
4533 if (video_server_dialog->show_again()) {
4534 Config->set_show_video_server_dialog(false);
4538 std::string icsd_exec = video_server_dialog->get_exec_path();
4539 std::string icsd_docroot = video_server_dialog->get_docroot();
4540 #ifndef PLATFORM_WINDOWS
4541 if (icsd_docroot.empty()) {
4542 icsd_docroot = VideoUtils::video_get_docroot (Config);
4547 #ifdef PLATFORM_WINDOWS
4548 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4549 /* OK, allow all drive letters */
4552 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4553 warning << _("Specified docroot is not an existing directory.") << endmsg;
4556 #ifndef PLATFORM_WINDOWS
4557 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4558 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4559 warning << _("Given Video Server is not an executable file.") << endmsg;
4563 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4564 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4565 warning << _("Given Video Server is not an executable file.") << endmsg;
4571 argp=(char**) calloc(9,sizeof(char*));
4572 argp[0] = strdup(icsd_exec.c_str());
4573 argp[1] = strdup("-P");
4574 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4575 argp[3] = strdup("-p");
4576 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4577 argp[5] = strdup("-C");
4578 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4579 argp[7] = strdup(icsd_docroot.c_str());
4581 stop_video_server();
4583 #ifdef PLATFORM_WINDOWS
4584 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4585 /* OK, allow all drive letters */
4588 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4589 Config->set_video_advanced_setup(false);
4591 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4592 Config->set_video_server_url(url_str);
4593 Config->set_video_server_docroot(icsd_docroot);
4594 Config->set_video_advanced_setup(true);
4597 if (video_server_process) {
4598 delete video_server_process;
4601 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4602 if (video_server_process->start()) {
4603 warning << _("Cannot launch the video-server") << endmsg;
4606 int timeout = 120; // 6 sec
4607 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4608 Glib::usleep (50000);
4610 if (--timeout <= 0 || !video_server_process->is_running()) break;
4613 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4615 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4616 delete video_server_process;
4617 video_server_process = 0;
4625 ARDOUR_UI::add_video (Gtk::Window* float_window)
4631 if (!start_video_server(float_window, false)) {
4632 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4637 add_video_dialog->set_transient_for (*float_window);
4640 if (add_video_dialog->is_visible()) {
4641 /* we're already doing this */
4645 ResponseType r = (ResponseType) add_video_dialog->run ();
4646 add_video_dialog->hide();
4647 if (r != RESPONSE_ACCEPT) { return; }
4649 bool local_file, orig_local_file;
4650 std::string path = add_video_dialog->file_name(local_file);
4652 std::string orig_path = path;
4653 orig_local_file = local_file;
4655 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4657 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4658 warning << string_compose(_("could not open %1"), path) << endmsg;
4661 if (!local_file && path.length() == 0) {
4662 warning << _("no video-file selected") << endmsg;
4666 std::string audio_from_video;
4667 bool detect_ltc = false;
4669 switch (add_video_dialog->import_option()) {
4670 case VTL_IMPORT_TRANSCODE:
4672 TranscodeVideoDialog *transcode_video_dialog;
4673 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4674 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4675 transcode_video_dialog->hide();
4676 if (r != RESPONSE_ACCEPT) {
4677 delete transcode_video_dialog;
4681 audio_from_video = transcode_video_dialog->get_audiofile();
4683 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4686 else if (!audio_from_video.empty()) {
4687 editor->embed_audio_from_video(
4689 video_timeline->get_offset(),
4690 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4693 switch (transcode_video_dialog->import_option()) {
4694 case VTL_IMPORT_TRANSCODED:
4695 path = transcode_video_dialog->get_filename();
4698 case VTL_IMPORT_REFERENCE:
4701 delete transcode_video_dialog;
4704 delete transcode_video_dialog;
4708 case VTL_IMPORT_NONE:
4712 /* strip _session->session_directory().video_path() from video file if possible */
4713 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4714 path=path.substr(_session->session_directory().video_path().size());
4715 if (path.at(0) == G_DIR_SEPARATOR) {
4716 path=path.substr(1);
4720 video_timeline->set_update_session_fps(auto_set_session_fps);
4722 if (video_timeline->video_file_info(path, local_file)) {
4723 XMLNode* node = new XMLNode(X_("Videotimeline"));
4724 node->set_property (X_("Filename"), path);
4725 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4726 node->set_property (X_("LocalFile"), local_file);
4727 if (orig_local_file) {
4728 node->set_property (X_("OriginalVideoFile"), orig_path);
4730 node->remove_property (X_("OriginalVideoFile"));
4732 _session->add_extra_xml (*node);
4733 _session->set_dirty ();
4735 if (!audio_from_video.empty() && detect_ltc) {
4736 std::vector<LTCFileReader::LTCMap> ltc_seq;
4739 /* TODO ask user about TV standard (LTC alignment if any) */
4740 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4741 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4743 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4745 /* TODO seek near end of file, and read LTC until end.
4746 * if it fails to find any LTC samples, scan complete file
4748 * calculate drift of LTC compared to video-duration,
4749 * ask user for reference (timecode from start/mid/end)
4752 // LTCFileReader will have written error messages
4755 ::g_unlink(audio_from_video.c_str());
4757 if (ltc_seq.size() == 0) {
4758 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4760 /* the very first TC in the file is somteimes not aligned properly */
4761 int i = ltc_seq.size() -1;
4762 ARDOUR::sampleoffset_t video_start_offset =
4763 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4764 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4765 video_timeline->set_offset(video_start_offset);
4769 _session->maybe_update_session_range(
4770 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4771 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4774 if (add_video_dialog->launch_xjadeo() && local_file) {
4775 editor->set_xjadeo_sensitive(true);
4776 editor->toggle_xjadeo_proc(1);
4778 editor->toggle_xjadeo_proc(0);
4780 editor->toggle_ruler_video(true);
4785 ARDOUR_UI::remove_video ()
4787 video_timeline->close_session();
4788 editor->toggle_ruler_video(false);
4791 video_timeline->set_offset_locked(false);
4792 video_timeline->set_offset(0);
4794 /* delete session state */
4795 XMLNode* node = new XMLNode(X_("Videotimeline"));
4796 _session->add_extra_xml(*node);
4797 node = new XMLNode(X_("Videomonitor"));
4798 _session->add_extra_xml(*node);
4799 node = new XMLNode(X_("Videoexport"));
4800 _session->add_extra_xml(*node);
4801 stop_video_server();
4805 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4807 if (localcacheonly) {
4808 video_timeline->vmon_update();
4810 video_timeline->flush_cache();
4812 editor->queue_visual_videotimeline_update();
4816 ARDOUR_UI::export_video (bool range)
4818 if (ARDOUR::Config->get_show_video_export_info()) {
4819 ExportVideoInfobox infobox (_session);
4820 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4821 if (infobox.show_again()) {
4822 ARDOUR::Config->set_show_video_export_info(false);
4825 case GTK_RESPONSE_YES:
4826 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4832 export_video_dialog->set_session (_session);
4833 export_video_dialog->apply_state(editor->get_selection().time, range);
4834 export_video_dialog->run ();
4835 export_video_dialog->hide ();
4839 ARDOUR_UI::preferences_settings () const
4844 node = _session->instant_xml(X_("Preferences"));
4846 node = Config->instant_xml(X_("Preferences"));
4850 node = new XMLNode (X_("Preferences"));
4857 ARDOUR_UI::mixer_settings () const
4862 node = _session->instant_xml(X_("Mixer"));
4864 node = Config->instant_xml(X_("Mixer"));
4868 node = new XMLNode (X_("Mixer"));
4875 ARDOUR_UI::main_window_settings () const
4880 node = _session->instant_xml(X_("Main"));
4882 node = Config->instant_xml(X_("Main"));
4886 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4887 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4892 node = new XMLNode (X_("Main"));
4899 ARDOUR_UI::editor_settings () const
4904 node = _session->instant_xml(X_("Editor"));
4906 node = Config->instant_xml(X_("Editor"));
4910 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4911 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4916 node = new XMLNode (X_("Editor"));
4923 ARDOUR_UI::keyboard_settings () const
4927 node = Config->extra_xml(X_("Keyboard"));
4930 node = new XMLNode (X_("Keyboard"));
4937 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4940 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4941 _session->locations()->add (location);
4946 ARDOUR_UI::halt_on_xrun_message ()
4948 cerr << "HALT on xrun\n";
4949 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4954 ARDOUR_UI::xrun_handler (samplepos_t where)
4960 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4962 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4963 create_xrun_marker(where);
4966 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4967 halt_on_xrun_message ();
4972 ARDOUR_UI::disk_overrun_handler ()
4974 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4976 if (!have_disk_speed_dialog_displayed) {
4977 have_disk_speed_dialog_displayed = true;
4978 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4979 The disk system on your computer\n\
4980 was not able to keep up with %1.\n\
4982 Specifically, it failed to write data to disk\n\
4983 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4984 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4990 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4991 static MessageDialog *scan_dlg = NULL;
4992 static ProgressBar *scan_pbar = NULL;
4993 static HBox *scan_tbox = NULL;
4994 static Gtk::Button *scan_timeout_button;
4997 ARDOUR_UI::cancel_plugin_scan ()
4999 PluginManager::instance().cancel_plugin_scan();
5003 ARDOUR_UI::cancel_plugin_timeout ()
5005 PluginManager::instance().cancel_plugin_timeout();
5006 scan_timeout_button->set_sensitive (false);
5010 ARDOUR_UI::plugin_scan_timeout (int timeout)
5012 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5016 scan_pbar->set_sensitive (false);
5017 scan_timeout_button->set_sensitive (true);
5018 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5021 scan_pbar->set_sensitive (false);
5022 scan_timeout_button->set_sensitive (false);
5028 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5030 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5034 const bool cancelled = PluginManager::instance().cancelled();
5035 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5036 if (cancelled && scan_dlg->is_mapped()) {
5041 if (cancelled || !can_cancel) {
5046 static Gtk::Button *cancel_button;
5048 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5049 VBox* vbox = scan_dlg->get_vbox();
5050 vbox->set_size_request(400,-1);
5051 scan_dlg->set_title (_("Scanning for plugins"));
5053 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5054 cancel_button->set_name ("EditorGTKButton");
5055 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5056 cancel_button->show();
5058 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5060 scan_tbox = manage( new HBox() );
5062 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5063 scan_timeout_button->set_name ("EditorGTKButton");
5064 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5065 scan_timeout_button->show();
5067 scan_pbar = manage(new ProgressBar());
5068 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5069 scan_pbar->set_text(_("Scan Timeout"));
5072 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5073 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5075 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5078 assert(scan_dlg && scan_tbox && cancel_button);
5080 if (type == X_("closeme")) {
5084 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5087 if (!can_cancel || !cancelled) {
5088 scan_timeout_button->set_sensitive(false);
5090 cancel_button->set_sensitive(can_cancel && !cancelled);
5096 ARDOUR_UI::gui_idle_handler ()
5099 /* due to idle calls, gtk_events_pending() may always return true */
5100 while (gtk_events_pending() && --timeout) {
5101 gtk_main_iteration ();
5106 ARDOUR_UI::disk_underrun_handler ()
5108 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5110 if (!have_disk_speed_dialog_displayed) {
5111 have_disk_speed_dialog_displayed = true;
5112 MessageDialog* msg = new MessageDialog (
5113 _main_window, string_compose (_("The disk system on your computer\n\
5114 was not able to keep up with %1.\n\
5116 Specifically, it failed to read data from disk\n\
5117 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5118 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5124 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5126 have_disk_speed_dialog_displayed = false;
5131 ARDOUR_UI::session_dialog (std::string msg)
5133 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5137 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5144 ARDOUR_UI::pending_state_dialog ()
5146 HBox* hbox = manage (new HBox());
5147 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5148 ArdourDialog dialog (_("Crash Recovery"), true);
5149 Label message (string_compose (_("\
5150 This session appears to have been in the\n\
5151 middle of recording when %1 or\n\
5152 the computer was shutdown.\n\
5154 %1 can recover any captured audio for\n\
5155 you, or it can ignore it. Please decide\n\
5156 what you would like to do.\n"), PROGRAM_NAME));
5157 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5158 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5159 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5160 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5161 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5162 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5163 dialog.set_default_response (RESPONSE_ACCEPT);
5164 dialog.set_position (WIN_POS_CENTER);
5169 switch (dialog.run ()) {
5170 case RESPONSE_ACCEPT:
5178 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5180 HBox* hbox = new HBox();
5181 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5182 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5183 Label message (string_compose (_("\
5184 This session was created with a sample rate of %1 Hz, but\n\
5185 %2 is currently running at %3 Hz. If you load this session,\n\
5186 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5188 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5189 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5190 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5191 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5192 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5193 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5194 dialog.set_default_response (RESPONSE_ACCEPT);
5195 dialog.set_position (WIN_POS_CENTER);
5200 switch (dialog.run()) {
5201 case RESPONSE_ACCEPT:
5211 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5213 MessageDialog msg (string_compose (_("\
5214 This session was created with a sample rate of %1 Hz, but\n\
5215 %2 is currently running at %3 Hz.\n\
5216 Audio will be recorded and played at the wrong sample rate.\n\
5217 Re-Configure the Audio Engine in\n\
5218 Menu > Window > Audio/Midi Setup"),
5219 desired, PROGRAM_NAME, actual),
5221 Gtk::MESSAGE_WARNING);
5226 ARDOUR_UI::use_config ()
5228 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5230 set_transport_controllable_state (*node);
5235 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5237 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5239 primary_clock->set (pos);
5241 case DeltaEditPoint:
5242 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5244 case DeltaOriginMarker:
5246 Location* loc = _session->locations()->clock_origin_location ();
5247 primary_clock->set (pos, false, loc ? loc->start() : 0);
5252 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5254 secondary_clock->set (pos);
5256 case DeltaEditPoint:
5257 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5259 case DeltaOriginMarker:
5261 Location* loc = _session->locations()->clock_origin_location ();
5262 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5267 if (big_clock_window) {
5268 big_clock->set (pos);
5270 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5275 ARDOUR_UI::record_state_changed ()
5277 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5280 /* why bother - the clock isn't visible */
5284 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5286 if (big_clock_window) {
5287 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5288 big_clock->set_active (true);
5290 big_clock->set_active (false);
5297 ARDOUR_UI::first_idle ()
5300 _session->allow_auto_play (true);
5304 editor->first_idle();
5307 /* in 1 second, hide the splash screen
5309 * Consider hiding it *now*. If a user opens opens a dialog
5310 * during that one second while the splash is still visible,
5311 * the dialog will push-back the splash.
5312 * Closing the dialog later will pop it back.
5314 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5316 Keyboard::set_can_save_keybindings (true);
5321 ARDOUR_UI::store_clock_modes ()
5323 XMLNode* node = new XMLNode(X_("ClockModes"));
5325 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5326 XMLNode* child = new XMLNode (X_("Clock"));
5328 child->set_property (X_("name"), (*x)->name());
5329 child->set_property (X_("mode"), (*x)->mode());
5330 child->set_property (X_("on"), (*x)->on());
5332 node->add_child_nocopy (*child);
5335 _session->add_extra_xml (*node);
5336 _session->set_dirty ();
5340 ARDOUR_UI::setup_profile ()
5342 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5343 Profile->set_small_screen ();
5346 if (g_getenv ("TRX")) {
5347 Profile->set_trx ();
5350 if (g_getenv ("MIXBUS")) {
5351 Profile->set_mixbus ();
5356 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5358 MissingFileDialog dialog (s, str, type);
5363 int result = dialog.run ();
5370 return 1; // quit entire session load
5373 result = dialog.get_action ();
5379 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5381 AmbiguousFileDialog dialog (file, hits);
5388 return dialog.get_which ();
5391 /** Allocate our thread-local buffers */
5393 ARDOUR_UI::get_process_buffers ()
5395 _process_thread->get_buffers ();
5398 /** Drop our thread-local buffers */
5400 ARDOUR_UI::drop_process_buffers ()
5402 _process_thread->drop_buffers ();
5406 ARDOUR_UI::feedback_detected ()
5408 _feedback_exists = true;
5412 ARDOUR_UI::successful_graph_sort ()
5414 _feedback_exists = false;
5418 ARDOUR_UI::midi_panic ()
5421 _session->midi_panic();
5426 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5428 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5429 const char* end_big = "</span>";
5430 const char* start_mono = "<tt>";
5431 const char* end_mono = "</tt>";
5433 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5434 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5435 "From now on, use the backup copy with older versions of %3"),
5436 xml_path, backup_path, PROGRAM_NAME,
5438 start_mono, end_mono), true);
5444 ARDOUR_UI::reset_peak_display ()
5446 if (!_session || !_session->master_out() || !editor_meter) return;
5447 editor_meter->clear_meters();
5448 editor_meter_max_peak = -INFINITY;
5449 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5453 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5455 if (!_session || !_session->master_out()) return;
5456 if (group == _session->master_out()->route_group()) {
5457 reset_peak_display ();
5462 ARDOUR_UI::reset_route_peak_display (Route* route)
5464 if (!_session || !_session->master_out()) return;
5465 if (_session->master_out().get() == route) {
5466 reset_peak_display ();
5471 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5473 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5474 audio_midi_setup->set_position (WIN_POS_CENTER);
5476 if (desired_sample_rate != 0) {
5477 if (Config->get_try_autostart_engine () || g_getenv ("ARDOUR_TRY_AUTOSTART_ENGINE")) {
5478 audio_midi_setup->try_autostart ();
5479 if (ARDOUR::AudioEngine::instance()->running()) {
5486 int response = audio_midi_setup->run();
5488 case Gtk::RESPONSE_DELETE_EVENT:
5489 // after latency callibration engine may run,
5490 // Running() signal was emitted, but dialog will not
5491 // have emitted a response. The user needs to close
5492 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5493 if (!AudioEngine::instance()->running()) {
5498 if (!AudioEngine::instance()->running()) {
5501 audio_midi_setup->hide ();
5509 ARDOUR_UI::transport_numpad_timeout ()
5511 _numpad_locate_happening = false;
5512 if (_numpad_timeout_connection.connected() )
5513 _numpad_timeout_connection.disconnect();
5518 ARDOUR_UI::transport_numpad_decimal ()
5520 _numpad_timeout_connection.disconnect();
5522 if (_numpad_locate_happening) {
5523 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5524 _numpad_locate_happening = false;
5526 _pending_locate_num = 0;
5527 _numpad_locate_happening = true;
5528 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5533 ARDOUR_UI::transport_numpad_event (int num)
5535 if ( _numpad_locate_happening ) {
5536 _pending_locate_num = _pending_locate_num*10 + num;
5539 case 0: toggle_roll(false, false); break;
5540 case 1: transport_rewind(1); break;
5541 case 2: transport_forward(1); break;
5542 case 3: transport_record(true); break;
5543 case 4: toggle_session_auto_loop(); break;
5544 case 5: transport_record(false); toggle_session_auto_loop(); break;
5545 case 6: toggle_punch(); break;
5546 case 7: toggle_click(); break;
5547 case 8: toggle_auto_return(); break;
5548 case 9: toggle_follow_edits(); break;
5554 ARDOUR_UI::set_flat_buttons ()
5556 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5560 ARDOUR_UI::audioengine_became_silent ()
5562 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5564 Gtk::MESSAGE_WARNING,
5568 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5570 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5571 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5572 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5573 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5574 Gtk::HBox pay_button_box;
5575 Gtk::HBox subscribe_button_box;
5577 pay_button_box.pack_start (pay_button, true, false);
5578 subscribe_button_box.pack_start (subscribe_button, true, false);
5580 bool (*openuri)(const char*) = PBD::open_uri; /* this forces selection of the const char* variant of PBD::open_uri(), which we need to avoid ambiguity below */
5582 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5583 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5585 msg.get_vbox()->pack_start (pay_label);
5586 msg.get_vbox()->pack_start (pay_button_box);
5587 msg.get_vbox()->pack_start (subscribe_label);
5588 msg.get_vbox()->pack_start (subscribe_button_box);
5590 msg.get_vbox()->show_all ();
5592 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5593 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5594 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5599 case Gtk::RESPONSE_YES:
5600 AudioEngine::instance()->reset_silence_countdown ();
5603 case Gtk::RESPONSE_NO:
5605 save_state_canfail ("");
5606 exit (EXIT_SUCCESS);
5609 case Gtk::RESPONSE_CANCEL:
5611 /* don't reset, save session and exit */
5617 ARDOUR_UI::hide_application ()
5619 Application::instance ()-> hide ();
5623 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5625 /* icons, titles, WM stuff */
5627 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5629 if (window_icons.empty()) {
5630 Glib::RefPtr<Gdk::Pixbuf> icon;
5631 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5632 window_icons.push_back (icon);
5634 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5635 window_icons.push_back (icon);
5637 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5638 window_icons.push_back (icon);
5640 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5641 window_icons.push_back (icon);
5645 if (!window_icons.empty()) {
5646 window.set_default_icon_list (window_icons);
5649 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5651 if (!name.empty()) {
5655 window.set_title (title.get_string());
5656 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5658 window.set_flags (CAN_FOCUS);
5659 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5661 /* This is a hack to ensure that GTK-accelerators continue to
5662 * work. Once we switch over to entirely native bindings, this will be
5663 * unnecessary and should be removed
5665 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5667 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5668 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5669 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5670 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5674 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5676 Gtkmm2ext::Bindings* bindings = 0;
5677 Gtk::Window* window = 0;
5679 /* until we get ardour bindings working, we are not handling key
5683 if (ev->type != GDK_KEY_PRESS) {
5687 if (event_window == &_main_window) {
5689 window = event_window;
5691 /* find current tab contents */
5693 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5695 /* see if it uses the ardour binding system */
5698 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5701 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5705 window = event_window;
5707 /* see if window uses ardour binding system */
5709 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5712 /* An empty binding set is treated as if it doesn't exist */
5714 if (bindings && bindings->empty()) {
5718 return key_press_focus_accelerator_handler (*window, ev, bindings);
5721 static Gtkmm2ext::Bindings*
5722 get_bindings_from_widget_heirarchy (GtkWidget** w)
5727 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5730 *w = gtk_widget_get_parent (*w);
5733 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5737 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5739 GtkWindow* win = window.gobj();
5740 GtkWidget* focus = gtk_window_get_focus (win);
5741 GtkWidget* binding_widget = focus;
5742 bool special_handling_of_unmodified_accelerators = false;
5743 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5747 /* some widget has keyboard focus */
5749 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5751 /* A particular kind of focusable widget currently has keyboard
5752 * focus. All unmodified key events should go to that widget
5753 * first and not be used as an accelerator by default
5756 special_handling_of_unmodified_accelerators = true;
5760 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5761 if (focus_bindings) {
5762 bindings = focus_bindings;
5763 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5768 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
5771 Gtkmm2ext::show_gdk_event_state (ev->state),
5772 special_handling_of_unmodified_accelerators,
5773 Keyboard::some_magic_widget_has_focus(),
5775 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5776 ((ev->state & mask) ? "yes" : "no"),
5777 window.get_title()));
5779 /* This exists to allow us to override the way GTK handles
5780 key events. The normal sequence is:
5782 a) event is delivered to a GtkWindow
5783 b) accelerators/mnemonics are activated
5784 c) if (b) didn't handle the event, propagate to
5785 the focus widget and/or focus chain
5787 The problem with this is that if the accelerators include
5788 keys without modifiers, such as the space bar or the
5789 letter "e", then pressing the key while typing into
5790 a text entry widget results in the accelerator being
5791 activated, instead of the desired letter appearing
5794 There is no good way of fixing this, but this
5795 represents a compromise. The idea is that
5796 key events involving modifiers (not Shift)
5797 get routed into the activation pathway first, then
5798 get propagated to the focus widget if necessary.
5800 If the key event doesn't involve modifiers,
5801 we deliver to the focus widget first, thus allowing
5802 it to get "normal text" without interference
5805 Of course, this can also be problematic: if there
5806 is a widget with focus, then it will swallow
5807 all "normal text" accelerators.
5811 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5813 /* no special handling or there are modifiers in effect: accelerate first */
5815 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5816 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5817 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5819 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5820 KeyboardKey k (ev->state, ev->keyval);
5824 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5826 if (bindings->activate (k, Bindings::Press)) {
5827 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5831 if (binding_widget) {
5832 binding_widget = gtk_widget_get_parent (binding_widget);
5833 if (binding_widget) {
5834 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5843 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5845 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5846 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5850 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5852 if (gtk_window_propagate_key_event (win, ev)) {
5853 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5859 /* no modifiers, propagate first */
5861 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5863 if (gtk_window_propagate_key_event (win, ev)) {
5864 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5868 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5869 KeyboardKey k (ev->state, ev->keyval);
5873 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5876 if (bindings->activate (k, Bindings::Press)) {
5877 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5881 if (binding_widget) {
5882 binding_widget = gtk_widget_get_parent (binding_widget);
5883 if (binding_widget) {
5884 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5893 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5895 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5896 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5901 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5906 ARDOUR_UI::cancel_solo ()
5909 _session->cancel_all_solo ();
5914 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5916 /* this resets focus to the first focusable parent of the given widget,
5917 * or, if there is no focusable parent, cancels focus in the toplevel
5918 * window that the given widget is packed into (if there is one).
5925 Gtk::Widget* top = w->get_toplevel();
5927 if (!top || !top->is_toplevel()) {
5931 w = w->get_parent ();
5935 if (w->is_toplevel()) {
5936 /* Setting the focus widget to a Gtk::Window causes all
5937 * subsequent calls to ::has_focus() on the nominal
5938 * focus widget in that window to return
5939 * false. Workaround: never set focus to the toplevel
5945 if (w->get_can_focus ()) {
5946 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5947 win->set_focus (*w);
5950 w = w->get_parent ();
5953 if (top == &_main_window) {
5957 /* no focusable parent found, cancel focus in top level window.
5958 C++ API cannot be used for this. Thanks, references.
5961 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
5966 ARDOUR_UI::monitor_dim_all ()
5968 boost::shared_ptr<Route> mon = _session->monitor_out ();
5972 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5974 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
5975 _monitor->set_dim_all (tact->get_active());
5979 ARDOUR_UI::monitor_cut_all ()
5981 boost::shared_ptr<Route> mon = _session->monitor_out ();
5985 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5987 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
5988 _monitor->set_cut_all (tact->get_active());
5992 ARDOUR_UI::monitor_mono ()
5994 boost::shared_ptr<Route> mon = _session->monitor_out ();
5998 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6000 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
6001 _monitor->set_mono (tact->get_active());
6005 ARDOUR_UI::shared_popup_menu ()
6007 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::shared_popup_menu, ignored);
6009 assert (!_shared_popup_menu || !_shared_popup_menu->is_visible());
6010 delete _shared_popup_menu;
6011 _shared_popup_menu = new Gtk::Menu;
6012 return _shared_popup_menu;