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 /* lets get this party started */
476 setup_gtk_ardour_enums ();
479 SessionEvent::create_per_thread_pool ("GUI", 4096);
481 UIConfiguration::instance().reset_dpi ();
483 TimeAxisViewItem::set_constant_heights ();
485 /* The following must happen after ARDOUR::init() so that Config is set up */
487 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
490 key_editor.set_state (*ui_xml, 0);
491 session_option_editor.set_state (*ui_xml, 0);
492 speaker_config_window.set_state (*ui_xml, 0);
493 about.set_state (*ui_xml, 0);
494 add_route_dialog.set_state (*ui_xml, 0);
495 add_video_dialog.set_state (*ui_xml, 0);
496 route_params.set_state (*ui_xml, 0);
497 bundle_manager.set_state (*ui_xml, 0);
498 location_ui.set_state (*ui_xml, 0);
499 big_clock_window.set_state (*ui_xml, 0);
500 big_transport_window.set_state (*ui_xml, 0);
501 audio_port_matrix.set_state (*ui_xml, 0);
502 midi_port_matrix.set_state (*ui_xml, 0);
503 export_video_dialog.set_state (*ui_xml, 0);
504 lua_script_window.set_state (*ui_xml, 0);
505 idleometer.set_state (*ui_xml, 0);
506 plugin_dsp_load_window.set_state (*ui_xml, 0);
507 transport_masters_window.set_state (*ui_xml, 0);
510 /* Separate windows */
512 WM::Manager::instance().register_window (&key_editor);
513 WM::Manager::instance().register_window (&session_option_editor);
514 WM::Manager::instance().register_window (&speaker_config_window);
515 WM::Manager::instance().register_window (&about);
516 WM::Manager::instance().register_window (&add_route_dialog);
517 WM::Manager::instance().register_window (&add_video_dialog);
518 WM::Manager::instance().register_window (&route_params);
519 WM::Manager::instance().register_window (&audio_midi_setup);
520 WM::Manager::instance().register_window (&export_video_dialog);
521 WM::Manager::instance().register_window (&lua_script_window);
522 WM::Manager::instance().register_window (&bundle_manager);
523 WM::Manager::instance().register_window (&location_ui);
524 WM::Manager::instance().register_window (&big_clock_window);
525 WM::Manager::instance().register_window (&big_transport_window);
526 WM::Manager::instance().register_window (&audio_port_matrix);
527 WM::Manager::instance().register_window (&midi_port_matrix);
528 WM::Manager::instance().register_window (&idleometer);
529 WM::Manager::instance().register_window (&plugin_dsp_load_window);
530 WM::Manager::instance().register_window (&transport_masters_window);
532 /* do not retain position for add route dialog */
533 add_route_dialog.set_state_mask (WindowProxy::Size);
535 /* Trigger setting up the color scheme and loading the GTK RC file */
537 UIConfiguration::instance().load_rc_file (false);
539 _process_thread = new ProcessThread ();
540 _process_thread->init ();
542 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
548 ARDOUR_UI::pre_release_dialog ()
550 ArdourDialog d (_("Pre-Release Warning"), true, false);
551 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
553 Label* label = manage (new Label);
554 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
555 There are still several issues and bugs to be worked on,\n\
556 as well as general workflow improvements, before this can be considered\n\
557 release software. So, a few guidelines:\n\
559 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
560 though it may be so, depending on your workflow.\n\
561 2) Please wait for a helpful writeup of new features.\n\
562 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
563 4) <b>Please do NOT file bugs for this alpha-development versions at this point in time</b>.\n\
564 There is no bug triaging before the initial development concludes and\n\
565 reporting issue for incomplete, ongoing work-in-progress is mostly useless.\n\
566 5) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
567 can get there directly from within the program via the Help->Chat menu option.\n\
568 6) Please <b>DO</b> submit patches for issues after discussing them on IRC.\n\
570 Full information on all the above can be found on the support page at\n\
572 http://ardour.org/support\n\
573 "), PROGRAM_NAME, VERSIONSTRING));
575 d.get_vbox()->set_border_width (12);
576 d.get_vbox()->pack_start (*label, false, false, 12);
577 d.get_vbox()->show_all ();
582 GlobalPortMatrixWindow*
583 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
588 return new GlobalPortMatrixWindow (_session, type);
592 ARDOUR_UI::attach_to_engine ()
594 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this, _1), gui_context());
595 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
599 ARDOUR_UI::engine_stopped ()
601 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
602 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
603 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
604 update_sample_rate (0);
609 ARDOUR_UI::engine_running (uint32_t cnt)
616 _session->reset_xrun_count ();
618 update_disk_space ();
620 update_sample_rate (AudioEngine::instance()->sample_rate());
621 update_timecode_format ();
622 update_peak_thread_work ();
623 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
624 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
628 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
630 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
631 /* we can't rely on the original string continuing to exist when we are called
632 again in the GUI thread, so make a copy and note that we need to
635 char *copy = strdup (reason);
636 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
640 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
641 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
643 update_sample_rate (0);
647 /* if the reason is a non-empty string, it means that the backend was shutdown
648 rather than just Ardour.
651 if (strlen (reason)) {
652 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
654 msgstr = string_compose (_("\
655 The audio backend has either been shutdown or it\n\
656 disconnected %1 because %1\n\
657 was not fast enough. Try to restart\n\
658 the audio backend and save the session."), PROGRAM_NAME);
661 MessageDialog msg (_main_window, msgstr);
662 pop_back_splash (msg);
666 free (const_cast<char*> (reason));
671 ARDOUR_UI::post_engine ()
673 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
675 #ifdef AUDIOUNIT_SUPPORT
677 if (AUPluginInfo::au_get_crashlog(au_msg)) {
678 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
679 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
680 info << au_msg << endmsg;
684 /* connect to important signals */
686 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
687 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
688 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
689 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
690 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
692 if (setup_windows ()) {
693 throw failed_constructor ();
696 transport_ctrl.map_actions ();
698 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
699 XMLNode* n = Config->extra_xml (X_("UI"));
701 _status_bar_visibility.set_state (*n);
704 check_memory_locking();
706 /* this is the first point at which all the possible actions are
707 * available, because some of the available actions are dependent on
708 * aspects of the engine/backend.
711 if (ARDOUR_COMMAND_LINE::show_key_actions) {
713 Bindings::save_all_bindings_as_html (sstr);
715 if (sstr.str().empty()) {
722 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
724 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
730 #ifdef PLATFORM_WINDOWS
736 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
737 #ifndef PLATFORM_WINDOWS
740 g_unlink (file_name);
742 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
748 #ifndef PLATFORM_WINDOWS
752 PBD::open_uri (string_compose ("file:///%1", file_name));
754 halt_connection.disconnect ();
755 AudioEngine::instance()->stop ();
760 if (ARDOUR_COMMAND_LINE::show_actions) {
763 vector<string> paths;
764 vector<string> labels;
765 vector<string> tooltips;
767 vector<Glib::RefPtr<Gtk::Action> > actions;
768 string ver_in = revision;
769 string ver = ver_in.substr(0, ver_in.find("-"));
772 output << "\n<h2>Menu actions</h2>" << endl;
773 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
774 output << " surfaces or scripts.\n</p>\n" << endl;
775 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
776 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
777 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
778 output << "<table class=\"dl\">\n <thead>" << endl;
779 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
780 output << " </thead>\n <tbody>" << endl;
782 ActionManager::get_all_actions (paths, labels, tooltips, keys, actions);
784 vector<string>::iterator p;
785 vector<string>::iterator l;
787 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
788 output << " <tr><th><kbd class=\"osc\">" << *p << "</kbd></th><td>" << *l << "</td></tr>" << endl;
790 output << " </tbody>\n </table>" << endl;
792 // output this mess to a browser for easiest X-platform use
793 // it is not pretty HTML, but it works and it's main purpose
794 // is to create raw html to fit in Ardour's manual with no editing
799 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
801 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
807 #ifdef PLATFORM_WINDOWS
813 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
814 #ifndef PLATFORM_WINDOWS
817 g_unlink (file_name);
819 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
825 #ifndef PLATFORM_WINDOWS
829 PBD::open_uri (string_compose ("file:///%1", file_name));
831 halt_connection.disconnect ();
832 AudioEngine::instance()->stop ();
836 /* this being a GUI and all, we want peakfiles */
838 AudioFileSource::set_build_peakfiles (true);
839 AudioFileSource::set_build_missing_peakfiles (true);
841 /* set default clock modes */
843 primary_clock->set_mode (AudioClock::Timecode);
844 secondary_clock->set_mode (AudioClock::BBT);
846 /* start the time-of-day-clock */
849 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
850 update_wall_clock ();
851 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
856 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
857 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
858 Config->map_parameters (pc);
860 UIConfiguration::instance().map_parameters (pc);
864 ARDOUR_UI::~ARDOUR_UI ()
866 UIConfiguration::instance().save_state();
868 ARDOUR_UI_UTILS::inhibit_screensaver (false);
872 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
873 // don't bother at 'real' exit. the OS cleans up for us.
874 delete big_clock; big_clock = 0;
875 delete primary_clock; primary_clock = 0;
876 delete secondary_clock; secondary_clock = 0;
877 delete _process_thread; _process_thread = 0;
878 delete time_info_box; time_info_box = 0;
879 delete meterbridge; meterbridge = 0;
880 delete luawindow; luawindow = 0;
881 delete editor; editor = 0;
882 delete mixer; mixer = 0;
883 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
885 delete gui_object_state; gui_object_state = 0;
886 delete _shared_popup_menu ; _shared_popup_menu = 0;
887 delete main_window_visibility;
888 FastMeter::flush_pattern_cache ();
889 ArdourFader::flush_pattern_cache ();
893 /* Small trick to flush main-thread event pool.
894 * Other thread-pools are destroyed at pthread_exit(),
895 * but tmain thread termination is too late to trigger Pool::~Pool()
897 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.
898 delete ev->event_pool();
903 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
905 if (Splash::instance()) {
906 Splash::instance()->pop_back_for (win);
911 ARDOUR_UI::configure_timeout ()
913 if (last_configure_time == 0) {
914 /* no configure events yet */
918 /* force a gap of 0.5 seconds since the last configure event
921 if (get_microseconds() - last_configure_time < 500000) {
924 have_configure_timeout = false;
925 save_ardour_state ();
931 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
933 if (have_configure_timeout) {
934 last_configure_time = get_microseconds();
936 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
937 have_configure_timeout = true;
944 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
948 if (node.get_property ("roll", str)){
949 roll_controllable->set_id (str);
951 if (node.get_property ("stop", str)) {
952 stop_controllable->set_id (str);
954 if (node.get_property ("goto-start", str)) {
955 goto_start_controllable->set_id (str);
957 if (node.get_property ("goto-end", str)) {
958 goto_end_controllable->set_id (str);
960 if (node.get_property ("auto-loop", str)) {
961 auto_loop_controllable->set_id (str);
963 if (node.get_property ("play-selection", str)) {
964 play_selection_controllable->set_id (str);
966 if (node.get_property ("rec", str)) {
967 rec_controllable->set_id (str);
969 if (node.get_property ("shuttle", str)) {
970 shuttle_box.controllable()->set_id (str);
975 ARDOUR_UI::get_transport_controllable_state ()
977 XMLNode* node = new XMLNode(X_("TransportControllables"));
979 node->set_property (X_("roll"), roll_controllable->id());
980 node->set_property (X_("stop"), stop_controllable->id());
981 node->set_property (X_("goto-start"), goto_start_controllable->id());
982 node->set_property (X_("goto-end"), goto_end_controllable->id());
983 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
984 node->set_property (X_("play-selection"), play_selection_controllable->id());
985 node->set_property (X_("rec"), rec_controllable->id());
986 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
992 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
995 _session->save_state (snapshot_name);
1000 ARDOUR_UI::autosave_session ()
1002 if (g_main_depth() > 1) {
1003 /* inside a recursive main loop,
1004 give up because we may not be able to
1010 if (!Config->get_periodic_safety_backups()) {
1015 _session->maybe_write_autosave();
1022 ARDOUR_UI::session_dirty_changed ()
1029 ARDOUR_UI::update_autosave ()
1031 if (_session && _session->dirty()) {
1032 if (_autosave_connection.connected()) {
1033 _autosave_connection.disconnect();
1036 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1037 Config->get_periodic_safety_backup_interval() * 1000);
1040 if (_autosave_connection.connected()) {
1041 _autosave_connection.disconnect();
1047 ARDOUR_UI::check_announcements ()
1050 string _annc_filename;
1053 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1054 #elif defined PLATFORM_WINDOWS
1055 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1057 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1059 _annc_filename.append (VERSIONSTRING);
1061 _announce_string = "";
1063 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1064 FILE* fin = g_fopen (path.c_str(), "rb");
1066 while (!feof (fin)) {
1069 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1072 _announce_string.append (tmp, len);
1077 pingback (VERSIONSTRING, path);
1082 _hide_splash (gpointer arg)
1084 ((ARDOUR_UI*)arg)->hide_splash();
1089 ARDOUR_UI::starting ()
1091 Application* app = Application::instance ();
1092 const char *nsm_url;
1093 bool brand_new_user = ArdourStartup::required ();
1095 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1096 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1098 if (ARDOUR_COMMAND_LINE::check_announcements) {
1099 check_announcements ();
1104 /* we need to create this early because it may need to set the
1105 * audio backend end up.
1109 audio_midi_setup.get (true);
1111 std::cerr << "audio-midi engine setup failed."<< std::endl;
1115 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1116 nsm = new NSM_Client;
1117 if (!nsm->init (nsm_url)) {
1118 /* the ardour executable may have different names:
1120 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1121 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1122 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1124 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1126 const char *process_name = g_getenv ("ARDOUR_SELF");
1127 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1130 // wait for announce reply from nsm server
1131 for ( i = 0; i < 5000; ++i) {
1135 if (nsm->is_active()) {
1140 error << _("NSM server did not announce itself") << endmsg;
1143 // wait for open command from nsm server
1144 for ( i = 0; i < 5000; ++i) {
1146 Glib::usleep (1000);
1147 if (nsm->client_id ()) {
1153 error << _("NSM: no client ID provided") << endmsg;
1157 if (_session && nsm) {
1158 _session->set_nsm_state( nsm->is_active() );
1160 error << _("NSM: no session created") << endmsg;
1164 // nsm requires these actions disabled
1165 vector<string> action_names;
1166 action_names.push_back("SaveAs");
1167 action_names.push_back("Rename");
1168 action_names.push_back("New");
1169 action_names.push_back("Open");
1170 action_names.push_back("Recent");
1171 action_names.push_back("Close");
1173 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1174 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1176 act->set_sensitive (false);
1183 error << _("NSM: initialization failed") << endmsg;
1189 if (brand_new_user) {
1190 _initial_verbose_plugin_scan = true;
1195 _initial_verbose_plugin_scan = false;
1196 switch (s.response ()) {
1197 case Gtk::RESPONSE_OK:
1204 // TODO: maybe IFF brand_new_user
1205 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1206 std::string dspd (Config->get_default_session_parent_dir());
1207 Searchpath ds (ARDOUR::ardour_data_search_path());
1208 ds.add_subdirectory_to_paths ("sessions");
1209 vector<string> demos;
1210 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1212 ARDOUR::RecentSessions rs;
1213 ARDOUR::read_recent_sessions (rs);
1215 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1216 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1217 std::string name = basename_nosuffix (basename_nosuffix (*i));
1218 std::string path = Glib::build_filename (dspd, name);
1219 /* skip if session-dir already exists */
1220 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1223 /* skip sessions that are already in 'recent'.
1224 * eg. a new user changed <session-default-dir> shorly after installation
1226 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1227 if ((*r).first == name) {
1232 PBD::FileArchive ar (*i);
1233 if (0 == ar.inflate (dspd)) {
1234 store_recent_sessions (name, path);
1235 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1241 #ifdef NO_PLUGIN_STATE
1243 ARDOUR::RecentSessions rs;
1244 ARDOUR::read_recent_sessions (rs);
1246 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1248 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1250 /* already used Ardour, have sessions ... warn about plugin state */
1252 ArdourDialog d (_("Free/Demo Version Warning"), true);
1254 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1255 CheckButton c (_("Don't warn me about this again"));
1257 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"),
1258 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1259 _("It will not restore OR save any plugin settings"),
1260 _("If you load an existing session with plugin settings\n"
1261 "they will not be used and will be lost."),
1262 _("To get full access to updates without this limitation\n"
1263 "consider becoming a subscriber for a low cost every month.")));
1264 l.set_justify (JUSTIFY_CENTER);
1266 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1268 d.get_vbox()->pack_start (l, true, true);
1269 d.get_vbox()->pack_start (b, false, false, 12);
1270 d.get_vbox()->pack_start (c, false, false, 12);
1272 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1273 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1277 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1279 if (d.run () != RESPONSE_OK) {
1280 _exit (EXIT_SUCCESS);
1285 /* go get a session */
1287 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1289 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1290 std::cerr << "Cannot get session parameters."<< std::endl;
1297 WM::Manager::instance().show_visible ();
1299 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1300 * editor window, and we may want stuff to be hidden.
1302 _status_bar_visibility.update ();
1304 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1306 /* all other dialogs are created conditionally */
1312 ARDOUR_UI::check_memory_locking ()
1314 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1315 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1319 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1321 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1323 struct rlimit limits;
1325 long pages, page_size;
1327 size_t pages_len=sizeof(pages);
1328 if ((page_size = getpagesize()) < 0 ||
1329 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1331 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1336 ram = (int64_t) pages * (int64_t) page_size;
1339 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1343 if (limits.rlim_cur != RLIM_INFINITY) {
1345 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1349 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1350 "This might cause %1 to run out of memory before your system "
1351 "runs out of memory. \n\n"
1352 "You can view the memory limit with 'ulimit -l', "
1353 "and it is normally controlled by %2"),
1356 X_("/etc/login.conf")
1358 X_(" /etc/security/limits.conf")
1362 msg.set_default_response (RESPONSE_OK);
1364 VBox* vbox = msg.get_vbox();
1366 CheckButton cb (_("Do not show this window again"));
1367 hbox.pack_start (cb, true, false);
1368 vbox->pack_start (hbox);
1373 pop_back_splash (msg);
1377 if (cb.get_active()) {
1378 XMLNode node (X_("no-memory-warning"));
1379 Config->add_instant_xml (node);
1384 #endif // !__APPLE__
1389 ARDOUR_UI::queue_finish ()
1391 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1395 ARDOUR_UI::idle_finish ()
1398 return false; /* do not call again */
1405 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1407 if (_session->dirty()) {
1408 vector<string> actions;
1409 actions.push_back (_("Don't quit"));
1410 actions.push_back (_("Just quit"));
1411 actions.push_back (_("Save and quit"));
1412 switch (ask_about_saving_session(actions)) {
1417 /* use the default name */
1418 if (save_state_canfail ("")) {
1419 /* failed - don't quit */
1420 MessageDialog msg (_main_window,
1421 string_compose (_("\
1422 %1 was unable to save your session.\n\n\
1423 If you still wish to quit, please use the\n\n\
1424 \"Just quit\" option."), PROGRAM_NAME));
1425 pop_back_splash(msg);
1435 second_connection.disconnect ();
1436 point_one_second_connection.disconnect ();
1437 point_zero_something_second_connection.disconnect();
1438 fps_connection.disconnect();
1441 delete ARDOUR_UI::instance()->video_timeline;
1442 ARDOUR_UI::instance()->video_timeline = NULL;
1443 stop_video_server();
1445 /* Save state before deleting the session, as that causes some
1446 windows to be destroyed before their visible state can be
1449 save_ardour_state ();
1451 if (key_editor.get (false)) {
1452 key_editor->disconnect ();
1455 close_all_dialogs ();
1458 _session->set_clean ();
1459 _session->remove_pending_capture_state ();
1464 halt_connection.disconnect ();
1465 AudioEngine::instance()->stop ();
1466 #ifdef WINDOWS_VST_SUPPORT
1467 fst_stop_threading();
1473 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1475 ArdourDialog window (_("Unsaved Session"));
1476 Gtk::HBox dhbox; // the hbox for the image and text
1477 Gtk::Label prompt_label;
1478 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1482 assert (actions.size() >= 3);
1484 window.add_button (actions[0], RESPONSE_REJECT);
1485 window.add_button (actions[1], RESPONSE_APPLY);
1486 window.add_button (actions[2], RESPONSE_ACCEPT);
1488 window.set_default_response (RESPONSE_ACCEPT);
1490 Gtk::Button noquit_button (msg);
1491 noquit_button.set_name ("EditorGTKButton");
1495 if (_session->snap_name() == _session->name()) {
1496 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?"),
1497 _session->snap_name());
1499 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?"),
1500 _session->snap_name());
1503 prompt_label.set_text (prompt);
1504 prompt_label.set_name (X_("PrompterLabel"));
1505 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1507 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1508 dhbox.set_homogeneous (false);
1509 dhbox.pack_start (*dimage, false, false, 5);
1510 dhbox.pack_start (prompt_label, true, false, 5);
1511 window.get_vbox()->pack_start (dhbox);
1513 window.set_name (_("Prompter"));
1514 window.set_modal (true);
1515 window.set_resizable (false);
1518 prompt_label.show();
1523 ResponseType r = (ResponseType) window.run();
1528 case RESPONSE_ACCEPT: // save and get out of here
1530 case RESPONSE_APPLY: // get out of here
1541 ARDOUR_UI::every_second ()
1544 update_disk_space ();
1545 update_timecode_format ();
1546 update_peak_thread_work ();
1548 if (nsm && nsm->is_active ()) {
1551 if (!_was_dirty && _session->dirty ()) {
1555 else if (_was_dirty && !_session->dirty ()){
1563 ARDOUR_UI::every_point_one_seconds ()
1565 if (editor) editor->build_region_boundary_cache();
1569 ARDOUR_UI::every_point_zero_something_seconds ()
1571 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1573 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1574 float mpeak = editor_meter->update_meters();
1575 if (mpeak > editor_meter_max_peak) {
1576 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1577 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1584 ARDOUR_UI::set_fps_timeout_connection ()
1586 unsigned int interval = 40;
1587 if (!_session) return;
1588 if (_session->timecode_frames_per_second() != 0) {
1589 /* ideally we'll use a select() to sleep and not accumulate
1590 * idle time to provide a regular periodic signal.
1591 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1592 * However, that'll require a dedicated thread and cross-thread
1593 * signals to the GUI Thread..
1595 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1596 * _session->sample_rate() / _session->nominal_sample_rate()
1597 / _session->timecode_frames_per_second()
1599 #ifdef PLATFORM_WINDOWS
1600 // the smallest windows scheduler time-slice is ~15ms.
1601 // periodic GUI timeouts shorter than that will cause
1602 // WaitForSingleObject to spinlock (100% of one CPU Core)
1603 // and gtk never enters idle mode.
1604 // also changing timeBeginPeriod(1) does not affect that in
1605 // any beneficial way, so we just limit the max rate for now.
1606 interval = std::max(30u, interval); // at most ~33Hz.
1608 interval = std::max(8u, interval); // at most 120Hz.
1611 fps_connection.disconnect();
1612 Timers::set_fps_interval (interval);
1616 ARDOUR_UI::update_sample_rate (samplecnt_t)
1620 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1622 if (!AudioEngine::instance()->running()) {
1624 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1628 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1631 /* no sample rate available */
1632 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1635 if (fmod (rate, 1000.0) != 0.0) {
1636 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1637 (float) rate / 1000.0f,
1638 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1640 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1642 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1646 sample_rate_label.set_markup (buf);
1650 ARDOUR_UI::update_format ()
1653 format_label.set_text ("");
1658 s << _("File:") << X_(" <span foreground=\"green\">");
1660 switch (_session->config.get_native_file_header_format ()) {
1695 switch (_session->config.get_native_file_data_format ()) {
1709 format_label.set_markup (s.str ());
1713 ARDOUR_UI::update_cpu_load ()
1715 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1716 double const c = AudioEngine::instance()->get_dsp_load ();
1718 const char* const bg = c > 90 ? " background=\"red\"" : "";
1722 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1724 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1726 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1729 dsp_load_label.set_markup (buf);
1732 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1734 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1736 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1739 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1743 ARDOUR_UI::update_peak_thread_work ()
1746 const int c = SourceFactory::peak_work_queue_length ();
1748 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1749 peak_thread_work_label.set_markup (buf);
1751 peak_thread_work_label.set_markup (X_(""));
1756 ARDOUR_UI::count_recenabled_streams (Route& route)
1758 Track* track = dynamic_cast<Track*>(&route);
1759 if (track && track->rec_enable_control()->get_value()) {
1760 rec_enabled_streams += track->n_inputs().n_total();
1765 ARDOUR_UI::format_disk_space_label (float remain_sec)
1767 if (remain_sec < 0) {
1768 disk_space_label.set_text (_("N/A"));
1769 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1775 int sec = floor (remain_sec);
1776 int hrs = sec / 3600;
1777 int mins = (sec / 60) % 60;
1778 int secs = sec % 60;
1779 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1780 ArdourWidgets::set_tooltip (disk_space_label, buf);
1782 if (remain_sec > 86400) {
1783 disk_space_label.set_text (_("Rec: >24h"));
1785 } else if (remain_sec > 32400 /* 9 hours */) {
1786 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1787 } else if (remain_sec > 5940 /* 99 mins */) {
1788 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1790 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1792 disk_space_label.set_text (buf);
1797 ARDOUR_UI::update_disk_space()
1799 if (_session == 0) {
1800 format_disk_space_label (-1);
1804 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1805 samplecnt_t fr = _session->sample_rate();
1808 /* skip update - no SR available */
1809 format_disk_space_label (-1);
1814 /* Available space is unknown */
1815 format_disk_space_label (-1);
1816 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1817 format_disk_space_label (max_samplecnt);
1819 rec_enabled_streams = 0;
1820 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1822 samplecnt_t samples = opt_samples.get_value_or (0);
1824 if (rec_enabled_streams) {
1825 samples /= rec_enabled_streams;
1828 format_disk_space_label (samples / (float)fr);
1834 ARDOUR_UI::update_timecode_format ()
1840 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1841 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1843 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1844 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1849 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1850 matching ? X_("green") : X_("red"),
1851 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1853 snprintf (buf, sizeof (buf), "TC: n/a");
1856 timecode_format_label.set_markup (buf);
1860 ARDOUR_UI::update_wall_clock ()
1864 static int last_min = -1;
1867 tm_now = localtime (&now);
1868 if (last_min != tm_now->tm_min) {
1870 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1871 wall_clock_label.set_text (buf);
1872 last_min = tm_now->tm_min;
1879 ARDOUR_UI::open_recent_session ()
1881 bool can_return = (_session != 0);
1883 SessionDialog recent_session_dialog;
1887 ResponseType r = (ResponseType) recent_session_dialog.run ();
1890 case RESPONSE_ACCEPT:
1894 recent_session_dialog.hide();
1897 exit (EXIT_FAILURE);
1901 recent_session_dialog.hide();
1905 std::string path = recent_session_dialog.session_folder();
1906 std::string state = recent_session_dialog.session_name (should_be_new);
1908 if (should_be_new == true) {
1912 _session_is_new = false;
1914 if (load_session (path, state) == 0) {
1923 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1925 if (!AudioEngine::instance()->running()) {
1926 MessageDialog msg (parent, string_compose (
1927 _("%1 is not connected to any audio backend.\n"
1928 "You cannot open or close sessions in this condition"),
1930 pop_back_splash (msg);
1938 ARDOUR_UI::open_session ()
1940 if (!check_audioengine (_main_window)) {
1944 /* ardour sessions are folders */
1945 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1946 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1947 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1948 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1951 string session_parent_dir = Glib::path_get_dirname(_session->path());
1952 open_session_selector.set_current_folder(session_parent_dir);
1954 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1957 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1959 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1960 string default_session_folder = Config->get_default_session_parent_dir();
1961 open_session_selector.add_shortcut_folder (default_session_folder);
1963 catch (Glib::Error const& e) {
1964 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1967 FileFilter session_filter;
1968 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1969 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1970 open_session_selector.add_filter (session_filter);
1972 FileFilter archive_filter;
1973 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1974 archive_filter.set_name (_("Session Archives"));
1976 open_session_selector.add_filter (archive_filter);
1978 open_session_selector.set_filter (session_filter);
1980 int response = open_session_selector.run();
1981 open_session_selector.hide ();
1983 if (response == Gtk::RESPONSE_CANCEL) {
1987 string session_path = open_session_selector.get_filename();
1991 if (session_path.length() > 0) {
1992 int rv = ARDOUR::inflate_session (session_path,
1993 Config->get_default_session_parent_dir(), path, name);
1995 _session_is_new = false;
1996 load_session (path, name);
1999 MessageDialog msg (_main_window,
2000 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2003 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2004 _session_is_new = isnew;
2005 load_session (path, name);
2011 ARDOUR_UI::session_add_mixed_track (
2012 const ChanCount& input,
2013 const ChanCount& output,
2014 RouteGroup* route_group,
2016 const string& name_template,
2018 PluginInfoPtr instrument,
2019 Plugin::PresetRecord* pset,
2020 ARDOUR::PresentationInfo::order_t order)
2024 if (Profile->get_mixbus ()) {
2029 list<boost::shared_ptr<MidiTrack> > tracks;
2030 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2032 if (tracks.size() != how_many) {
2033 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2038 display_insufficient_ports_message ();
2044 ARDOUR_UI::session_add_midi_bus (
2045 RouteGroup* route_group,
2047 const string& name_template,
2049 PluginInfoPtr instrument,
2050 Plugin::PresetRecord* pset,
2051 ARDOUR::PresentationInfo::order_t order)
2053 if (_session == 0) {
2054 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2058 if (Profile->get_mixbus ()) {
2064 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2065 if (routes.size() != how_many) {
2066 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2071 display_insufficient_ports_message ();
2077 ARDOUR_UI::session_add_midi_route (
2079 RouteGroup* route_group,
2081 const string& name_template,
2083 PluginInfoPtr instrument,
2084 Plugin::PresetRecord* pset,
2085 ARDOUR::PresentationInfo::order_t order)
2087 ChanCount one_midi_channel;
2088 one_midi_channel.set (DataType::MIDI, 1);
2091 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2093 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2098 ARDOUR_UI::session_add_audio_route (
2100 int32_t input_channels,
2101 int32_t output_channels,
2102 ARDOUR::TrackMode mode,
2103 RouteGroup* route_group,
2105 string const & name_template,
2107 ARDOUR::PresentationInfo::order_t order)
2109 list<boost::shared_ptr<AudioTrack> > tracks;
2116 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2118 if (tracks.size() != how_many) {
2119 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2125 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2127 if (routes.size() != how_many) {
2128 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2135 display_insufficient_ports_message ();
2140 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2141 (*i)->set_strict_io (true);
2143 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2144 (*i)->set_strict_io (true);
2150 ARDOUR_UI::session_add_foldback_bus (int32_t channels, uint32_t how_many, string const & name_template)
2157 routes = _session->new_audio_route (channels, channels, 0, how_many, name_template, PresentationInfo::FoldbackBus, -1);
2159 if (routes.size() != how_many) {
2160 error << string_compose (P_("could not create %1 new foldback bus", "could not create %1 new foldback busses", how_many), how_many)
2166 display_insufficient_ports_message ();
2172 ARDOUR_UI::display_insufficient_ports_message ()
2174 MessageDialog msg (_main_window,
2175 string_compose (_("There are insufficient ports available\n\
2176 to create a new track or bus.\n\
2177 You should save %1, exit and\n\
2178 restart with more ports."), PROGRAM_NAME));
2179 pop_back_splash (msg);
2184 ARDOUR_UI::transport_goto_start ()
2187 _session->goto_start();
2189 /* force displayed area in editor to start no matter
2190 what "follow playhead" setting is.
2194 editor->center_screen (_session->current_start_sample ());
2200 ARDOUR_UI::transport_goto_zero ()
2203 _session->request_locate (0);
2205 /* force displayed area in editor to start no matter
2206 what "follow playhead" setting is.
2210 editor->reset_x_origin (0);
2216 ARDOUR_UI::transport_goto_wallclock ()
2218 if (_session && editor) {
2222 samplepos_t samples;
2225 localtime_r (&now, &tmnow);
2227 samplecnt_t sample_rate = _session->sample_rate();
2229 if (sample_rate == 0) {
2230 /* no frame rate available */
2234 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2235 samples += tmnow.tm_min * (60 * sample_rate);
2236 samples += tmnow.tm_sec * sample_rate;
2238 _session->request_locate (samples, _session->transport_rolling ());
2240 /* force displayed area in editor to start no matter
2241 what "follow playhead" setting is.
2245 editor->center_screen (samples);
2251 ARDOUR_UI::transport_goto_end ()
2254 samplepos_t const sample = _session->current_end_sample();
2255 _session->request_locate (sample);
2257 /* force displayed area in editor to start no matter
2258 what "follow playhead" setting is.
2262 editor->center_screen (sample);
2268 ARDOUR_UI::transport_stop ()
2274 if (_session->is_auditioning()) {
2275 _session->cancel_audition ();
2279 _session->request_stop (false, true);
2282 /** Check if any tracks are record enabled. If none are, record enable all of them.
2283 * @return true if track record-enabled status was changed, false otherwise.
2286 ARDOUR_UI::trx_record_enable_all_tracks ()
2292 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2293 bool none_record_enabled = true;
2295 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2296 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2299 if (t->rec_enable_control()->get_value()) {
2300 none_record_enabled = false;
2305 if (none_record_enabled) {
2306 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2309 return none_record_enabled;
2313 ARDOUR_UI::transport_record (bool roll)
2316 switch (_session->record_status()) {
2317 case Session::Disabled:
2318 if (_session->ntracks() == 0) {
2319 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."));
2323 if (Profile->get_trx()) {
2324 roll = trx_record_enable_all_tracks ();
2326 _session->maybe_enable_record ();
2331 case Session::Recording:
2333 _session->request_stop();
2335 _session->disable_record (false, true);
2339 case Session::Enabled:
2340 _session->disable_record (false, true);
2346 ARDOUR_UI::transport_roll ()
2352 if (_session->is_auditioning()) {
2356 if (_session->config.get_external_sync()) {
2357 switch (TransportMasterManager::instance().current()->type()) {
2361 /* transport controlled by the master */
2366 bool rolling = _session->transport_rolling();
2368 if (_session->get_play_loop()) {
2370 /* If loop playback is not a mode, then we should cancel
2371 it when this action is requested. If it is a mode
2372 we just leave it in place.
2375 if (!Config->get_loop_is_mode()) {
2376 /* XXX it is not possible to just leave seamless loop and keep
2377 playing at present (nov 4th 2009)
2379 if (!Config->get_seamless_loop()) {
2380 /* stop loop playback and stop rolling */
2381 _session->request_play_loop (false, true);
2382 } else if (rolling) {
2383 /* stop loop playback but keep rolling */
2384 _session->request_play_loop (false, false);
2388 } else if (_session->get_play_range () ) {
2389 /* stop playing a range if we currently are */
2390 _session->request_play_range (0, true);
2394 _session->request_transport_speed (1.0f);
2399 ARDOUR_UI::get_smart_mode() const
2401 return ( editor->get_smart_mode() );
2406 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2412 if (_session->is_auditioning()) {
2413 _session->cancel_audition ();
2417 if (_session->config.get_external_sync()) {
2418 switch (TransportMasterManager::instance().current()->type()) {
2422 /* transport controlled by the master */
2427 bool rolling = _session->transport_rolling();
2428 bool affect_transport = true;
2430 if (rolling && roll_out_of_bounded_mode) {
2431 /* drop out of loop/range playback but leave transport rolling */
2432 if (_session->get_play_loop()) {
2433 if (_session->actively_recording()) {
2435 /* just stop using the loop, then actually stop
2438 _session->request_play_loop (false, affect_transport);
2441 if (Config->get_seamless_loop()) {
2442 /* the disk buffers contain copies of the loop - we can't
2443 just keep playing, so stop the transport. the user
2444 can restart as they wish.
2446 affect_transport = true;
2448 /* disk buffers are normal, so we can keep playing */
2449 affect_transport = false;
2451 _session->request_play_loop (false, affect_transport);
2453 } else if (_session->get_play_range ()) {
2454 affect_transport = false;
2455 _session->request_play_range (0, true);
2459 if (affect_transport) {
2461 _session->request_stop (with_abort, true);
2463 } else if (!with_abort) { /* with_abort == true means the
2464 * command was intended to stop
2465 * transport, not start.
2468 /* the only external sync condition we can be in here
2469 * would be Engine (JACK) sync, in which case we still
2473 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
2474 _session->request_play_range (&editor->get_selection().time, true);
2475 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2477 _session->request_transport_speed (1.0f);
2483 ARDOUR_UI::toggle_session_auto_loop ()
2489 Location * looploc = _session->locations()->auto_loop_location();
2495 if (_session->get_play_loop()) {
2497 /* looping enabled, our job is to disable it */
2499 _session->request_play_loop (false);
2503 /* looping not enabled, our job is to enable it.
2505 loop-is-NOT-mode: this action always starts the transport rolling.
2506 loop-IS-mode: this action simply sets the loop play mechanism, but
2507 does not start transport.
2509 if (Config->get_loop_is_mode()) {
2510 _session->request_play_loop (true, false);
2512 _session->request_play_loop (true, true);
2516 //show the loop markers
2517 looploc->set_hidden (false, this);
2521 ARDOUR_UI::transport_play_selection ()
2527 editor->play_selection ();
2531 ARDOUR_UI::transport_play_preroll ()
2536 editor->play_with_preroll ();
2540 ARDOUR_UI::transport_rec_preroll ()
2545 editor->rec_with_preroll ();
2549 ARDOUR_UI::transport_rec_count_in ()
2554 editor->rec_with_count_in ();
2558 ARDOUR_UI::transport_rewind (int option)
2560 float current_transport_speed;
2563 current_transport_speed = _session->transport_speed();
2565 if (current_transport_speed >= 0.0f) {
2568 _session->request_transport_speed (-1.0f);
2571 _session->request_transport_speed (-4.0f);
2574 _session->request_transport_speed (-0.5f);
2579 _session->request_transport_speed (current_transport_speed * 1.5f);
2585 ARDOUR_UI::transport_forward (int option)
2591 float current_transport_speed = _session->transport_speed();
2593 if (current_transport_speed <= 0.0f) {
2596 _session->request_transport_speed (1.0f);
2599 _session->request_transport_speed (4.0f);
2602 _session->request_transport_speed (0.5f);
2607 _session->request_transport_speed (current_transport_speed * 1.5f);
2612 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2618 boost::shared_ptr<Route> r;
2620 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2622 boost::shared_ptr<Track> t;
2624 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2625 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2631 ARDOUR_UI::map_transport_state ()
2634 layered_button.set_sensitive (false);
2638 shuttle_box.map_transport_state ();
2640 float sp = _session->transport_speed();
2643 layered_button.set_sensitive (!_session->actively_recording ());
2645 layered_button.set_sensitive (true);
2646 update_disk_space ();
2648 if (UIConfiguration::instance().get_screen_saver_mode () == InhibitWhileRecording) {
2649 inhibit_screensaver (_session->actively_recording ());
2654 ARDOUR_UI::blink_handler (bool blink_on)
2656 sync_blink (blink_on);
2658 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2661 error_blink (blink_on);
2662 solo_blink (blink_on);
2663 audition_blink (blink_on);
2664 feedback_blink (blink_on);
2668 ARDOUR_UI::update_clocks ()
2670 if (!_session) return;
2672 if (editor && !editor->dragging_playhead()) {
2673 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2678 ARDOUR_UI::start_clocking ()
2680 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2681 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2683 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2688 ARDOUR_UI::stop_clocking ()
2690 clock_signal_connection.disconnect ();
2694 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2698 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2700 label->set_text (buf);
2701 bar->set_fraction (fraction);
2703 /* process events, redraws, etc. */
2705 while (gtk_events_pending()) {
2706 gtk_main_iteration ();
2709 return true; /* continue with save-as */
2713 ARDOUR_UI::save_session_as ()
2719 if (_session->dirty()) {
2720 vector<string> actions;
2721 actions.push_back (_("Abort save-as"));
2722 actions.push_back (_("Don't save now, just save-as"));
2723 actions.push_back (_("Save it first"));
2724 switch (ask_about_saving_session(actions)) {
2729 if (save_state_canfail ("")) {
2730 MessageDialog msg (_main_window,
2731 string_compose (_("\
2732 %1 was unable to save your session.\n\n\
2733 If you still wish to proceed, please use the\n\n\
2734 \"Don't save now\" option."), PROGRAM_NAME));
2735 pop_back_splash(msg);
2741 _session->remove_pending_capture_state ();
2746 if (!save_as_dialog) {
2747 save_as_dialog = new SaveAsDialog;
2750 save_as_dialog->set_name (_session->name());
2752 int response = save_as_dialog->run ();
2754 save_as_dialog->hide ();
2757 case Gtk::RESPONSE_OK:
2766 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2767 sa.new_name = save_as_dialog->new_name ();
2768 sa.switch_to = save_as_dialog->switch_to();
2769 sa.copy_media = save_as_dialog->copy_media();
2770 sa.copy_external = save_as_dialog->copy_external();
2771 sa.include_media = save_as_dialog->include_media ();
2773 /* Only bother with a progress dialog if we're going to copy
2774 media into the save-as target. Without that choice, this
2775 will be very fast because we're only talking about a few kB's to
2776 perhaps a couple of MB's of data.
2779 ArdourDialog progress_dialog (_("Save As"), true);
2782 if (sa.include_media && sa.copy_media) {
2784 Gtk::Label* label = manage (new Gtk::Label());
2785 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2787 progress_dialog.get_vbox()->pack_start (*label);
2788 progress_dialog.get_vbox()->pack_start (*progress_bar);
2790 progress_bar->show ();
2792 /* this signal will be emitted from within this, the calling thread,
2793 * after every file is copied. It provides information on percentage
2794 * complete (in terms of total data to copy), the number of files
2795 * copied so far, and the total number to copy.
2798 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2800 progress_dialog.show_all ();
2801 progress_dialog.present ();
2804 if (_session->save_as (sa)) {
2806 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2810 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2811 * the trick is this: if the new session was copy with media included,
2812 * then Session::save_as() will have already done a neat trick to avoid
2813 * us having to unload and load the new state. But if the media was not
2814 * included, then this is required (it avoids us having to otherwise
2815 * drop all references to media (sources).
2818 if (!sa.include_media && sa.switch_to) {
2819 unload_session (false);
2820 load_session (sa.final_session_folder_name, sa.new_name);
2825 ARDOUR_UI::archive_session ()
2833 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2835 SessionArchiveDialog sad;
2836 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2837 int response = sad.run ();
2839 if (response != Gtk::RESPONSE_OK) {
2844 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2845 MessageDialog msg (_("Session Archiving failed."));
2851 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2855 struct tm local_time;
2858 localtime_r (&n, &local_time);
2859 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2860 if (switch_to_it && _session->dirty ()) {
2861 save_state_canfail ("");
2864 save_state (timebuf, switch_to_it);
2869 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2873 prompter.get_result (snapname);
2875 bool do_save = (snapname.length() != 0);
2878 char illegal = Session::session_name_is_legal(snapname);
2880 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2881 "snapshot names may not contain a '%1' character"), illegal));
2887 vector<std::string> p;
2888 get_state_files_in_directory (_session->session_directory().root_path(), p);
2889 vector<string> n = get_file_names_no_extension (p);
2891 if (find (n.begin(), n.end(), snapname) != n.end()) {
2893 do_save = overwrite_file_dialog (prompter,
2894 _("Confirm Snapshot Overwrite"),
2895 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2899 save_state (snapname, switch_to_it);
2909 /** Ask the user for the name of a new snapshot and then take it.
2913 ARDOUR_UI::snapshot_session (bool switch_to_it)
2915 if (switch_to_it && _session->dirty()) {
2916 vector<string> actions;
2917 actions.push_back (_("Abort saving snapshot"));
2918 actions.push_back (_("Don't save now, just snapshot"));
2919 actions.push_back (_("Save it first"));
2920 switch (ask_about_saving_session(actions)) {
2925 if (save_state_canfail ("")) {
2926 MessageDialog msg (_main_window,
2927 string_compose (_("\
2928 %1 was unable to save your session.\n\n\
2929 If you still wish to proceed, please use the\n\n\
2930 \"Don't save now\" option."), PROGRAM_NAME));
2931 pop_back_splash(msg);
2937 _session->remove_pending_capture_state ();
2942 Prompter prompter (true);
2943 prompter.set_name ("Prompter");
2944 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2946 prompter.set_title (_("Snapshot and switch"));
2947 prompter.set_prompt (_("New session name"));
2949 prompter.set_title (_("Take Snapshot"));
2950 prompter.set_prompt (_("Name of new snapshot"));
2954 prompter.set_initial_text (_session->snap_name());
2956 Glib::DateTime tm (g_date_time_new_now_local ());
2957 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2960 bool finished = false;
2962 switch (prompter.run()) {
2963 case RESPONSE_ACCEPT:
2965 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2976 /** Ask the user for a new session name and then rename the session to it.
2980 ARDOUR_UI::rename_session ()
2986 Prompter prompter (true);
2989 prompter.set_name ("Prompter");
2990 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2991 prompter.set_title (_("Rename Session"));
2992 prompter.set_prompt (_("New session name"));
2995 switch (prompter.run()) {
2996 case RESPONSE_ACCEPT:
2998 prompter.get_result (name);
3000 bool do_rename = (name.length() != 0);
3003 char illegal = Session::session_name_is_legal (name);
3006 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3007 "session names may not contain a '%1' character"), illegal));
3012 switch (_session->rename (name)) {
3014 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3015 msg.set_position (WIN_POS_MOUSE);
3023 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3024 msg.set_position (WIN_POS_MOUSE);
3040 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3042 if (!_session || _session->deletion_in_progress()) {
3046 XMLNode* node = new XMLNode (X_("UI"));
3048 WM::Manager::instance().add_state (*node);
3050 node->add_child_nocopy (gui_object_state->get_state());
3052 _session->add_extra_xml (*node);
3054 if (export_video_dialog) {
3055 _session->add_extra_xml (export_video_dialog->get_state());
3058 save_state_canfail (name, switch_to_it);
3062 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3067 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3072 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3077 ARDOUR_UI::primary_clock_value_changed ()
3080 _session->request_locate (primary_clock->current_time ());
3085 ARDOUR_UI::big_clock_value_changed ()
3088 _session->request_locate (big_clock->current_time ());
3093 ARDOUR_UI::secondary_clock_value_changed ()
3096 _session->request_locate (secondary_clock->current_time ());
3100 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3102 if (response == RESPONSE_ACCEPT) {
3103 const string name = d->get_template_name ();
3104 const string desc = d->get_description ();
3106 int failed = _session->save_template (name, desc);
3108 if (failed == -2) { /* file already exists. */
3109 bool overwrite = overwrite_file_dialog (*d,
3110 _("Confirm Template Overwrite"),
3111 _("A template already exists with that name. Do you want to overwrite it?"));
3114 _session->save_template (name, desc, true);
3126 ARDOUR_UI::save_template ()
3128 if (!check_audioengine (_main_window)) {
3132 const std::string desc = SessionMetadata::Metadata()->description ();
3133 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3134 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3138 void ARDOUR_UI::manage_templates ()
3145 ARDOUR_UI::edit_metadata ()
3147 SessionMetadataEditor dialog;
3148 dialog.set_session (_session);
3149 dialog.grab_focus ();
3154 ARDOUR_UI::import_metadata ()
3156 SessionMetadataImporter dialog;
3157 dialog.set_session (_session);
3162 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3164 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3166 MessageDialog msg (str,
3168 Gtk::MESSAGE_WARNING,
3169 Gtk::BUTTONS_YES_NO,
3173 msg.set_name (X_("OpenExistingDialog"));
3174 msg.set_title (_("Open Existing Session"));
3175 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3176 msg.set_position (Gtk::WIN_POS_CENTER);
3177 pop_back_splash (msg);
3179 switch (msg.run()) {
3188 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3190 BusProfile bus_profile;
3193 bus_profile.master_out_channels = 2;
3195 /* get settings from advanced section of NSD */
3196 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3199 // NULL profile: no master, no monitor
3200 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3208 ARDOUR_UI::load_from_application_api (const std::string& path)
3210 /* OS X El Capitan (and probably later) now somehow passes the command
3211 line arguments to an app via the openFile delegate protocol. Ardour
3212 already does its own command line processing, and having both
3213 pathways active causes crashes. So, if the command line was already
3214 set, do nothing here.
3217 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3221 ARDOUR_COMMAND_LINE::session_name = path;
3223 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3225 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3227 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3228 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3229 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3230 * -> SessionDialog is not displayed
3233 if (_session_dialog) {
3234 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3235 std::string session_path = path;
3236 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3237 session_path = Glib::path_get_dirname (session_path);
3239 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3240 _session_dialog->set_provided_session (session_name, session_path);
3241 _session_dialog->response (RESPONSE_NONE);
3242 _session_dialog->hide();
3247 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3248 /* /path/to/foo => /path/to/foo, foo */
3249 rv = load_session (path, basename_nosuffix (path));
3251 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3252 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3255 // if load_session fails -> pop up SessionDialog.
3257 ARDOUR_COMMAND_LINE::session_name = "";
3259 if (get_session_parameters (true, false)) {
3260 exit (EXIT_FAILURE);
3265 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3267 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3269 string session_name;
3270 string session_path;
3271 string template_name;
3273 bool likely_new = false;
3274 bool cancel_not_quit;
3276 /* deal with any existing DIRTY session now, rather than later. don't
3277 * treat a non-dirty session this way, so that it stays visible
3278 * as we bring up the new session dialog.
3281 if (_session && ARDOUR_UI::instance()->video_timeline) {
3282 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3285 /* if there is already a session, relabel the button
3286 on the SessionDialog so that we don't Quit directly
3288 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3290 if (_session && _session->dirty()) {
3291 if (unload_session (false)) {
3292 /* unload cancelled by user */
3295 ARDOUR_COMMAND_LINE::session_name = "";
3298 if (!load_template.empty()) {
3299 should_be_new = true;
3300 template_name = load_template;
3303 session_path = ARDOUR_COMMAND_LINE::session_name;
3305 if (!session_path.empty()) {
3307 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3309 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3311 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3312 /* session/snapshot file, change path to be dir */
3313 session_path = Glib::path_get_dirname (session_path);
3317 /* session (file or folder) does not exist ... did the
3318 * user give us a path or just a name?
3321 if (session_path.find (G_DIR_SEPARATOR) == string::npos) {
3322 /* user gave session name with no path info, use
3323 default session folder.
3325 session_name = ARDOUR_COMMAND_LINE::session_name;
3326 session_path = Glib::build_filename (Config->get_default_session_parent_dir (), session_name);
3328 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3333 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3335 _session_dialog = &session_dialog;
3338 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3340 /* if they named a specific statefile, use it, otherwise they are
3341 just giving a session folder, and we want to use it as is
3342 to find the session.
3345 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3347 if (suffix != string::npos) {
3348 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3349 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3350 session_name = Glib::path_get_basename (session_name);
3352 session_path = ARDOUR_COMMAND_LINE::session_name;
3353 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3358 session_dialog.clear_given ();
3361 if (session_name.empty()) {
3362 /* need the dialog to get the name (at least) from the user */
3363 switch (session_dialog.run()) {
3364 case RESPONSE_ACCEPT:
3367 /* this is used for async * app->ShouldLoad(). */
3368 continue; // while loop
3371 if (quit_on_cancel) {
3372 ARDOUR_UI::finish ();
3373 Gtkmm2ext::Application::instance()->cleanup();
3375 pthread_cancel_all ();
3376 return -1; // caller is responsible to call exit()
3382 session_dialog.hide ();
3385 /* if we run the startup dialog again, offer more than just "new session" */
3387 should_be_new = false;
3389 session_name = session_dialog.session_name (likely_new);
3390 session_path = session_dialog.session_folder ();
3397 int rv = ARDOUR::inflate_session (session_name,
3398 Config->get_default_session_parent_dir(), session_path, session_name);
3400 MessageDialog msg (session_dialog,
3401 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3406 session_dialog.set_provided_session (session_name, session_path);
3410 // XXX check archive, inflate
3411 string::size_type suffix = session_name.find (statefile_suffix);
3413 if (suffix != string::npos) {
3414 session_name = session_name.substr (0, suffix);
3417 /* this shouldn't happen, but we catch it just in case it does */
3419 if (session_name.empty()) {
3423 if (session_dialog.use_session_template()) {
3424 template_name = session_dialog.session_template_name();
3425 _session_is_new = true;
3428 if (session_name[0] == G_DIR_SEPARATOR ||
3429 #ifdef PLATFORM_WINDOWS
3430 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3432 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3433 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3438 /* absolute path or cwd-relative path specified for session name: infer session folder
3439 from what was given.
3442 session_path = Glib::path_get_dirname (session_name);
3443 session_name = Glib::path_get_basename (session_name);
3447 session_path = session_dialog.session_folder();
3449 char illegal = Session::session_name_is_legal (session_name);
3452 MessageDialog msg (session_dialog,
3453 string_compose (_("To ensure compatibility with various systems\n"
3454 "session names may not contain a '%1' character"),
3457 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3462 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3465 if (likely_new && !nsm) {
3467 std::string existing = Glib::build_filename (session_path, session_name);
3469 if (!ask_about_loading_existing_session (existing)) {
3470 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3475 _session_is_new = false;
3480 pop_back_splash (session_dialog);
3481 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3483 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3487 char illegal = Session::session_name_is_legal(session_name);
3490 pop_back_splash (session_dialog);
3491 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3492 "session names may not contain a '%1' character"), illegal));
3494 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3498 _session_is_new = true;
3501 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3503 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3504 meta_session_setup (template_name.substr (11));
3506 } else if (likely_new && template_name.empty()) {
3508 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3512 ret = load_session (session_path, session_name, template_name);
3515 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3516 exit (EXIT_FAILURE);
3519 /* clear this to avoid endless attempts to load the
3523 ARDOUR_COMMAND_LINE::session_name = "";
3527 _session_dialog = NULL;
3533 ARDOUR_UI::close_session()
3535 if (!check_audioengine (_main_window)) {
3539 if (unload_session (true)) {
3543 ARDOUR_COMMAND_LINE::session_name = "";
3545 if (get_session_parameters (true, false)) {
3546 exit (EXIT_FAILURE);
3550 /** @param snap_name Snapshot name (without .ardour suffix).
3551 * @return -2 if the load failed because we are not connected to the AudioEngine.
3554 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3556 /* load_session calls flush_pending() which allows
3557 * GUI interaction and potentially loading another session
3558 * (that was easy via snapshot sidebar).
3559 * Recursing into load_session() from load_session() and recusive
3560 * event loops causes all kind of crashes.
3562 assert (!session_load_in_progress);
3563 if (session_load_in_progress) {
3566 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3568 Session *new_session;
3573 unload_status = unload_session ();
3575 if (unload_status < 0) {
3577 } else if (unload_status > 0) {
3583 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3586 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3589 /* this one is special */
3591 catch (AudioEngine::PortRegistrationFailure const& err) {
3593 MessageDialog msg (err.what(),
3596 Gtk::BUTTONS_CLOSE);
3598 msg.set_title (_("Port Registration Error"));
3599 msg.set_secondary_text (_("Click the Close button to try again."));
3600 msg.set_position (Gtk::WIN_POS_CENTER);
3601 pop_back_splash (msg);
3604 int response = msg.run ();
3609 case RESPONSE_CANCEL:
3610 exit (EXIT_FAILURE);
3616 catch (SessionException const& e) {
3617 MessageDialog msg (string_compose(
3618 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3619 path, snap_name, e.what()),
3624 msg.set_title (_("Loading Error"));
3625 msg.set_position (Gtk::WIN_POS_CENTER);
3626 pop_back_splash (msg);
3638 MessageDialog msg (string_compose(
3639 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3645 msg.set_title (_("Loading Error"));
3646 msg.set_position (Gtk::WIN_POS_CENTER);
3647 pop_back_splash (msg);
3659 list<string> const u = new_session->unknown_processors ();
3661 MissingPluginDialog d (_session, u);
3666 if (!new_session->writable()) {
3667 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3672 msg.set_title (_("Read-only Session"));
3673 msg.set_position (Gtk::WIN_POS_CENTER);
3674 pop_back_splash (msg);
3681 /* Now the session been created, add the transport controls */
3682 new_session->add_controllable(roll_controllable);
3683 new_session->add_controllable(stop_controllable);
3684 new_session->add_controllable(goto_start_controllable);
3685 new_session->add_controllable(goto_end_controllable);
3686 new_session->add_controllable(auto_loop_controllable);
3687 new_session->add_controllable(play_selection_controllable);
3688 new_session->add_controllable(rec_controllable);
3690 set_session (new_session);
3693 _session->set_clean ();
3696 #ifdef WINDOWS_VST_SUPPORT
3697 fst_stop_threading();
3701 Timers::TimerSuspender t;
3705 #ifdef WINDOWS_VST_SUPPORT
3706 fst_start_threading();
3710 if (!mix_template.empty ()) {
3711 /* if mix_template is given, assume this is a new session */
3712 string metascript = Glib::build_filename (mix_template, "template.lua");
3713 meta_session_setup (metascript);
3718 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3719 * which is queued by set_session().
3720 * If session-loading fails we hide it explicitly.
3721 * This covers both cases in a central place.
3730 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3732 Session *new_session;
3735 x = unload_session ();
3743 _session_is_new = true;
3746 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3749 catch (SessionException const& e) {
3750 cerr << "Here are the errors associated with this failed session:\n";
3752 cerr << "---------\n";
3753 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3754 msg.set_title (_("Loading Error"));
3755 msg.set_position (Gtk::WIN_POS_CENTER);
3756 pop_back_splash (msg);
3761 cerr << "Here are the errors associated with this failed session:\n";
3763 cerr << "---------\n";
3764 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3765 msg.set_title (_("Loading Error"));
3766 msg.set_position (Gtk::WIN_POS_CENTER);
3767 pop_back_splash (msg);
3772 /* Give the new session the default GUI state, if such things exist */
3775 n = Config->instant_xml (X_("Editor"));
3777 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3778 new_session->add_instant_xml (*n, false);
3780 n = Config->instant_xml (X_("Mixer"));
3782 new_session->add_instant_xml (*n, false);
3785 n = Config->instant_xml (X_("Preferences"));
3787 new_session->add_instant_xml (*n, false);
3790 /* Put the playhead at 0 and scroll fully left */
3791 n = new_session->instant_xml (X_("Editor"));
3793 n->set_property (X_("playhead"), X_("0"));
3794 n->set_property (X_("left-frame"), X_("0"));
3797 set_session (new_session);
3799 new_session->save_state(new_session->name());
3805 static void _lua_print (std::string s) {
3807 std::cout << "LuaInstance: " << s << "\n";
3809 PBD::info << "LuaInstance: " << s << endmsg;
3812 std::map<std::string, std::string>
3813 ARDOUR_UI::route_setup_info (const std::string& script_path)
3815 std::map<std::string, std::string> rv;
3817 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3822 lua.Print.connect (&_lua_print);
3825 lua_State* L = lua.getState();
3826 LuaInstance::register_classes (L);
3827 LuaBindings::set_session (L, _session);
3828 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3829 lua_setglobal (L, "Editor");
3831 lua.do_command ("function ardour () end");
3832 lua.do_file (script_path);
3835 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3836 if (!fn.isFunction ()) {
3839 luabridge::LuaRef rs = fn ();
3840 if (!rs.isTable ()) {
3843 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3844 if (!i.key().isString()) {
3847 std::string key = i.key().tostring();
3848 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3849 rv[key] = i.value().tostring();
3852 } catch (luabridge::LuaException const& e) {
3853 cerr << "LuaException:" << e.what () << endl;
3859 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3861 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3864 assert (add_route_dialog);
3867 if ((count = add_route_dialog->count()) <= 0) {
3872 lua.Print.connect (&_lua_print);
3875 lua_State* L = lua.getState();
3876 LuaInstance::register_classes (L);
3877 LuaBindings::set_session (L, _session);
3878 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3879 lua_setglobal (L, "Editor");
3881 lua.do_command ("function ardour () end");
3882 lua.do_file (script_path);
3884 luabridge::LuaRef args (luabridge::newTable (L));
3886 args["name"] = add_route_dialog->name_template ();
3887 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3888 args["group"] = add_route_dialog->route_group ();
3889 args["strict_io"] = add_route_dialog->use_strict_io ();
3890 args["instrument"] = add_route_dialog->requested_instrument ();
3891 args["track_mode"] = add_route_dialog->mode ();
3892 args["channels"] = add_route_dialog->channel_count ();
3893 args["how_many"] = count;
3896 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3897 if (fn.isFunction()) {
3900 } catch (luabridge::LuaException const& e) {
3901 cerr << "LuaException:" << e.what () << endl;
3903 display_insufficient_ports_message ();
3908 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3910 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3915 lua.Print.connect (&_lua_print);
3918 lua_State* L = lua.getState();
3919 LuaInstance::register_classes (L);
3920 LuaBindings::set_session (L, _session);
3921 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3922 lua_setglobal (L, "Editor");
3924 lua.do_command ("function ardour () end");
3925 lua.do_file (script_path);
3928 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3929 if (fn.isFunction()) {
3932 } catch (luabridge::LuaException const& e) {
3933 cerr << "LuaException:" << e.what () << endl;
3935 display_insufficient_ports_message ();
3940 ARDOUR_UI::launch_chat ()
3942 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3944 dialog.set_title (_("About the Chat"));
3945 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."));
3947 switch (dialog.run()) {
3949 open_uri("http://webchat.freenode.net/?channels=ardour");
3957 ARDOUR_UI::launch_manual ()
3959 PBD::open_uri (Config->get_tutorial_manual_url());
3963 ARDOUR_UI::launch_reference ()
3965 PBD::open_uri (Config->get_reference_manual_url());
3969 ARDOUR_UI::launch_tracker ()
3971 PBD::open_uri ("http://tracker.ardour.org");
3975 ARDOUR_UI::launch_subscribe ()
3977 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3981 ARDOUR_UI::launch_cheat_sheet ()
3984 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3986 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3991 ARDOUR_UI::launch_website ()
3993 PBD::open_uri ("http://ardour.org");
3997 ARDOUR_UI::launch_website_dev ()
3999 PBD::open_uri ("http://ardour.org/development.html");
4003 ARDOUR_UI::launch_forums ()
4005 PBD::open_uri ("https://community.ardour.org/forums");
4009 ARDOUR_UI::launch_howto_report ()
4011 PBD::open_uri ("http://ardour.org/reporting_bugs");
4015 ARDOUR_UI::loading_message (const std::string& msg)
4017 if (ARDOUR_COMMAND_LINE::no_splash) {
4025 splash->message (msg);
4029 ARDOUR_UI::show_splash ()
4033 splash = new Splash;
4043 ARDOUR_UI::hide_splash ()
4050 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4054 removed = rep.paths.size();
4057 MessageDialog msgd (_main_window,
4058 _("No files were ready for clean-up"),
4062 msgd.set_title (_("Clean-up"));
4063 msgd.set_secondary_text (_("If this seems surprising, \n\
4064 check for any existing snapshots.\n\
4065 These may still include regions that\n\
4066 require some unused files to continue to exist."));
4072 ArdourDialog results (_("Clean-up"), true, false);
4074 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4075 CleanupResultsModelColumns() {
4079 Gtk::TreeModelColumn<std::string> visible_name;
4080 Gtk::TreeModelColumn<std::string> fullpath;
4084 CleanupResultsModelColumns results_columns;
4085 Glib::RefPtr<Gtk::ListStore> results_model;
4086 Gtk::TreeView results_display;
4088 results_model = ListStore::create (results_columns);
4089 results_display.set_model (results_model);
4090 results_display.append_column (list_title, results_columns.visible_name);
4092 results_display.set_name ("CleanupResultsList");
4093 results_display.set_headers_visible (true);
4094 results_display.set_headers_clickable (false);
4095 results_display.set_reorderable (false);
4097 Gtk::ScrolledWindow list_scroller;
4100 Gtk::HBox dhbox; // the hbox for the image and text
4101 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4102 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4104 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4106 const string dead_directory = _session->session_directory().dead_path();
4109 %1 - number of files removed
4110 %2 - location of "dead"
4111 %3 - size of files affected
4112 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4115 const char* bprefix;
4116 double space_adjusted = 0;
4118 if (rep.space < 1000) {
4120 space_adjusted = rep.space;
4121 } else if (rep.space < 1000000) {
4122 bprefix = _("kilo");
4123 space_adjusted = floorf((float)rep.space / 1000.0);
4124 } else if (rep.space < 1000000 * 1000) {
4125 bprefix = _("mega");
4126 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4128 bprefix = _("giga");
4129 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4133 txt.set_markup (string_compose (P_("\
4134 The following file was deleted from %2,\n\
4135 releasing %3 %4bytes of disk space", "\
4136 The following %1 files were deleted from %2,\n\
4137 releasing %3 %4bytes of disk space", removed),
4138 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4140 txt.set_markup (string_compose (P_("\
4141 The following file was not in use and \n\
4142 has been moved to: %2\n\n\
4143 After a restart of %5\n\n\
4144 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4145 will release an additional %3 %4bytes of disk space.\n", "\
4146 The following %1 files were not in use and \n\
4147 have been moved to: %2\n\n\
4148 After a restart of %5\n\n\
4149 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4150 will release an additional %3 %4bytes of disk space.\n", removed),
4151 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4154 dhbox.pack_start (*dimage, true, false, 5);
4155 dhbox.pack_start (txt, true, false, 5);
4157 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4158 TreeModel::Row row = *(results_model->append());
4159 row[results_columns.visible_name] = *i;
4160 row[results_columns.fullpath] = *i;
4163 list_scroller.add (results_display);
4164 list_scroller.set_size_request (-1, 150);
4165 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4167 dvbox.pack_start (dhbox, true, false, 5);
4168 dvbox.pack_start (list_scroller, true, false, 5);
4169 ddhbox.pack_start (dvbox, true, false, 5);
4171 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4172 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4173 results.set_default_response (RESPONSE_CLOSE);
4174 results.set_position (Gtk::WIN_POS_MOUSE);
4176 results_display.show();
4177 list_scroller.show();
4184 //results.get_vbox()->show();
4185 results.set_resizable (false);
4192 ARDOUR_UI::cleanup ()
4194 if (_session == 0) {
4195 /* shouldn't happen: menu item is insensitive */
4200 MessageDialog checker (_("Are you sure you want to clean-up?"),
4202 Gtk::MESSAGE_QUESTION,
4205 checker.set_title (_("Clean-up"));
4207 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4208 ALL undo/redo information will be lost if you clean-up.\n\
4209 Clean-up will move all unused files to a \"dead\" location."));
4211 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4212 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4213 checker.set_default_response (RESPONSE_CANCEL);
4215 checker.set_name (_("CleanupDialog"));
4216 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4217 checker.set_position (Gtk::WIN_POS_MOUSE);
4219 switch (checker.run()) {
4220 case RESPONSE_ACCEPT:
4227 ARDOUR::CleanupReport rep;
4229 editor->prepare_for_cleanup ();
4231 /* do not allow flush until a session is reloaded */
4232 ActionManager::get_action (X_("Main"), X_("FlushWastebasket"))->set_sensitive (false);
4234 if (_session->cleanup_sources (rep)) {
4235 editor->finish_cleanup ();
4239 editor->finish_cleanup ();
4241 display_cleanup_results (rep, _("Cleaned Files"), false);
4245 ARDOUR_UI::flush_trash ()
4247 if (_session == 0) {
4248 /* shouldn't happen: menu item is insensitive */
4252 ARDOUR::CleanupReport rep;
4254 if (_session->cleanup_trash_sources (rep)) {
4258 display_cleanup_results (rep, _("deleted file"), true);
4262 ARDOUR_UI::cleanup_peakfiles ()
4264 if (_session == 0) {
4265 /* shouldn't happen: menu item is insensitive */
4269 if (! _session->can_cleanup_peakfiles ()) {
4273 // get all region-views in this session
4275 TrackViewList empty;
4277 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4278 std::list<RegionView*> views = rs.by_layer();
4280 // remove displayed audio-region-views waveforms
4281 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4282 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4283 if (!arv) { continue ; }
4284 arv->delete_waves();
4287 // cleanup peak files:
4288 // - stop pending peakfile threads
4289 // - close peakfiles if any
4290 // - remove peak dir in session
4291 // - setup peakfiles (background thread)
4292 _session->cleanup_peakfiles ();
4294 // re-add waves to ARV
4295 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4296 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4297 if (!arv) { continue ; }
4298 arv->create_waves();
4302 PresentationInfo::order_t
4303 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4305 if (editor->get_selection().tracks.empty()) {
4306 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4309 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4312 we want the new routes to have their order keys set starting from
4313 the highest order key in the selection + 1 (if available).
4316 if (place == RouteDialogs::AfterSelection) {
4317 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4319 order_hint = rtav->route()->presentation_info().order();
4322 } else if (place == RouteDialogs::BeforeSelection) {
4323 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4325 order_hint = rtav->route()->presentation_info().order();
4327 } else if (place == RouteDialogs::First) {
4330 /* leave order_hint at max_order */
4337 ARDOUR_UI::start_duplicate_routes ()
4339 if (!duplicate_routes_dialog) {
4340 duplicate_routes_dialog = new DuplicateRouteDialog;
4343 if (duplicate_routes_dialog->restart (_session)) {
4347 duplicate_routes_dialog->present ();
4351 ARDOUR_UI::add_route ()
4353 if (!add_route_dialog.get (false)) {
4354 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4361 if (add_route_dialog->is_visible()) {
4362 /* we're already doing this */
4366 add_route_dialog->set_position (WIN_POS_MOUSE);
4367 add_route_dialog->present();
4371 ARDOUR_UI::add_route_dialog_response (int r)
4374 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4378 if (!AudioEngine::instance()->running ()) {
4380 case AddRouteDialog::Add:
4381 case AddRouteDialog::AddAndClose:
4386 add_route_dialog->ArdourDialog::on_response (r);
4387 ARDOUR_UI_UTILS::engine_is_running ();
4394 case AddRouteDialog::Add:
4395 add_route_dialog->reset_name_edited ();
4397 case AddRouteDialog::AddAndClose:
4398 add_route_dialog->ArdourDialog::on_response (r);
4401 add_route_dialog->ArdourDialog::on_response (r);
4405 std::string template_path = add_route_dialog->get_template_path();
4406 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4407 meta_route_setup (template_path.substr (11));
4411 if ((count = add_route_dialog->count()) <= 0) {
4415 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4416 const string name_template = add_route_dialog->name_template ();
4417 DisplaySuspender ds;
4419 if (!template_path.empty ()) {
4420 if (add_route_dialog->name_template_is_default ()) {
4421 _session->new_route_from_template (count, order, template_path, string ());
4423 _session->new_route_from_template (count, order, template_path, name_template);
4428 ChanCount input_chan= add_route_dialog->channels ();
4429 ChanCount output_chan;
4430 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4431 RouteGroup* route_group = add_route_dialog->route_group ();
4432 AutoConnectOption oac = Config->get_output_auto_connect();
4433 bool strict_io = add_route_dialog->use_strict_io ();
4435 if (oac & AutoConnectMaster) {
4436 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4437 output_chan.set (DataType::MIDI, 0);
4439 output_chan = input_chan;
4442 /* XXX do something with name template */
4444 Session::ProcessorChangeBlocker pcb (_session);
4446 switch (add_route_dialog->type_wanted()) {
4447 case AddRouteDialog::AudioTrack:
4448 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);
4450 case AddRouteDialog::MidiTrack:
4451 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4453 case AddRouteDialog::MixedTrack:
4454 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4456 case AddRouteDialog::AudioBus:
4457 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4459 case AddRouteDialog::MidiBus:
4460 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4462 case AddRouteDialog::VCAMaster:
4463 _session->vca_manager().create_vca (count, name_template);
4465 case AddRouteDialog::FoldbackBus:
4466 session_add_foldback_bus (input_chan.n_audio(), count, name_template);
4472 ARDOUR_UI::stop_video_server (bool ask_confirm)
4474 if (!video_server_process && ask_confirm) {
4475 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4477 if (video_server_process) {
4479 ArdourDialog confirm (_("Stop Video-Server"), true);
4480 Label m (_("Do you really want to stop the Video Server?"));
4481 confirm.get_vbox()->pack_start (m, true, true);
4482 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4483 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4484 confirm.show_all ();
4485 if (confirm.run() == RESPONSE_CANCEL) {
4489 delete video_server_process;
4490 video_server_process =0;
4495 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4497 ARDOUR_UI::start_video_server( float_window, true);
4501 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4507 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4508 if (video_server_process) {
4509 popup_error(_("The Video Server is already started."));
4511 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4517 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4519 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4521 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4523 video_server_dialog->set_transient_for (*float_window);
4526 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4527 video_server_dialog->hide();
4529 ResponseType r = (ResponseType) video_server_dialog->run ();
4530 video_server_dialog->hide();
4531 if (r != RESPONSE_ACCEPT) { return false; }
4532 if (video_server_dialog->show_again()) {
4533 Config->set_show_video_server_dialog(false);
4537 std::string icsd_exec = video_server_dialog->get_exec_path();
4538 std::string icsd_docroot = video_server_dialog->get_docroot();
4539 #ifndef PLATFORM_WINDOWS
4540 if (icsd_docroot.empty()) {
4541 icsd_docroot = VideoUtils::video_get_docroot (Config);
4546 #ifdef PLATFORM_WINDOWS
4547 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4548 /* OK, allow all drive letters */
4551 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4552 warning << _("Specified docroot is not an existing directory.") << endmsg;
4555 #ifndef PLATFORM_WINDOWS
4556 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4557 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4558 warning << _("Given Video Server is not an executable file.") << endmsg;
4562 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4563 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4564 warning << _("Given Video Server is not an executable file.") << endmsg;
4570 argp=(char**) calloc(9,sizeof(char*));
4571 argp[0] = strdup(icsd_exec.c_str());
4572 argp[1] = strdup("-P");
4573 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4574 argp[3] = strdup("-p");
4575 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4576 argp[5] = strdup("-C");
4577 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4578 argp[7] = strdup(icsd_docroot.c_str());
4580 stop_video_server();
4582 #ifdef PLATFORM_WINDOWS
4583 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4584 /* OK, allow all drive letters */
4587 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4588 Config->set_video_advanced_setup(false);
4590 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4591 Config->set_video_server_url(url_str);
4592 Config->set_video_server_docroot(icsd_docroot);
4593 Config->set_video_advanced_setup(true);
4596 if (video_server_process) {
4597 delete video_server_process;
4600 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4601 if (video_server_process->start()) {
4602 warning << _("Cannot launch the video-server") << endmsg;
4605 int timeout = 120; // 6 sec
4606 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4607 Glib::usleep (50000);
4609 if (--timeout <= 0 || !video_server_process->is_running()) break;
4612 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4614 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4615 delete video_server_process;
4616 video_server_process = 0;
4624 ARDOUR_UI::add_video (Gtk::Window* float_window)
4630 if (!start_video_server(float_window, false)) {
4631 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4636 add_video_dialog->set_transient_for (*float_window);
4639 if (add_video_dialog->is_visible()) {
4640 /* we're already doing this */
4644 ResponseType r = (ResponseType) add_video_dialog->run ();
4645 add_video_dialog->hide();
4646 if (r != RESPONSE_ACCEPT) { return; }
4648 bool local_file, orig_local_file;
4649 std::string path = add_video_dialog->file_name(local_file);
4651 std::string orig_path = path;
4652 orig_local_file = local_file;
4654 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4656 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4657 warning << string_compose(_("could not open %1"), path) << endmsg;
4660 if (!local_file && path.length() == 0) {
4661 warning << _("no video-file selected") << endmsg;
4665 std::string audio_from_video;
4666 bool detect_ltc = false;
4668 switch (add_video_dialog->import_option()) {
4669 case VTL_IMPORT_TRANSCODE:
4671 TranscodeVideoDialog *transcode_video_dialog;
4672 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4673 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4674 transcode_video_dialog->hide();
4675 if (r != RESPONSE_ACCEPT) {
4676 delete transcode_video_dialog;
4680 audio_from_video = transcode_video_dialog->get_audiofile();
4682 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4685 else if (!audio_from_video.empty()) {
4686 editor->embed_audio_from_video(
4688 video_timeline->get_offset(),
4689 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4692 switch (transcode_video_dialog->import_option()) {
4693 case VTL_IMPORT_TRANSCODED:
4694 path = transcode_video_dialog->get_filename();
4697 case VTL_IMPORT_REFERENCE:
4700 delete transcode_video_dialog;
4703 delete transcode_video_dialog;
4707 case VTL_IMPORT_NONE:
4711 /* strip _session->session_directory().video_path() from video file if possible */
4712 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4713 path=path.substr(_session->session_directory().video_path().size());
4714 if (path.at(0) == G_DIR_SEPARATOR) {
4715 path=path.substr(1);
4719 video_timeline->set_update_session_fps(auto_set_session_fps);
4721 if (video_timeline->video_file_info(path, local_file)) {
4722 XMLNode* node = new XMLNode(X_("Videotimeline"));
4723 node->set_property (X_("Filename"), path);
4724 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4725 node->set_property (X_("LocalFile"), local_file);
4726 if (orig_local_file) {
4727 node->set_property (X_("OriginalVideoFile"), orig_path);
4729 node->remove_property (X_("OriginalVideoFile"));
4731 _session->add_extra_xml (*node);
4732 _session->set_dirty ();
4734 if (!audio_from_video.empty() && detect_ltc) {
4735 std::vector<LTCFileReader::LTCMap> ltc_seq;
4738 /* TODO ask user about TV standard (LTC alignment if any) */
4739 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4740 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4742 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4744 /* TODO seek near end of file, and read LTC until end.
4745 * if it fails to find any LTC samples, scan complete file
4747 * calculate drift of LTC compared to video-duration,
4748 * ask user for reference (timecode from start/mid/end)
4751 // LTCFileReader will have written error messages
4754 ::g_unlink(audio_from_video.c_str());
4756 if (ltc_seq.size() == 0) {
4757 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4759 /* the very first TC in the file is somteimes not aligned properly */
4760 int i = ltc_seq.size() -1;
4761 ARDOUR::sampleoffset_t video_start_offset =
4762 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4763 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4764 video_timeline->set_offset(video_start_offset);
4768 _session->maybe_update_session_range(
4769 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4770 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4773 if (add_video_dialog->launch_xjadeo() && local_file) {
4774 editor->set_xjadeo_sensitive(true);
4775 editor->toggle_xjadeo_proc(1);
4777 editor->toggle_xjadeo_proc(0);
4779 editor->toggle_ruler_video(true);
4784 ARDOUR_UI::remove_video ()
4786 video_timeline->close_session();
4787 editor->toggle_ruler_video(false);
4790 video_timeline->set_offset_locked(false);
4791 video_timeline->set_offset(0);
4793 /* delete session state */
4794 XMLNode* node = new XMLNode(X_("Videotimeline"));
4795 _session->add_extra_xml(*node);
4796 node = new XMLNode(X_("Videomonitor"));
4797 _session->add_extra_xml(*node);
4798 node = new XMLNode(X_("Videoexport"));
4799 _session->add_extra_xml(*node);
4800 stop_video_server();
4804 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4806 if (localcacheonly) {
4807 video_timeline->vmon_update();
4809 video_timeline->flush_cache();
4811 editor->queue_visual_videotimeline_update();
4815 ARDOUR_UI::export_video (bool range)
4817 if (ARDOUR::Config->get_show_video_export_info()) {
4818 ExportVideoInfobox infobox (_session);
4819 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4820 if (infobox.show_again()) {
4821 ARDOUR::Config->set_show_video_export_info(false);
4824 case GTK_RESPONSE_YES:
4825 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4831 export_video_dialog->set_session (_session);
4832 export_video_dialog->apply_state(editor->get_selection().time, range);
4833 export_video_dialog->run ();
4834 export_video_dialog->hide ();
4838 ARDOUR_UI::preferences_settings () const
4843 node = _session->instant_xml(X_("Preferences"));
4845 node = Config->instant_xml(X_("Preferences"));
4849 node = new XMLNode (X_("Preferences"));
4856 ARDOUR_UI::mixer_settings () const
4861 node = _session->instant_xml(X_("Mixer"));
4863 node = Config->instant_xml(X_("Mixer"));
4867 node = new XMLNode (X_("Mixer"));
4874 ARDOUR_UI::main_window_settings () const
4879 node = _session->instant_xml(X_("Main"));
4881 node = Config->instant_xml(X_("Main"));
4885 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4886 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4891 node = new XMLNode (X_("Main"));
4898 ARDOUR_UI::editor_settings () const
4903 node = _session->instant_xml(X_("Editor"));
4905 node = Config->instant_xml(X_("Editor"));
4909 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4910 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4915 node = new XMLNode (X_("Editor"));
4922 ARDOUR_UI::keyboard_settings () const
4926 node = Config->extra_xml(X_("Keyboard"));
4929 node = new XMLNode (X_("Keyboard"));
4936 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4939 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4940 _session->locations()->add (location);
4945 ARDOUR_UI::halt_on_xrun_message ()
4947 cerr << "HALT on xrun\n";
4948 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4953 ARDOUR_UI::xrun_handler (samplepos_t where)
4959 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4961 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4962 create_xrun_marker(where);
4965 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4966 halt_on_xrun_message ();
4971 ARDOUR_UI::disk_overrun_handler ()
4973 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4975 if (!have_disk_speed_dialog_displayed) {
4976 have_disk_speed_dialog_displayed = true;
4977 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4978 The disk system on your computer\n\
4979 was not able to keep up with %1.\n\
4981 Specifically, it failed to write data to disk\n\
4982 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4983 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4989 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4990 static MessageDialog *scan_dlg = NULL;
4991 static ProgressBar *scan_pbar = NULL;
4992 static HBox *scan_tbox = NULL;
4993 static Gtk::Button *scan_timeout_button;
4996 ARDOUR_UI::cancel_plugin_scan ()
4998 PluginManager::instance().cancel_plugin_scan();
5002 ARDOUR_UI::cancel_plugin_timeout ()
5004 PluginManager::instance().cancel_plugin_timeout();
5005 scan_timeout_button->set_sensitive (false);
5009 ARDOUR_UI::plugin_scan_timeout (int timeout)
5011 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5015 scan_pbar->set_sensitive (false);
5016 scan_timeout_button->set_sensitive (true);
5017 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5020 scan_pbar->set_sensitive (false);
5021 scan_timeout_button->set_sensitive (false);
5027 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5029 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5033 const bool cancelled = PluginManager::instance().cancelled();
5034 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5035 if (cancelled && scan_dlg->is_mapped()) {
5040 if (cancelled || !can_cancel) {
5045 static Gtk::Button *cancel_button;
5047 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5048 VBox* vbox = scan_dlg->get_vbox();
5049 vbox->set_size_request(400,-1);
5050 scan_dlg->set_title (_("Scanning for plugins"));
5052 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5053 cancel_button->set_name ("EditorGTKButton");
5054 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5055 cancel_button->show();
5057 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5059 scan_tbox = manage( new HBox() );
5061 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5062 scan_timeout_button->set_name ("EditorGTKButton");
5063 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5064 scan_timeout_button->show();
5066 scan_pbar = manage(new ProgressBar());
5067 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5068 scan_pbar->set_text(_("Scan Timeout"));
5071 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5072 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5074 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5077 assert(scan_dlg && scan_tbox && cancel_button);
5079 if (type == X_("closeme")) {
5083 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5086 if (!can_cancel || !cancelled) {
5087 scan_timeout_button->set_sensitive(false);
5089 cancel_button->set_sensitive(can_cancel && !cancelled);
5095 ARDOUR_UI::gui_idle_handler ()
5098 /* due to idle calls, gtk_events_pending() may always return true */
5099 while (gtk_events_pending() && --timeout) {
5100 gtk_main_iteration ();
5105 ARDOUR_UI::disk_underrun_handler ()
5107 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5109 if (!have_disk_speed_dialog_displayed) {
5110 have_disk_speed_dialog_displayed = true;
5111 MessageDialog* msg = new MessageDialog (
5112 _main_window, string_compose (_("The disk system on your computer\n\
5113 was not able to keep up with %1.\n\
5115 Specifically, it failed to read data from disk\n\
5116 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5117 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5123 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5125 have_disk_speed_dialog_displayed = false;
5130 ARDOUR_UI::session_dialog (std::string msg)
5132 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5136 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5143 ARDOUR_UI::pending_state_dialog ()
5145 HBox* hbox = manage (new HBox());
5146 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5147 ArdourDialog dialog (_("Crash Recovery"), true);
5148 Label message (string_compose (_("\
5149 This session appears to have been in the\n\
5150 middle of recording when %1 or\n\
5151 the computer was shutdown.\n\
5153 %1 can recover any captured audio for\n\
5154 you, or it can ignore it. Please decide\n\
5155 what you would like to do.\n"), PROGRAM_NAME));
5156 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5157 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5158 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5159 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5160 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5161 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5162 dialog.set_default_response (RESPONSE_ACCEPT);
5163 dialog.set_position (WIN_POS_CENTER);
5168 switch (dialog.run ()) {
5169 case RESPONSE_ACCEPT:
5177 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5179 HBox* hbox = new HBox();
5180 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5181 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5182 Label message (string_compose (_("\
5183 This session was created with a sample rate of %1 Hz, but\n\
5184 %2 is currently running at %3 Hz. If you load this session,\n\
5185 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5187 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5188 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5189 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5190 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5191 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5192 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5193 dialog.set_default_response (RESPONSE_ACCEPT);
5194 dialog.set_position (WIN_POS_CENTER);
5199 switch (dialog.run()) {
5200 case RESPONSE_ACCEPT:
5210 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5212 MessageDialog msg (string_compose (_("\
5213 This session was created with a sample rate of %1 Hz, but\n\
5214 %2 is currently running at %3 Hz.\n\
5215 Audio will be recorded and played at the wrong sample rate.\n\
5216 Re-Configure the Audio Engine in\n\
5217 Menu > Window > Audio/Midi Setup"),
5218 desired, PROGRAM_NAME, actual),
5220 Gtk::MESSAGE_WARNING);
5225 ARDOUR_UI::use_config ()
5227 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5229 set_transport_controllable_state (*node);
5234 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5236 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5238 primary_clock->set (pos);
5240 case DeltaEditPoint:
5241 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5243 case DeltaOriginMarker:
5245 Location* loc = _session->locations()->clock_origin_location ();
5246 primary_clock->set (pos, false, loc ? loc->start() : 0);
5251 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5253 secondary_clock->set (pos);
5255 case DeltaEditPoint:
5256 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5258 case DeltaOriginMarker:
5260 Location* loc = _session->locations()->clock_origin_location ();
5261 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5266 if (big_clock_window) {
5267 big_clock->set (pos);
5269 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5274 ARDOUR_UI::record_state_changed ()
5276 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5279 /* why bother - the clock isn't visible */
5283 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5285 if (big_clock_window) {
5286 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5287 big_clock->set_active (true);
5289 big_clock->set_active (false);
5296 ARDOUR_UI::first_idle ()
5299 _session->allow_auto_play (true);
5303 editor->first_idle();
5306 /* in 1 second, hide the splash screen
5308 * Consider hiding it *now*. If a user opens opens a dialog
5309 * during that one second while the splash is still visible,
5310 * the dialog will push-back the splash.
5311 * Closing the dialog later will pop it back.
5313 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5315 Keyboard::set_can_save_keybindings (true);
5320 ARDOUR_UI::store_clock_modes ()
5322 XMLNode* node = new XMLNode(X_("ClockModes"));
5324 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5325 XMLNode* child = new XMLNode (X_("Clock"));
5327 child->set_property (X_("name"), (*x)->name());
5328 child->set_property (X_("mode"), (*x)->mode());
5329 child->set_property (X_("on"), (*x)->on());
5331 node->add_child_nocopy (*child);
5334 _session->add_extra_xml (*node);
5335 _session->set_dirty ();
5339 ARDOUR_UI::setup_profile ()
5341 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5342 Profile->set_small_screen ();
5345 if (g_getenv ("TRX")) {
5346 Profile->set_trx ();
5349 if (g_getenv ("MIXBUS")) {
5350 Profile->set_mixbus ();
5355 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5357 MissingFileDialog dialog (s, str, type);
5362 int result = dialog.run ();
5369 return 1; // quit entire session load
5372 result = dialog.get_action ();
5378 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5380 AmbiguousFileDialog dialog (file, hits);
5387 return dialog.get_which ();
5390 /** Allocate our thread-local buffers */
5392 ARDOUR_UI::get_process_buffers ()
5394 _process_thread->get_buffers ();
5397 /** Drop our thread-local buffers */
5399 ARDOUR_UI::drop_process_buffers ()
5401 _process_thread->drop_buffers ();
5405 ARDOUR_UI::feedback_detected ()
5407 _feedback_exists = true;
5411 ARDOUR_UI::successful_graph_sort ()
5413 _feedback_exists = false;
5417 ARDOUR_UI::midi_panic ()
5420 _session->midi_panic();
5425 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5427 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5428 const char* end_big = "</span>";
5429 const char* start_mono = "<tt>";
5430 const char* end_mono = "</tt>";
5432 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5433 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5434 "From now on, use the backup copy with older versions of %3"),
5435 xml_path, backup_path, PROGRAM_NAME,
5437 start_mono, end_mono), true);
5443 ARDOUR_UI::reset_peak_display ()
5445 if (!_session || !_session->master_out() || !editor_meter) return;
5446 editor_meter->clear_meters();
5447 editor_meter_max_peak = -INFINITY;
5448 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5452 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5454 if (!_session || !_session->master_out()) return;
5455 if (group == _session->master_out()->route_group()) {
5456 reset_peak_display ();
5461 ARDOUR_UI::reset_route_peak_display (Route* route)
5463 if (!_session || !_session->master_out()) return;
5464 if (_session->master_out().get() == route) {
5465 reset_peak_display ();
5470 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5472 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5473 audio_midi_setup->set_position (WIN_POS_CENTER);
5475 if (desired_sample_rate != 0) {
5476 if (Config->get_try_autostart_engine () || g_getenv ("ARDOUR_TRY_AUTOSTART_ENGINE")) {
5477 audio_midi_setup->try_autostart ();
5478 if (ARDOUR::AudioEngine::instance()->running()) {
5485 int response = audio_midi_setup->run();
5487 case Gtk::RESPONSE_DELETE_EVENT:
5488 // after latency callibration engine may run,
5489 // Running() signal was emitted, but dialog will not
5490 // have emitted a response. The user needs to close
5491 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5492 if (!AudioEngine::instance()->running()) {
5497 if (!AudioEngine::instance()->running()) {
5500 audio_midi_setup->hide ();
5508 ARDOUR_UI::transport_numpad_timeout ()
5510 _numpad_locate_happening = false;
5511 if (_numpad_timeout_connection.connected() )
5512 _numpad_timeout_connection.disconnect();
5517 ARDOUR_UI::transport_numpad_decimal ()
5519 _numpad_timeout_connection.disconnect();
5521 if (_numpad_locate_happening) {
5522 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5523 _numpad_locate_happening = false;
5525 _pending_locate_num = 0;
5526 _numpad_locate_happening = true;
5527 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5532 ARDOUR_UI::transport_numpad_event (int num)
5534 if ( _numpad_locate_happening ) {
5535 _pending_locate_num = _pending_locate_num*10 + num;
5538 case 0: toggle_roll(false, false); break;
5539 case 1: transport_rewind(1); break;
5540 case 2: transport_forward(1); break;
5541 case 3: transport_record(true); break;
5542 case 4: toggle_session_auto_loop(); break;
5543 case 5: transport_record(false); toggle_session_auto_loop(); break;
5544 case 6: toggle_punch(); break;
5545 case 7: toggle_click(); break;
5546 case 8: toggle_auto_return(); break;
5547 case 9: toggle_follow_edits(); break;
5553 ARDOUR_UI::set_flat_buttons ()
5555 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5559 ARDOUR_UI::audioengine_became_silent ()
5561 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5563 Gtk::MESSAGE_WARNING,
5567 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5569 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5570 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5571 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5572 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5573 Gtk::HBox pay_button_box;
5574 Gtk::HBox subscribe_button_box;
5576 pay_button_box.pack_start (pay_button, true, false);
5577 subscribe_button_box.pack_start (subscribe_button, true, false);
5579 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 */
5581 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5582 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5584 msg.get_vbox()->pack_start (pay_label);
5585 msg.get_vbox()->pack_start (pay_button_box);
5586 msg.get_vbox()->pack_start (subscribe_label);
5587 msg.get_vbox()->pack_start (subscribe_button_box);
5589 msg.get_vbox()->show_all ();
5591 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5592 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5593 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5598 case Gtk::RESPONSE_YES:
5599 AudioEngine::instance()->reset_silence_countdown ();
5602 case Gtk::RESPONSE_NO:
5604 save_state_canfail ("");
5605 exit (EXIT_SUCCESS);
5608 case Gtk::RESPONSE_CANCEL:
5610 /* don't reset, save session and exit */
5616 ARDOUR_UI::hide_application ()
5618 Application::instance ()-> hide ();
5622 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5624 /* icons, titles, WM stuff */
5626 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5628 if (window_icons.empty()) {
5629 Glib::RefPtr<Gdk::Pixbuf> icon;
5630 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5631 window_icons.push_back (icon);
5633 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5634 window_icons.push_back (icon);
5636 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5637 window_icons.push_back (icon);
5639 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5640 window_icons.push_back (icon);
5644 if (!window_icons.empty()) {
5645 window.set_default_icon_list (window_icons);
5648 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5650 if (!name.empty()) {
5654 window.set_title (title.get_string());
5655 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5657 window.set_flags (CAN_FOCUS);
5658 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5660 /* This is a hack to ensure that GTK-accelerators continue to
5661 * work. Once we switch over to entirely native bindings, this will be
5662 * unnecessary and should be removed
5664 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5666 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5667 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5668 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5669 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5673 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5675 Gtkmm2ext::Bindings* bindings = 0;
5676 Gtk::Window* window = 0;
5678 /* until we get ardour bindings working, we are not handling key
5682 if (ev->type != GDK_KEY_PRESS) {
5686 if (event_window == &_main_window) {
5688 window = event_window;
5690 /* find current tab contents */
5692 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5694 /* see if it uses the ardour binding system */
5697 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5700 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5704 window = event_window;
5706 /* see if window uses ardour binding system */
5708 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5711 /* An empty binding set is treated as if it doesn't exist */
5713 if (bindings && bindings->empty()) {
5717 return key_press_focus_accelerator_handler (*window, ev, bindings);
5720 static Gtkmm2ext::Bindings*
5721 get_bindings_from_widget_heirarchy (GtkWidget** w)
5726 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5729 *w = gtk_widget_get_parent (*w);
5732 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5736 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5738 GtkWindow* win = window.gobj();
5739 GtkWidget* focus = gtk_window_get_focus (win);
5740 GtkWidget* binding_widget = focus;
5741 bool special_handling_of_unmodified_accelerators = false;
5742 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5746 /* some widget has keyboard focus */
5748 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5750 /* A particular kind of focusable widget currently has keyboard
5751 * focus. All unmodified key events should go to that widget
5752 * first and not be used as an accelerator by default
5755 special_handling_of_unmodified_accelerators = true;
5759 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5760 if (focus_bindings) {
5761 bindings = focus_bindings;
5762 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5767 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",
5770 Gtkmm2ext::show_gdk_event_state (ev->state),
5771 special_handling_of_unmodified_accelerators,
5772 Keyboard::some_magic_widget_has_focus(),
5774 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5775 ((ev->state & mask) ? "yes" : "no"),
5776 window.get_title()));
5778 /* This exists to allow us to override the way GTK handles
5779 key events. The normal sequence is:
5781 a) event is delivered to a GtkWindow
5782 b) accelerators/mnemonics are activated
5783 c) if (b) didn't handle the event, propagate to
5784 the focus widget and/or focus chain
5786 The problem with this is that if the accelerators include
5787 keys without modifiers, such as the space bar or the
5788 letter "e", then pressing the key while typing into
5789 a text entry widget results in the accelerator being
5790 activated, instead of the desired letter appearing
5793 There is no good way of fixing this, but this
5794 represents a compromise. The idea is that
5795 key events involving modifiers (not Shift)
5796 get routed into the activation pathway first, then
5797 get propagated to the focus widget if necessary.
5799 If the key event doesn't involve modifiers,
5800 we deliver to the focus widget first, thus allowing
5801 it to get "normal text" without interference
5804 Of course, this can also be problematic: if there
5805 is a widget with focus, then it will swallow
5806 all "normal text" accelerators.
5810 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5812 /* no special handling or there are modifiers in effect: accelerate first */
5814 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5815 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5816 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5818 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5819 KeyboardKey k (ev->state, ev->keyval);
5823 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5825 if (bindings->activate (k, Bindings::Press)) {
5826 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5830 if (binding_widget) {
5831 binding_widget = gtk_widget_get_parent (binding_widget);
5832 if (binding_widget) {
5833 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5842 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5844 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5845 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5849 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5851 if (gtk_window_propagate_key_event (win, ev)) {
5852 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5858 /* no modifiers, propagate first */
5860 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5862 if (gtk_window_propagate_key_event (win, ev)) {
5863 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5867 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5868 KeyboardKey k (ev->state, ev->keyval);
5872 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5875 if (bindings->activate (k, Bindings::Press)) {
5876 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5880 if (binding_widget) {
5881 binding_widget = gtk_widget_get_parent (binding_widget);
5882 if (binding_widget) {
5883 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5892 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5894 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5895 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5900 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5905 ARDOUR_UI::cancel_solo ()
5908 _session->cancel_all_solo ();
5913 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5915 /* this resets focus to the first focusable parent of the given widget,
5916 * or, if there is no focusable parent, cancels focus in the toplevel
5917 * window that the given widget is packed into (if there is one).
5924 Gtk::Widget* top = w->get_toplevel();
5926 if (!top || !top->is_toplevel()) {
5930 w = w->get_parent ();
5934 if (w->is_toplevel()) {
5935 /* Setting the focus widget to a Gtk::Window causes all
5936 * subsequent calls to ::has_focus() on the nominal
5937 * focus widget in that window to return
5938 * false. Workaround: never set focus to the toplevel
5944 if (w->get_can_focus ()) {
5945 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5946 win->set_focus (*w);
5949 w = w->get_parent ();
5952 if (top == &_main_window) {
5956 /* no focusable parent found, cancel focus in top level window.
5957 C++ API cannot be used for this. Thanks, references.
5960 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
5965 ARDOUR_UI::monitor_dim_all ()
5967 boost::shared_ptr<Route> mon = _session->monitor_out ();
5971 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5973 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
5974 _monitor->set_dim_all (tact->get_active());
5978 ARDOUR_UI::monitor_cut_all ()
5980 boost::shared_ptr<Route> mon = _session->monitor_out ();
5984 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5986 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
5987 _monitor->set_cut_all (tact->get_active());
5991 ARDOUR_UI::monitor_mono ()
5993 boost::shared_ptr<Route> mon = _session->monitor_out ();
5997 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5999 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
6000 _monitor->set_mono (tact->get_active());
6004 ARDOUR_UI::shared_popup_menu ()
6006 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::shared_popup_menu, ignored);
6008 assert (!_shared_popup_menu || !_shared_popup_menu->is_visible());
6009 delete _shared_popup_menu;
6010 _shared_popup_menu = new Gtk::Menu;
6011 return _shared_popup_menu;