2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/accelmap.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/uimanager.h>
55 #include "pbd/error.h"
56 #include "pbd/basename.h"
57 #include "pbd/compose.h"
58 #include "pbd/convert.h"
59 #include "pbd/failed_constructor.h"
60 #include "pbd/file_archive.h"
61 #include "pbd/enumwriter.h"
62 #include "pbd/memento_command.h"
63 #include "pbd/openuri.h"
64 #include "pbd/stl_delete.h"
65 #include "pbd/types_convert.h"
66 #include "pbd/unwind.h"
67 #include "pbd/file_utils.h"
68 #include "pbd/localtime_r.h"
69 #include "pbd/pthread_utils.h"
70 #include "pbd/replace_all.h"
71 #include "pbd/scoped_file_descriptor.h"
72 #include "pbd/xml++.h"
74 #include "gtkmm2ext/application.h"
75 #include "gtkmm2ext/bindings.h"
76 #include "gtkmm2ext/gtk_ui.h"
77 #include "gtkmm2ext/utils.h"
78 #include "gtkmm2ext/window_title.h"
80 #include "widgets/fastmeter.h"
81 #include "widgets/prompter.h"
82 #include "widgets/tooltips.h"
84 #include "ardour/ardour.h"
85 #include "ardour/audio_backend.h"
86 #include "ardour/audio_track.h"
87 #include "ardour/audioengine.h"
88 #include "ardour/audiofilesource.h"
89 #include "ardour/automation_watch.h"
90 #include "ardour/disk_reader.h"
91 #include "ardour/disk_writer.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/filesystem_paths.h"
94 #include "ardour/ltc_file_reader.h"
95 #include "ardour/monitor_control.h"
96 #include "ardour/midi_track.h"
97 #include "ardour/port.h"
98 #include "ardour/plugin_manager.h"
99 #include "ardour/process_thread.h"
100 #include "ardour/profile.h"
101 #include "ardour/recent_sessions.h"
102 #include "ardour/record_enable_control.h"
103 #include "ardour/revision.h"
104 #include "ardour/session_directory.h"
105 #include "ardour/session_route.h"
106 #include "ardour/session_state_utils.h"
107 #include "ardour/session_utils.h"
108 #include "ardour/source_factory.h"
109 #include "ardour/transport_master.h"
110 #include "ardour/transport_master_manager.h"
111 #include "ardour/system_exec.h"
112 #include "ardour/track.h"
113 #include "ardour/vca_manager.h"
114 #include "ardour/utils.h"
116 #include "LuaBridge/LuaBridge.h"
118 #ifdef WINDOWS_VST_SUPPORT
121 #ifdef AUDIOUNIT_SUPPORT
122 #include "ardour/audio_unit.h"
125 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
130 #include "temporal/time.h"
132 typedef uint64_t microseconds_t;
136 #include "enums_convert.h"
138 #include "add_route_dialog.h"
139 #include "ambiguous_file_dialog.h"
140 #include "ardour_ui.h"
141 #include "audio_clock.h"
142 #include "audio_region_view.h"
143 #include "big_clock_window.h"
144 #include "big_transport_window.h"
145 #include "bundle_manager.h"
146 #include "duplicate_routes_dialog.h"
148 #include "engine_dialog.h"
149 #include "export_video_dialog.h"
150 #include "export_video_infobox.h"
151 #include "gain_meter.h"
152 #include "global_port_matrix.h"
153 #include "gui_object.h"
154 #include "gui_thread.h"
155 #include "idleometer.h"
156 #include "keyboard.h"
157 #include "keyeditor.h"
158 #include "location_ui.h"
159 #include "lua_script_manager.h"
160 #include "luawindow.h"
161 #include "main_clock.h"
162 #include "missing_file_dialog.h"
163 #include "missing_plugin_dialog.h"
164 #include "mixer_ui.h"
165 #include "meterbridge.h"
166 #include "meter_patterns.h"
167 #include "mouse_cursors.h"
170 #include "pingback.h"
171 #include "plugin_dspload_window.h"
172 #include "processor_box.h"
173 #include "public_editor.h"
174 #include "rc_option_editor.h"
175 #include "route_time_axis.h"
176 #include "route_params_ui.h"
177 #include "save_as_dialog.h"
178 #include "save_template_dialog.h"
179 #include "script_selector.h"
180 #include "session_archive_dialog.h"
181 #include "session_dialog.h"
182 #include "session_metadata_dialog.h"
183 #include "session_option_editor.h"
184 #include "speaker_dialog.h"
187 #include "template_dialog.h"
188 #include "time_axis_view_item.h"
189 #include "time_info_box.h"
191 #include "transport_masters_dialog.h"
193 #include "utils_videotl.h"
194 #include "video_server_dialog.h"
195 #include "add_video_dialog.h"
196 #include "transcode_video_dialog.h"
198 #include "pbd/i18n.h"
200 using namespace ARDOUR;
201 using namespace ARDOUR_UI_UTILS;
203 using namespace Gtkmm2ext;
204 using namespace ArdourWidgets;
207 using namespace Editing;
209 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
211 sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
212 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
215 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
217 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
218 "Would you like these files to be copied and used for %1 %2.x?\n\n"
219 "(This will require you to restart %1.)"),
220 PROGRAM_NAME, PROGRAM_VERSION, version),
221 false, /* no markup */
224 true /* modal, though it hardly matters since it is the only window */
227 msg.set_default_response (Gtk::RESPONSE_YES);
230 return (msg.run() == Gtk::RESPONSE_YES);
234 libxml_generic_error_func (void* /* parsing_context*/,
242 vsnprintf (buf, sizeof (buf), msg, ap);
243 error << buf << endmsg;
248 libxml_structured_error_func (void* /* parsing_context*/,
256 replace_all (msg, "\n", "");
259 if (err->file && err->line) {
260 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
263 error << ':' << err->int2;
268 error << X_("XML error: ") << msg << endmsg;
274 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
275 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
276 , session_load_in_progress (false)
277 , gui_object_state (new GUIObjectState)
278 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
279 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
280 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
282 , ignore_dual_punch (false)
283 , main_window_visibility (0)
288 , _mixer_on_top (false)
289 , _initial_verbose_plugin_scan (false)
290 , _shared_popup_menu (0)
291 , secondary_clock_spacer (0)
292 , auto_input_button (ArdourButton::led_default_elements)
294 , auto_return_button (ArdourButton::led_default_elements)
295 , follow_edits_button (ArdourButton::led_default_elements)
296 , auditioning_alert_button (_("Audition"))
297 , solo_alert_button (_("Solo"))
298 , feedback_alert_button (_("Feedback"))
299 , error_alert_button ( ArdourButton::just_led_default_elements )
300 , editor_meter_peak_display()
302 , _suspend_editor_meter_callbacks (false)
303 , _numpad_locate_happening (false)
304 , _session_is_new (false)
305 , last_key_press_time (0)
309 , rc_option_editor (0)
310 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
311 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
312 , about (X_("about"), _("About"))
313 , location_ui (X_("locations"), S_("Ranges|Locations"))
314 , route_params (X_("inspector"), _("Tracks and Busses"))
315 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
316 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
317 , lua_script_window (X_("script-manager"), _("Script Manager"))
318 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
319 , plugin_dsp_load_window (X_("plugin-dsp-load"), _("Plugin DSP Load"))
320 , transport_masters_window (X_("transport-masters"), _("Transport Masters"))
321 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
322 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
323 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
324 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
325 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
326 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
327 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
328 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
329 , video_server_process (0)
331 , have_configure_timeout (false)
332 , last_configure_time (0)
334 , have_disk_speed_dialog_displayed (false)
335 , _status_bar_visibility (X_("status-bar"))
336 , _feedback_exists (false)
337 , _log_not_acknowledged (LogLevelNone)
338 , duplicate_routes_dialog (0)
339 , editor_visibility_button (S_("Window|Editor"))
340 , mixer_visibility_button (S_("Window|Mixer"))
341 , prefs_visibility_button (S_("Window|Preferences"))
343 Gtkmm2ext::init (localedir);
345 UIConfiguration::instance().post_gui_init ();
347 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
349 /* "touch" the been-here-before path now that config has been migrated */
350 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
352 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
354 /* configuration was modified, exit immediately */
359 if (string (VERSIONSTRING).find (".pre") != string::npos) {
360 /* check this is not being run from ./ardev etc. */
361 if (!running_from_source_tree ()) {
362 pre_release_dialog ();
366 if (theArdourUI == 0) {
370 /* track main window visibility */
372 main_window_visibility = new VisibilityTracker (_main_window);
374 /* stop libxml from spewing to stdout/stderr */
376 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
377 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
379 /* Set this up early */
381 ActionManager::init ();
383 /* we like keyboards */
385 keyboard = new ArdourKeyboard(*this);
387 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
389 keyboard->set_state (*node, Stateful::loading_state_version);
392 /* actions do not need to be defined when we load keybindings. They
393 * will be lazily discovered. But bindings do need to exist when we
394 * create windows/tabs with their own binding sets.
397 keyboard->setup_keybindings ();
399 if ((global_bindings = Bindings::get_bindings (X_("Global"))) == 0) {
400 error << _("Global keybindings are missing") << endmsg;
405 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
406 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
407 UIConfiguration::instance().map_parameters (pc);
409 transport_ctrl.setup (this);
411 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
412 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
414 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
416 /* handle dialog requests */
418 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
420 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
422 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
424 /* handle Audio/MIDI setup when session requires it */
426 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
428 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
430 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
432 /* handle sr mismatch with a dialog - cross-thread from engine */
433 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
435 /* handle requests to quit (coming from JACK session) */
437 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
439 /* tell the user about feedback */
441 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
442 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
444 /* handle requests to deal with missing files */
446 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
448 /* and ambiguous files */
450 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
452 /* also plugin scan messages */
453 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
454 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
456 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
458 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
461 /* lets get this party started */
463 setup_gtk_ardour_enums ();
466 SessionEvent::create_per_thread_pool ("GUI", 4096);
468 UIConfiguration::instance().reset_dpi ();
470 TimeAxisViewItem::set_constant_heights ();
472 /* The following must happen after ARDOUR::init() so that Config is set up */
474 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
477 key_editor.set_state (*ui_xml, 0);
478 session_option_editor.set_state (*ui_xml, 0);
479 speaker_config_window.set_state (*ui_xml, 0);
480 about.set_state (*ui_xml, 0);
481 add_route_dialog.set_state (*ui_xml, 0);
482 add_video_dialog.set_state (*ui_xml, 0);
483 route_params.set_state (*ui_xml, 0);
484 bundle_manager.set_state (*ui_xml, 0);
485 location_ui.set_state (*ui_xml, 0);
486 big_clock_window.set_state (*ui_xml, 0);
487 big_transport_window.set_state (*ui_xml, 0);
488 audio_port_matrix.set_state (*ui_xml, 0);
489 midi_port_matrix.set_state (*ui_xml, 0);
490 export_video_dialog.set_state (*ui_xml, 0);
491 lua_script_window.set_state (*ui_xml, 0);
492 idleometer.set_state (*ui_xml, 0);
493 plugin_dsp_load_window.set_state (*ui_xml, 0);
494 transport_masters_window.set_state (*ui_xml, 0);
497 /* Separate windows */
499 WM::Manager::instance().register_window (&key_editor);
500 WM::Manager::instance().register_window (&session_option_editor);
501 WM::Manager::instance().register_window (&speaker_config_window);
502 WM::Manager::instance().register_window (&about);
503 WM::Manager::instance().register_window (&add_route_dialog);
504 WM::Manager::instance().register_window (&add_video_dialog);
505 WM::Manager::instance().register_window (&route_params);
506 WM::Manager::instance().register_window (&audio_midi_setup);
507 WM::Manager::instance().register_window (&export_video_dialog);
508 WM::Manager::instance().register_window (&lua_script_window);
509 WM::Manager::instance().register_window (&bundle_manager);
510 WM::Manager::instance().register_window (&location_ui);
511 WM::Manager::instance().register_window (&big_clock_window);
512 WM::Manager::instance().register_window (&big_transport_window);
513 WM::Manager::instance().register_window (&audio_port_matrix);
514 WM::Manager::instance().register_window (&midi_port_matrix);
515 WM::Manager::instance().register_window (&idleometer);
516 WM::Manager::instance().register_window (&plugin_dsp_load_window);
517 WM::Manager::instance().register_window (&transport_masters_window);
519 /* do not retain position for add route dialog */
520 add_route_dialog.set_state_mask (WindowProxy::Size);
522 /* Trigger setting up the color scheme and loading the GTK RC file */
524 UIConfiguration::instance().load_rc_file (false);
526 _process_thread = new ProcessThread ();
527 _process_thread->init ();
529 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
535 ARDOUR_UI::pre_release_dialog ()
537 ArdourDialog d (_("Pre-Release Warning"), true, false);
538 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
540 Label* label = manage (new Label);
541 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
542 There are still several issues and bugs to be worked on,\n\
543 as well as general workflow improvements, before this can be considered\n\
544 release software. So, a few guidelines:\n\
546 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
547 though it may be so, depending on your workflow.\n\
548 2) Please wait for a helpful writeup of new features.\n\
549 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
550 4) <b>Please do NOT file bugs for this alpha-development versions at this point in time</b>.\n\
551 There is no bug triaging before the initial development concludes and\n\
552 reporting issue for incomplete, ongoing work-in-progress is mostly useless.\n\
553 5) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
554 can get there directly from within the program via the Help->Chat menu option.\n\
555 6) Please <b>DO</b> submit patches for issues after discussing them on IRC.\n\
557 Full information on all the above can be found on the support page at\n\
559 http://ardour.org/support\n\
560 "), PROGRAM_NAME, VERSIONSTRING));
562 d.get_vbox()->set_border_width (12);
563 d.get_vbox()->pack_start (*label, false, false, 12);
564 d.get_vbox()->show_all ();
569 GlobalPortMatrixWindow*
570 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
575 return new GlobalPortMatrixWindow (_session, type);
579 ARDOUR_UI::attach_to_engine ()
581 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this, _1), gui_context());
582 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
586 ARDOUR_UI::engine_stopped ()
588 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
589 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
590 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
591 update_sample_rate (0);
596 ARDOUR_UI::engine_running (uint32_t cnt)
603 _session->reset_xrun_count ();
605 update_disk_space ();
607 update_sample_rate (AudioEngine::instance()->sample_rate());
608 update_timecode_format ();
609 update_peak_thread_work ();
610 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
611 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
615 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
617 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
618 /* we can't rely on the original string continuing to exist when we are called
619 again in the GUI thread, so make a copy and note that we need to
622 char *copy = strdup (reason);
623 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
627 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
628 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
630 update_sample_rate (0);
634 /* if the reason is a non-empty string, it means that the backend was shutdown
635 rather than just Ardour.
638 if (strlen (reason)) {
639 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
641 msgstr = string_compose (_("\
642 The audio backend has either been shutdown or it\n\
643 disconnected %1 because %1\n\
644 was not fast enough. Try to restart\n\
645 the audio backend and save the session."), PROGRAM_NAME);
648 MessageDialog msg (_main_window, msgstr);
649 pop_back_splash (msg);
653 free (const_cast<char*> (reason));
658 ARDOUR_UI::post_engine ()
660 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
662 #ifdef AUDIOUNIT_SUPPORT
664 if (AUPluginInfo::au_get_crashlog(au_msg)) {
665 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
666 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
667 info << au_msg << endmsg;
671 /* connect to important signals */
673 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
674 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
675 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
676 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
677 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
679 if (setup_windows ()) {
680 throw failed_constructor ();
683 transport_ctrl.map_actions ();
685 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
686 XMLNode* n = Config->extra_xml (X_("UI"));
688 _status_bar_visibility.set_state (*n);
691 check_memory_locking();
693 /* this is the first point at which all the possible actions are
694 * available, because some of the available actions are dependent on
695 * aspects of the engine/backend.
698 if (ARDOUR_COMMAND_LINE::show_key_actions) {
700 Bindings::save_all_bindings_as_html (sstr);
702 if (sstr.str().empty()) {
709 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
711 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
717 #ifdef PLATFORM_WINDOWS
723 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
724 #ifndef PLATFORM_WINDOWS
727 g_unlink (file_name);
729 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
735 #ifndef PLATFORM_WINDOWS
739 PBD::open_uri (string_compose ("file:///%1", file_name));
741 halt_connection.disconnect ();
742 AudioEngine::instance()->stop ();
747 if (ARDOUR_COMMAND_LINE::show_actions) {
750 vector<string> paths;
751 vector<string> labels;
752 vector<string> tooltips;
754 vector<Glib::RefPtr<Gtk::Action> > actions;
755 string ver_in = revision;
756 string ver = ver_in.substr(0, ver_in.find("-"));
759 output << "\n<h2>Menu actions</h2>" << endl;
760 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
761 output << " surfaces or scripts.\n</p>\n" << endl;
762 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
763 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
764 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
765 output << "<table class=\"dl\">\n <thead>" << endl;
766 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
767 output << " </thead>\n <tbody>" << endl;
769 ActionManager::get_all_actions (paths, labels, tooltips, keys, actions);
771 vector<string>::iterator p;
772 vector<string>::iterator l;
774 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
775 output << " <tr><th><kbd class=\"osc\">" << *p << "</kbd></th><td>" << *l << "</td></tr>" << endl;
777 output << " </tbody>\n </table>" << endl;
779 // output this mess to a browser for easiest X-platform use
780 // it is not pretty HTML, but it works and it's main purpose
781 // is to create raw html to fit in Ardour's manual with no editing
786 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
788 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
794 #ifdef PLATFORM_WINDOWS
800 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
801 #ifndef PLATFORM_WINDOWS
804 g_unlink (file_name);
806 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
812 #ifndef PLATFORM_WINDOWS
816 PBD::open_uri (string_compose ("file:///%1", file_name));
818 halt_connection.disconnect ();
819 AudioEngine::instance()->stop ();
823 /* this being a GUI and all, we want peakfiles */
825 AudioFileSource::set_build_peakfiles (true);
826 AudioFileSource::set_build_missing_peakfiles (true);
828 /* set default clock modes */
830 primary_clock->set_mode (AudioClock::Timecode);
831 secondary_clock->set_mode (AudioClock::BBT);
833 /* start the time-of-day-clock */
836 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
837 update_wall_clock ();
838 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
843 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
844 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
845 Config->map_parameters (pc);
847 UIConfiguration::instance().map_parameters (pc);
851 ARDOUR_UI::~ARDOUR_UI ()
853 UIConfiguration::instance().save_state();
857 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
858 // don't bother at 'real' exit. the OS cleans up for us.
859 delete big_clock; big_clock = 0;
860 delete primary_clock; primary_clock = 0;
861 delete secondary_clock; secondary_clock = 0;
862 delete _process_thread; _process_thread = 0;
863 delete time_info_box; time_info_box = 0;
864 delete meterbridge; meterbridge = 0;
865 delete luawindow; luawindow = 0;
866 delete editor; editor = 0;
867 delete mixer; mixer = 0;
868 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
870 delete gui_object_state; gui_object_state = 0;
871 delete _shared_popup_menu ; _shared_popup_menu = 0;
872 delete main_window_visibility;
873 FastMeter::flush_pattern_cache ();
874 ArdourFader::flush_pattern_cache ();
878 /* Small trick to flush main-thread event pool.
879 * Other thread-pools are destroyed at pthread_exit(),
880 * but tmain thread termination is too late to trigger Pool::~Pool()
882 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.
883 delete ev->event_pool();
888 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
890 if (Splash::instance()) {
891 Splash::instance()->pop_back_for (win);
896 ARDOUR_UI::configure_timeout ()
898 if (last_configure_time == 0) {
899 /* no configure events yet */
903 /* force a gap of 0.5 seconds since the last configure event
906 if (get_microseconds() - last_configure_time < 500000) {
909 have_configure_timeout = false;
910 save_ardour_state ();
916 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
918 if (have_configure_timeout) {
919 last_configure_time = get_microseconds();
921 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
922 have_configure_timeout = true;
929 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
933 if (node.get_property ("roll", str)){
934 roll_controllable->set_id (str);
936 if (node.get_property ("stop", str)) {
937 stop_controllable->set_id (str);
939 if (node.get_property ("goto-start", str)) {
940 goto_start_controllable->set_id (str);
942 if (node.get_property ("goto-end", str)) {
943 goto_end_controllable->set_id (str);
945 if (node.get_property ("auto-loop", str)) {
946 auto_loop_controllable->set_id (str);
948 if (node.get_property ("play-selection", str)) {
949 play_selection_controllable->set_id (str);
951 if (node.get_property ("rec", str)) {
952 rec_controllable->set_id (str);
954 if (node.get_property ("shuttle", str)) {
955 shuttle_box.controllable()->set_id (str);
960 ARDOUR_UI::get_transport_controllable_state ()
962 XMLNode* node = new XMLNode(X_("TransportControllables"));
964 node->set_property (X_("roll"), roll_controllable->id());
965 node->set_property (X_("stop"), stop_controllable->id());
966 node->set_property (X_("goto-start"), goto_start_controllable->id());
967 node->set_property (X_("goto-end"), goto_end_controllable->id());
968 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
969 node->set_property (X_("play-selection"), play_selection_controllable->id());
970 node->set_property (X_("rec"), rec_controllable->id());
971 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
977 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
980 _session->save_state (snapshot_name);
985 ARDOUR_UI::autosave_session ()
987 if (g_main_depth() > 1) {
988 /* inside a recursive main loop,
989 give up because we may not be able to
995 if (!Config->get_periodic_safety_backups()) {
1000 _session->maybe_write_autosave();
1007 ARDOUR_UI::session_dirty_changed ()
1014 ARDOUR_UI::update_autosave ()
1016 if (_session && _session->dirty()) {
1017 if (_autosave_connection.connected()) {
1018 _autosave_connection.disconnect();
1021 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1022 Config->get_periodic_safety_backup_interval() * 1000);
1025 if (_autosave_connection.connected()) {
1026 _autosave_connection.disconnect();
1032 ARDOUR_UI::check_announcements ()
1035 string _annc_filename;
1038 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1039 #elif defined PLATFORM_WINDOWS
1040 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1042 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1044 _annc_filename.append (VERSIONSTRING);
1046 _announce_string = "";
1048 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1049 FILE* fin = g_fopen (path.c_str(), "rb");
1051 while (!feof (fin)) {
1054 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1057 _announce_string.append (tmp, len);
1062 pingback (VERSIONSTRING, path);
1067 _hide_splash (gpointer arg)
1069 ((ARDOUR_UI*)arg)->hide_splash();
1074 ARDOUR_UI::starting ()
1076 Application* app = Application::instance ();
1077 const char *nsm_url;
1078 bool brand_new_user = ArdourStartup::required ();
1080 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1081 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1083 if (ARDOUR_COMMAND_LINE::check_announcements) {
1084 check_announcements ();
1089 /* we need to create this early because it may need to set the
1090 * audio backend end up.
1094 audio_midi_setup.get (true);
1096 std::cerr << "audio-midi engine setup failed."<< std::endl;
1100 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1101 nsm = new NSM_Client;
1102 if (!nsm->init (nsm_url)) {
1103 /* the ardour executable may have different names:
1105 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1106 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1107 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1109 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1111 const char *process_name = g_getenv ("ARDOUR_SELF");
1112 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1115 // wait for announce reply from nsm server
1116 for ( i = 0; i < 5000; ++i) {
1120 if (nsm->is_active()) {
1125 error << _("NSM server did not announce itself") << endmsg;
1128 // wait for open command from nsm server
1129 for ( i = 0; i < 5000; ++i) {
1131 Glib::usleep (1000);
1132 if (nsm->client_id ()) {
1138 error << _("NSM: no client ID provided") << endmsg;
1142 if (_session && nsm) {
1143 _session->set_nsm_state( nsm->is_active() );
1145 error << _("NSM: no session created") << endmsg;
1149 // nsm requires these actions disabled
1150 vector<string> action_names;
1151 action_names.push_back("SaveAs");
1152 action_names.push_back("Rename");
1153 action_names.push_back("New");
1154 action_names.push_back("Open");
1155 action_names.push_back("Recent");
1156 action_names.push_back("Close");
1158 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1159 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1161 act->set_sensitive (false);
1168 error << _("NSM: initialization failed") << endmsg;
1174 if (brand_new_user) {
1175 _initial_verbose_plugin_scan = true;
1180 _initial_verbose_plugin_scan = false;
1181 switch (s.response ()) {
1182 case Gtk::RESPONSE_OK:
1189 // TODO: maybe IFF brand_new_user
1190 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1191 std::string dspd (Config->get_default_session_parent_dir());
1192 Searchpath ds (ARDOUR::ardour_data_search_path());
1193 ds.add_subdirectory_to_paths ("sessions");
1194 vector<string> demos;
1195 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1197 ARDOUR::RecentSessions rs;
1198 ARDOUR::read_recent_sessions (rs);
1200 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1201 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1202 std::string name = basename_nosuffix (basename_nosuffix (*i));
1203 std::string path = Glib::build_filename (dspd, name);
1204 /* skip if session-dir already exists */
1205 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1208 /* skip sessions that are already in 'recent'.
1209 * eg. a new user changed <session-default-dir> shorly after installation
1211 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1212 if ((*r).first == name) {
1217 PBD::FileArchive ar (*i);
1218 if (0 == ar.inflate (dspd)) {
1219 store_recent_sessions (name, path);
1220 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1226 #ifdef NO_PLUGIN_STATE
1228 ARDOUR::RecentSessions rs;
1229 ARDOUR::read_recent_sessions (rs);
1231 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1233 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1235 /* already used Ardour, have sessions ... warn about plugin state */
1237 ArdourDialog d (_("Free/Demo Version Warning"), true);
1239 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1240 CheckButton c (_("Don't warn me about this again"));
1242 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"),
1243 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1244 _("It will not restore OR save any plugin settings"),
1245 _("If you load an existing session with plugin settings\n"
1246 "they will not be used and will be lost."),
1247 _("To get full access to updates without this limitation\n"
1248 "consider becoming a subscriber for a low cost every month.")));
1249 l.set_justify (JUSTIFY_CENTER);
1251 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1253 d.get_vbox()->pack_start (l, true, true);
1254 d.get_vbox()->pack_start (b, false, false, 12);
1255 d.get_vbox()->pack_start (c, false, false, 12);
1257 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1258 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1262 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1264 if (d.run () != RESPONSE_OK) {
1270 /* go get a session */
1272 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1274 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1275 std::cerr << "Cannot get session parameters."<< std::endl;
1282 WM::Manager::instance().show_visible ();
1284 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1285 * editor window, and we may want stuff to be hidden.
1287 _status_bar_visibility.update ();
1289 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1291 /* all other dialogs are created conditionally */
1297 ARDOUR_UI::check_memory_locking ()
1299 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1300 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1304 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1306 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1308 struct rlimit limits;
1310 long pages, page_size;
1312 size_t pages_len=sizeof(pages);
1313 if ((page_size = getpagesize()) < 0 ||
1314 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1316 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1321 ram = (int64_t) pages * (int64_t) page_size;
1324 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1328 if (limits.rlim_cur != RLIM_INFINITY) {
1330 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1334 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1335 "This might cause %1 to run out of memory before your system "
1336 "runs out of memory. \n\n"
1337 "You can view the memory limit with 'ulimit -l', "
1338 "and it is normally controlled by %2"),
1341 X_("/etc/login.conf")
1343 X_(" /etc/security/limits.conf")
1347 msg.set_default_response (RESPONSE_OK);
1349 VBox* vbox = msg.get_vbox();
1351 CheckButton cb (_("Do not show this window again"));
1352 hbox.pack_start (cb, true, false);
1353 vbox->pack_start (hbox);
1358 pop_back_splash (msg);
1362 if (cb.get_active()) {
1363 XMLNode node (X_("no-memory-warning"));
1364 Config->add_instant_xml (node);
1369 #endif // !__APPLE__
1374 ARDOUR_UI::queue_finish ()
1376 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1380 ARDOUR_UI::idle_finish ()
1383 return false; /* do not call again */
1390 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1392 if (_session->dirty()) {
1393 vector<string> actions;
1394 actions.push_back (_("Don't quit"));
1395 actions.push_back (_("Just quit"));
1396 actions.push_back (_("Save and quit"));
1397 switch (ask_about_saving_session(actions)) {
1402 /* use the default name */
1403 if (save_state_canfail ("")) {
1404 /* failed - don't quit */
1405 MessageDialog msg (_main_window,
1406 string_compose (_("\
1407 %1 was unable to save your session.\n\n\
1408 If you still wish to quit, please use the\n\n\
1409 \"Just quit\" option."), PROGRAM_NAME));
1410 pop_back_splash(msg);
1420 second_connection.disconnect ();
1421 point_one_second_connection.disconnect ();
1422 point_zero_something_second_connection.disconnect();
1423 fps_connection.disconnect();
1426 delete ARDOUR_UI::instance()->video_timeline;
1427 ARDOUR_UI::instance()->video_timeline = NULL;
1428 stop_video_server();
1430 /* Save state before deleting the session, as that causes some
1431 windows to be destroyed before their visible state can be
1434 save_ardour_state ();
1436 if (key_editor.get (false)) {
1437 key_editor->disconnect ();
1440 close_all_dialogs ();
1443 _session->set_clean ();
1444 _session->remove_pending_capture_state ();
1449 halt_connection.disconnect ();
1450 AudioEngine::instance()->stop ();
1451 #ifdef WINDOWS_VST_SUPPORT
1452 fst_stop_threading();
1458 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1460 ArdourDialog window (_("Unsaved Session"));
1461 Gtk::HBox dhbox; // the hbox for the image and text
1462 Gtk::Label prompt_label;
1463 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1467 assert (actions.size() >= 3);
1469 window.add_button (actions[0], RESPONSE_REJECT);
1470 window.add_button (actions[1], RESPONSE_APPLY);
1471 window.add_button (actions[2], RESPONSE_ACCEPT);
1473 window.set_default_response (RESPONSE_ACCEPT);
1475 Gtk::Button noquit_button (msg);
1476 noquit_button.set_name ("EditorGTKButton");
1480 if (_session->snap_name() == _session->name()) {
1481 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?"),
1482 _session->snap_name());
1484 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?"),
1485 _session->snap_name());
1488 prompt_label.set_text (prompt);
1489 prompt_label.set_name (X_("PrompterLabel"));
1490 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1492 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1493 dhbox.set_homogeneous (false);
1494 dhbox.pack_start (*dimage, false, false, 5);
1495 dhbox.pack_start (prompt_label, true, false, 5);
1496 window.get_vbox()->pack_start (dhbox);
1498 window.set_name (_("Prompter"));
1499 window.set_modal (true);
1500 window.set_resizable (false);
1503 prompt_label.show();
1508 ResponseType r = (ResponseType) window.run();
1513 case RESPONSE_ACCEPT: // save and get out of here
1515 case RESPONSE_APPLY: // get out of here
1526 ARDOUR_UI::every_second ()
1529 update_disk_space ();
1530 update_timecode_format ();
1531 update_peak_thread_work ();
1533 if (nsm && nsm->is_active ()) {
1536 if (!_was_dirty && _session->dirty ()) {
1540 else if (_was_dirty && !_session->dirty ()){
1548 ARDOUR_UI::every_point_one_seconds ()
1550 if (editor) editor->build_region_boundary_cache();
1554 ARDOUR_UI::every_point_zero_something_seconds ()
1556 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1558 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1559 float mpeak = editor_meter->update_meters();
1560 if (mpeak > editor_meter_max_peak) {
1561 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1562 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1569 ARDOUR_UI::set_fps_timeout_connection ()
1571 unsigned int interval = 40;
1572 if (!_session) return;
1573 if (_session->timecode_frames_per_second() != 0) {
1574 /* ideally we'll use a select() to sleep and not accumulate
1575 * idle time to provide a regular periodic signal.
1576 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1577 * However, that'll require a dedicated thread and cross-thread
1578 * signals to the GUI Thread..
1580 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1581 * _session->sample_rate() / _session->nominal_sample_rate()
1582 / _session->timecode_frames_per_second()
1584 #ifdef PLATFORM_WINDOWS
1585 // the smallest windows scheduler time-slice is ~15ms.
1586 // periodic GUI timeouts shorter than that will cause
1587 // WaitForSingleObject to spinlock (100% of one CPU Core)
1588 // and gtk never enters idle mode.
1589 // also changing timeBeginPeriod(1) does not affect that in
1590 // any beneficial way, so we just limit the max rate for now.
1591 interval = std::max(30u, interval); // at most ~33Hz.
1593 interval = std::max(8u, interval); // at most 120Hz.
1596 fps_connection.disconnect();
1597 Timers::set_fps_interval (interval);
1601 ARDOUR_UI::update_sample_rate (samplecnt_t)
1605 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1607 if (!AudioEngine::instance()->running()) {
1609 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1613 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1616 /* no sample rate available */
1617 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1620 if (fmod (rate, 1000.0) != 0.0) {
1621 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1622 (float) rate / 1000.0f,
1623 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1625 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1627 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1631 sample_rate_label.set_markup (buf);
1635 ARDOUR_UI::update_format ()
1638 format_label.set_text ("");
1643 s << _("File:") << X_(" <span foreground=\"green\">");
1645 switch (_session->config.get_native_file_header_format ()) {
1680 switch (_session->config.get_native_file_data_format ()) {
1694 format_label.set_markup (s.str ());
1698 ARDOUR_UI::update_cpu_load ()
1700 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1701 double const c = AudioEngine::instance()->get_dsp_load ();
1703 const char* const bg = c > 90 ? " background=\"red\"" : "";
1707 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1709 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1711 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1714 dsp_load_label.set_markup (buf);
1717 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1719 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1721 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1724 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1728 ARDOUR_UI::update_peak_thread_work ()
1731 const int c = SourceFactory::peak_work_queue_length ();
1733 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1734 peak_thread_work_label.set_markup (buf);
1736 peak_thread_work_label.set_markup (X_(""));
1741 ARDOUR_UI::count_recenabled_streams (Route& route)
1743 Track* track = dynamic_cast<Track*>(&route);
1744 if (track && track->rec_enable_control()->get_value()) {
1745 rec_enabled_streams += track->n_inputs().n_total();
1750 ARDOUR_UI::format_disk_space_label (float remain_sec)
1752 if (remain_sec < 0) {
1753 disk_space_label.set_text (_("N/A"));
1754 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1760 int sec = floor (remain_sec);
1761 int hrs = sec / 3600;
1762 int mins = (sec / 60) % 60;
1763 int secs = sec % 60;
1764 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1765 ArdourWidgets::set_tooltip (disk_space_label, buf);
1767 if (remain_sec > 86400) {
1768 disk_space_label.set_text (_("Rec: >24h"));
1770 } else if (remain_sec > 32400 /* 9 hours */) {
1771 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1772 } else if (remain_sec > 5940 /* 99 mins */) {
1773 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1775 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1777 disk_space_label.set_text (buf);
1782 ARDOUR_UI::update_disk_space()
1784 if (_session == 0) {
1785 format_disk_space_label (-1);
1789 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1790 samplecnt_t fr = _session->sample_rate();
1793 /* skip update - no SR available */
1794 format_disk_space_label (-1);
1799 /* Available space is unknown */
1800 format_disk_space_label (-1);
1801 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1802 format_disk_space_label (max_samplecnt);
1804 rec_enabled_streams = 0;
1805 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1807 samplecnt_t samples = opt_samples.get_value_or (0);
1809 if (rec_enabled_streams) {
1810 samples /= rec_enabled_streams;
1813 format_disk_space_label (samples / (float)fr);
1819 ARDOUR_UI::update_timecode_format ()
1825 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1826 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1828 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1829 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1834 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1835 matching ? X_("green") : X_("red"),
1836 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1838 snprintf (buf, sizeof (buf), "TC: n/a");
1841 timecode_format_label.set_markup (buf);
1845 ARDOUR_UI::update_wall_clock ()
1849 static int last_min = -1;
1852 tm_now = localtime (&now);
1853 if (last_min != tm_now->tm_min) {
1855 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1856 wall_clock_label.set_text (buf);
1857 last_min = tm_now->tm_min;
1864 ARDOUR_UI::open_recent_session ()
1866 bool can_return = (_session != 0);
1868 SessionDialog recent_session_dialog;
1872 ResponseType r = (ResponseType) recent_session_dialog.run ();
1875 case RESPONSE_ACCEPT:
1879 recent_session_dialog.hide();
1886 recent_session_dialog.hide();
1890 std::string path = recent_session_dialog.session_folder();
1891 std::string state = recent_session_dialog.session_name (should_be_new);
1893 if (should_be_new == true) {
1897 _session_is_new = false;
1899 if (load_session (path, state) == 0) {
1908 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1910 if (!AudioEngine::instance()->running()) {
1911 MessageDialog msg (parent, string_compose (
1912 _("%1 is not connected to any audio backend.\n"
1913 "You cannot open or close sessions in this condition"),
1915 pop_back_splash (msg);
1923 ARDOUR_UI::open_session ()
1925 if (!check_audioengine (_main_window)) {
1929 /* ardour sessions are folders */
1930 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1931 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1932 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1933 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1936 string session_parent_dir = Glib::path_get_dirname(_session->path());
1937 open_session_selector.set_current_folder(session_parent_dir);
1939 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1942 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1944 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1945 string default_session_folder = Config->get_default_session_parent_dir();
1946 open_session_selector.add_shortcut_folder (default_session_folder);
1948 catch (Glib::Error const& e) {
1949 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1952 FileFilter session_filter;
1953 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1954 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1955 open_session_selector.add_filter (session_filter);
1957 FileFilter archive_filter;
1958 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1959 archive_filter.set_name (_("Session Archives"));
1961 open_session_selector.add_filter (archive_filter);
1963 open_session_selector.set_filter (session_filter);
1965 int response = open_session_selector.run();
1966 open_session_selector.hide ();
1968 if (response == Gtk::RESPONSE_CANCEL) {
1972 string session_path = open_session_selector.get_filename();
1976 if (session_path.length() > 0) {
1977 int rv = ARDOUR::inflate_session (session_path,
1978 Config->get_default_session_parent_dir(), path, name);
1980 _session_is_new = false;
1981 load_session (path, name);
1984 MessageDialog msg (_main_window,
1985 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1988 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1989 _session_is_new = isnew;
1990 load_session (path, name);
1996 ARDOUR_UI::session_add_mixed_track (
1997 const ChanCount& input,
1998 const ChanCount& output,
1999 RouteGroup* route_group,
2001 const string& name_template,
2003 PluginInfoPtr instrument,
2004 Plugin::PresetRecord* pset,
2005 ARDOUR::PresentationInfo::order_t order)
2009 if (Profile->get_mixbus ()) {
2014 list<boost::shared_ptr<MidiTrack> > tracks;
2015 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2017 if (tracks.size() != how_many) {
2018 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2023 display_insufficient_ports_message ();
2029 ARDOUR_UI::session_add_midi_bus (
2030 RouteGroup* route_group,
2032 const string& name_template,
2034 PluginInfoPtr instrument,
2035 Plugin::PresetRecord* pset,
2036 ARDOUR::PresentationInfo::order_t order)
2038 if (_session == 0) {
2039 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2043 if (Profile->get_mixbus ()) {
2049 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2050 if (routes.size() != how_many) {
2051 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2056 display_insufficient_ports_message ();
2062 ARDOUR_UI::session_add_midi_route (
2064 RouteGroup* route_group,
2066 const string& name_template,
2068 PluginInfoPtr instrument,
2069 Plugin::PresetRecord* pset,
2070 ARDOUR::PresentationInfo::order_t order)
2072 ChanCount one_midi_channel;
2073 one_midi_channel.set (DataType::MIDI, 1);
2076 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2078 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2083 ARDOUR_UI::session_add_audio_route (
2085 int32_t input_channels,
2086 int32_t output_channels,
2087 ARDOUR::TrackMode mode,
2088 RouteGroup* route_group,
2090 string const & name_template,
2092 ARDOUR::PresentationInfo::order_t order)
2094 list<boost::shared_ptr<AudioTrack> > tracks;
2101 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2103 if (tracks.size() != how_many) {
2104 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2110 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2112 if (routes.size() != how_many) {
2113 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2120 display_insufficient_ports_message ();
2125 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2126 (*i)->set_strict_io (true);
2128 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2129 (*i)->set_strict_io (true);
2135 ARDOUR_UI::session_add_foldback_bus (uint32_t how_many, string const & name_template)
2142 routes = _session->new_audio_route (2, 2, 0, how_many, name_template, PresentationInfo::FoldbackBus, -1);
2144 if (routes.size() != how_many) {
2145 error << string_compose (P_("could not create %1 new foldback bus", "could not create %1 new foldback busses", how_many), how_many)
2151 display_insufficient_ports_message ();
2155 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2156 (*i)->set_strict_io (true);
2161 ARDOUR_UI::display_insufficient_ports_message ()
2163 MessageDialog msg (_main_window,
2164 string_compose (_("There are insufficient ports available\n\
2165 to create a new track or bus.\n\
2166 You should save %1, exit and\n\
2167 restart with more ports."), PROGRAM_NAME));
2168 pop_back_splash (msg);
2173 ARDOUR_UI::transport_goto_start ()
2176 _session->goto_start();
2178 /* force displayed area in editor to start no matter
2179 what "follow playhead" setting is.
2183 editor->center_screen (_session->current_start_sample ());
2189 ARDOUR_UI::transport_goto_zero ()
2192 _session->request_locate (0);
2194 /* force displayed area in editor to start no matter
2195 what "follow playhead" setting is.
2199 editor->reset_x_origin (0);
2205 ARDOUR_UI::transport_goto_wallclock ()
2207 if (_session && editor) {
2211 samplepos_t samples;
2214 localtime_r (&now, &tmnow);
2216 samplecnt_t sample_rate = _session->sample_rate();
2218 if (sample_rate == 0) {
2219 /* no frame rate available */
2223 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2224 samples += tmnow.tm_min * (60 * sample_rate);
2225 samples += tmnow.tm_sec * sample_rate;
2227 _session->request_locate (samples, _session->transport_rolling ());
2229 /* force displayed area in editor to start no matter
2230 what "follow playhead" setting is.
2234 editor->center_screen (samples);
2240 ARDOUR_UI::transport_goto_end ()
2243 samplepos_t const sample = _session->current_end_sample();
2244 _session->request_locate (sample);
2246 /* force displayed area in editor to start no matter
2247 what "follow playhead" setting is.
2251 editor->center_screen (sample);
2257 ARDOUR_UI::transport_stop ()
2263 if (_session->is_auditioning()) {
2264 _session->cancel_audition ();
2268 _session->request_stop (false, true);
2271 /** Check if any tracks are record enabled. If none are, record enable all of them.
2272 * @return true if track record-enabled status was changed, false otherwise.
2275 ARDOUR_UI::trx_record_enable_all_tracks ()
2281 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2282 bool none_record_enabled = true;
2284 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2285 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2288 if (t->rec_enable_control()->get_value()) {
2289 none_record_enabled = false;
2294 if (none_record_enabled) {
2295 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2298 return none_record_enabled;
2302 ARDOUR_UI::transport_record (bool roll)
2305 switch (_session->record_status()) {
2306 case Session::Disabled:
2307 if (_session->ntracks() == 0) {
2308 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."));
2312 if (Profile->get_trx()) {
2313 roll = trx_record_enable_all_tracks ();
2315 _session->maybe_enable_record ();
2320 case Session::Recording:
2322 _session->request_stop();
2324 _session->disable_record (false, true);
2328 case Session::Enabled:
2329 _session->disable_record (false, true);
2335 ARDOUR_UI::transport_roll ()
2341 if (_session->is_auditioning()) {
2345 if (_session->config.get_external_sync()) {
2346 switch (TransportMasterManager::instance().current()->type()) {
2350 /* transport controlled by the master */
2355 bool rolling = _session->transport_rolling();
2357 if (_session->get_play_loop()) {
2359 /* If loop playback is not a mode, then we should cancel
2360 it when this action is requested. If it is a mode
2361 we just leave it in place.
2364 if (!Config->get_loop_is_mode()) {
2365 /* XXX it is not possible to just leave seamless loop and keep
2366 playing at present (nov 4th 2009)
2368 if (!Config->get_seamless_loop()) {
2369 /* stop loop playback and stop rolling */
2370 _session->request_play_loop (false, true);
2371 } else if (rolling) {
2372 /* stop loop playback but keep rolling */
2373 _session->request_play_loop (false, false);
2377 } else if (_session->get_play_range () ) {
2378 /* stop playing a range if we currently are */
2379 _session->request_play_range (0, true);
2383 _session->request_transport_speed (1.0f);
2388 ARDOUR_UI::get_smart_mode() const
2390 return ( editor->get_smart_mode() );
2395 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2401 if (_session->is_auditioning()) {
2402 _session->cancel_audition ();
2406 if (_session->config.get_external_sync()) {
2407 switch (TransportMasterManager::instance().current()->type()) {
2411 /* transport controlled by the master */
2416 bool rolling = _session->transport_rolling();
2417 bool affect_transport = true;
2419 if (rolling && roll_out_of_bounded_mode) {
2420 /* drop out of loop/range playback but leave transport rolling */
2421 if (_session->get_play_loop()) {
2422 if (_session->actively_recording()) {
2424 /* just stop using the loop, then actually stop
2427 _session->request_play_loop (false, affect_transport);
2430 if (Config->get_seamless_loop()) {
2431 /* the disk buffers contain copies of the loop - we can't
2432 just keep playing, so stop the transport. the user
2433 can restart as they wish.
2435 affect_transport = true;
2437 /* disk buffers are normal, so we can keep playing */
2438 affect_transport = false;
2440 _session->request_play_loop (false, affect_transport);
2442 } else if (_session->get_play_range ()) {
2443 affect_transport = false;
2444 _session->request_play_range (0, true);
2448 if (affect_transport) {
2450 _session->request_stop (with_abort, true);
2452 } else if (!with_abort) { /* with_abort == true means the
2453 * command was intended to stop
2454 * transport, not start.
2457 /* the only external sync condition we can be in here
2458 * would be Engine (JACK) sync, in which case we still
2462 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
2463 _session->request_play_range (&editor->get_selection().time, true);
2464 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2466 _session->request_transport_speed (1.0f);
2472 ARDOUR_UI::toggle_session_auto_loop ()
2478 Location * looploc = _session->locations()->auto_loop_location();
2484 if (_session->get_play_loop()) {
2486 /* looping enabled, our job is to disable it */
2488 _session->request_play_loop (false);
2492 /* looping not enabled, our job is to enable it.
2494 loop-is-NOT-mode: this action always starts the transport rolling.
2495 loop-IS-mode: this action simply sets the loop play mechanism, but
2496 does not start transport.
2498 if (Config->get_loop_is_mode()) {
2499 _session->request_play_loop (true, false);
2501 _session->request_play_loop (true, true);
2505 //show the loop markers
2506 looploc->set_hidden (false, this);
2510 ARDOUR_UI::transport_play_selection ()
2516 editor->play_selection ();
2520 ARDOUR_UI::transport_play_preroll ()
2525 editor->play_with_preroll ();
2529 ARDOUR_UI::transport_rec_preroll ()
2534 editor->rec_with_preroll ();
2538 ARDOUR_UI::transport_rec_count_in ()
2543 editor->rec_with_count_in ();
2547 ARDOUR_UI::transport_rewind (int option)
2549 float current_transport_speed;
2552 current_transport_speed = _session->transport_speed();
2554 if (current_transport_speed >= 0.0f) {
2557 _session->request_transport_speed (-1.0f);
2560 _session->request_transport_speed (-4.0f);
2563 _session->request_transport_speed (-0.5f);
2568 _session->request_transport_speed (current_transport_speed * 1.5f);
2574 ARDOUR_UI::transport_forward (int option)
2580 float current_transport_speed = _session->transport_speed();
2582 if (current_transport_speed <= 0.0f) {
2585 _session->request_transport_speed (1.0f);
2588 _session->request_transport_speed (4.0f);
2591 _session->request_transport_speed (0.5f);
2596 _session->request_transport_speed (current_transport_speed * 1.5f);
2601 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2607 boost::shared_ptr<Route> r;
2609 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2611 boost::shared_ptr<Track> t;
2613 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2614 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2620 ARDOUR_UI::map_transport_state ()
2623 layered_button.set_sensitive (false);
2627 shuttle_box.map_transport_state ();
2629 float sp = _session->transport_speed();
2632 layered_button.set_sensitive (!_session->actively_recording ());
2634 layered_button.set_sensitive (true);
2635 update_disk_space ();
2640 ARDOUR_UI::blink_handler (bool blink_on)
2642 sync_blink (blink_on);
2644 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2647 error_blink (blink_on);
2648 solo_blink (blink_on);
2649 audition_blink (blink_on);
2650 feedback_blink (blink_on);
2654 ARDOUR_UI::update_clocks ()
2656 if (!_session) return;
2658 if (editor && !editor->dragging_playhead()) {
2659 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2664 ARDOUR_UI::start_clocking ()
2666 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2667 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2669 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2674 ARDOUR_UI::stop_clocking ()
2676 clock_signal_connection.disconnect ();
2680 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2684 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2686 label->set_text (buf);
2687 bar->set_fraction (fraction);
2689 /* process events, redraws, etc. */
2691 while (gtk_events_pending()) {
2692 gtk_main_iteration ();
2695 return true; /* continue with save-as */
2699 ARDOUR_UI::save_session_as ()
2705 if (_session->dirty()) {
2706 vector<string> actions;
2707 actions.push_back (_("Abort save-as"));
2708 actions.push_back (_("Don't save now, just save-as"));
2709 actions.push_back (_("Save it first"));
2710 switch (ask_about_saving_session(actions)) {
2715 if (save_state_canfail ("")) {
2716 MessageDialog msg (_main_window,
2717 string_compose (_("\
2718 %1 was unable to save your session.\n\n\
2719 If you still wish to proceed, please use the\n\n\
2720 \"Don't save now\" option."), PROGRAM_NAME));
2721 pop_back_splash(msg);
2727 _session->remove_pending_capture_state ();
2732 if (!save_as_dialog) {
2733 save_as_dialog = new SaveAsDialog;
2736 save_as_dialog->set_name (_session->name());
2738 int response = save_as_dialog->run ();
2740 save_as_dialog->hide ();
2743 case Gtk::RESPONSE_OK:
2752 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2753 sa.new_name = save_as_dialog->new_name ();
2754 sa.switch_to = save_as_dialog->switch_to();
2755 sa.copy_media = save_as_dialog->copy_media();
2756 sa.copy_external = save_as_dialog->copy_external();
2757 sa.include_media = save_as_dialog->include_media ();
2759 /* Only bother with a progress dialog if we're going to copy
2760 media into the save-as target. Without that choice, this
2761 will be very fast because we're only talking about a few kB's to
2762 perhaps a couple of MB's of data.
2765 ArdourDialog progress_dialog (_("Save As"), true);
2768 if (sa.include_media && sa.copy_media) {
2770 Gtk::Label* label = manage (new Gtk::Label());
2771 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2773 progress_dialog.get_vbox()->pack_start (*label);
2774 progress_dialog.get_vbox()->pack_start (*progress_bar);
2776 progress_bar->show ();
2778 /* this signal will be emitted from within this, the calling thread,
2779 * after every file is copied. It provides information on percentage
2780 * complete (in terms of total data to copy), the number of files
2781 * copied so far, and the total number to copy.
2784 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2786 progress_dialog.show_all ();
2787 progress_dialog.present ();
2790 if (_session->save_as (sa)) {
2792 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2796 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2797 * the trick is this: if the new session was copy with media included,
2798 * then Session::save_as() will have already done a neat trick to avoid
2799 * us having to unload and load the new state. But if the media was not
2800 * included, then this is required (it avoids us having to otherwise
2801 * drop all references to media (sources).
2804 if (!sa.include_media && sa.switch_to) {
2805 unload_session (false);
2806 load_session (sa.final_session_folder_name, sa.new_name);
2811 ARDOUR_UI::archive_session ()
2819 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2821 SessionArchiveDialog sad;
2822 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2823 int response = sad.run ();
2825 if (response != Gtk::RESPONSE_OK) {
2830 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2831 MessageDialog msg (_("Session Archiving failed."));
2837 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2841 struct tm local_time;
2844 localtime_r (&n, &local_time);
2845 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2846 if (switch_to_it && _session->dirty ()) {
2847 save_state_canfail ("");
2850 save_state (timebuf, switch_to_it);
2855 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2859 prompter.get_result (snapname);
2861 bool do_save = (snapname.length() != 0);
2864 char illegal = Session::session_name_is_legal(snapname);
2866 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2867 "snapshot names may not contain a '%1' character"), illegal));
2873 vector<std::string> p;
2874 get_state_files_in_directory (_session->session_directory().root_path(), p);
2875 vector<string> n = get_file_names_no_extension (p);
2877 if (find (n.begin(), n.end(), snapname) != n.end()) {
2879 do_save = overwrite_file_dialog (prompter,
2880 _("Confirm Snapshot Overwrite"),
2881 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2885 save_state (snapname, switch_to_it);
2895 /** Ask the user for the name of a new snapshot and then take it.
2899 ARDOUR_UI::snapshot_session (bool switch_to_it)
2901 if (switch_to_it && _session->dirty()) {
2902 vector<string> actions;
2903 actions.push_back (_("Abort saving snapshot"));
2904 actions.push_back (_("Don't save now, just snapshot"));
2905 actions.push_back (_("Save it first"));
2906 switch (ask_about_saving_session(actions)) {
2911 if (save_state_canfail ("")) {
2912 MessageDialog msg (_main_window,
2913 string_compose (_("\
2914 %1 was unable to save your session.\n\n\
2915 If you still wish to proceed, please use the\n\n\
2916 \"Don't save now\" option."), PROGRAM_NAME));
2917 pop_back_splash(msg);
2923 _session->remove_pending_capture_state ();
2928 Prompter prompter (true);
2929 prompter.set_name ("Prompter");
2930 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2932 prompter.set_title (_("Snapshot and switch"));
2933 prompter.set_prompt (_("New session name"));
2935 prompter.set_title (_("Take Snapshot"));
2936 prompter.set_prompt (_("Name of new snapshot"));
2940 prompter.set_initial_text (_session->snap_name());
2942 Glib::DateTime tm (g_date_time_new_now_local ());
2943 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2946 bool finished = false;
2948 switch (prompter.run()) {
2949 case RESPONSE_ACCEPT:
2951 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2962 /** Ask the user for a new session name and then rename the session to it.
2966 ARDOUR_UI::rename_session ()
2972 Prompter prompter (true);
2975 prompter.set_name ("Prompter");
2976 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2977 prompter.set_title (_("Rename Session"));
2978 prompter.set_prompt (_("New session name"));
2981 switch (prompter.run()) {
2982 case RESPONSE_ACCEPT:
2984 prompter.get_result (name);
2986 bool do_rename = (name.length() != 0);
2989 char illegal = Session::session_name_is_legal (name);
2992 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2993 "session names may not contain a '%1' character"), illegal));
2998 switch (_session->rename (name)) {
3000 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3001 msg.set_position (WIN_POS_MOUSE);
3009 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3010 msg.set_position (WIN_POS_MOUSE);
3026 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3028 if (!_session || _session->deletion_in_progress()) {
3032 XMLNode* node = new XMLNode (X_("UI"));
3034 WM::Manager::instance().add_state (*node);
3036 node->add_child_nocopy (gui_object_state->get_state());
3038 _session->add_extra_xml (*node);
3040 if (export_video_dialog) {
3041 _session->add_extra_xml (export_video_dialog->get_state());
3044 save_state_canfail (name, switch_to_it);
3048 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3053 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3058 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3063 ARDOUR_UI::primary_clock_value_changed ()
3066 _session->request_locate (primary_clock->current_time ());
3071 ARDOUR_UI::big_clock_value_changed ()
3074 _session->request_locate (big_clock->current_time ());
3079 ARDOUR_UI::secondary_clock_value_changed ()
3082 _session->request_locate (secondary_clock->current_time ());
3086 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3088 if (response == RESPONSE_ACCEPT) {
3089 const string name = d->get_template_name ();
3090 const string desc = d->get_description ();
3092 int failed = _session->save_template (name, desc);
3094 if (failed == -2) { /* file already exists. */
3095 bool overwrite = overwrite_file_dialog (*d,
3096 _("Confirm Template Overwrite"),
3097 _("A template already exists with that name. Do you want to overwrite it?"));
3100 _session->save_template (name, desc, true);
3112 ARDOUR_UI::save_template ()
3114 if (!check_audioengine (_main_window)) {
3118 const std::string desc = SessionMetadata::Metadata()->description ();
3119 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3120 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3124 void ARDOUR_UI::manage_templates ()
3131 ARDOUR_UI::edit_metadata ()
3133 SessionMetadataEditor dialog;
3134 dialog.set_session (_session);
3135 dialog.grab_focus ();
3140 ARDOUR_UI::import_metadata ()
3142 SessionMetadataImporter dialog;
3143 dialog.set_session (_session);
3148 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3150 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3152 MessageDialog msg (str,
3154 Gtk::MESSAGE_WARNING,
3155 Gtk::BUTTONS_YES_NO,
3159 msg.set_name (X_("OpenExistingDialog"));
3160 msg.set_title (_("Open Existing Session"));
3161 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3162 msg.set_position (Gtk::WIN_POS_CENTER);
3163 pop_back_splash (msg);
3165 switch (msg.run()) {
3174 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3176 BusProfile bus_profile;
3179 bus_profile.master_out_channels = 2;
3181 /* get settings from advanced section of NSD */
3182 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3185 // NULL profile: no master, no monitor
3186 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3194 ARDOUR_UI::load_from_application_api (const std::string& path)
3196 /* OS X El Capitan (and probably later) now somehow passes the command
3197 line arguments to an app via the openFile delegate protocol. Ardour
3198 already does its own command line processing, and having both
3199 pathways active causes crashes. So, if the command line was already
3200 set, do nothing here.
3203 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3207 ARDOUR_COMMAND_LINE::session_name = path;
3209 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3211 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3213 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3214 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3215 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3216 * -> SessionDialog is not displayed
3219 if (_session_dialog) {
3220 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3221 std::string session_path = path;
3222 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3223 session_path = Glib::path_get_dirname (session_path);
3225 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3226 _session_dialog->set_provided_session (session_name, session_path);
3227 _session_dialog->response (RESPONSE_NONE);
3228 _session_dialog->hide();
3233 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3234 /* /path/to/foo => /path/to/foo, foo */
3235 rv = load_session (path, basename_nosuffix (path));
3237 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3238 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3241 // if load_session fails -> pop up SessionDialog.
3243 ARDOUR_COMMAND_LINE::session_name = "";
3245 if (get_session_parameters (true, false)) {
3251 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3253 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3255 string session_name;
3256 string session_path;
3257 string template_name;
3259 bool likely_new = false;
3260 bool cancel_not_quit;
3262 /* deal with any existing DIRTY session now, rather than later. don't
3263 * treat a non-dirty session this way, so that it stays visible
3264 * as we bring up the new session dialog.
3267 if (_session && ARDOUR_UI::instance()->video_timeline) {
3268 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3271 /* if there is already a session, relabel the button
3272 on the SessionDialog so that we don't Quit directly
3274 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3276 if (_session && _session->dirty()) {
3277 if (unload_session (false)) {
3278 /* unload cancelled by user */
3281 ARDOUR_COMMAND_LINE::session_name = "";
3284 if (!load_template.empty()) {
3285 should_be_new = true;
3286 template_name = load_template;
3289 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3290 session_path = ARDOUR_COMMAND_LINE::session_name;
3292 if (!session_path.empty()) {
3293 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3294 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3295 /* session/snapshot file, change path to be dir */
3296 session_path = Glib::path_get_dirname (session_path);
3301 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3303 _session_dialog = &session_dialog;
3306 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3308 /* if they named a specific statefile, use it, otherwise they are
3309 just giving a session folder, and we want to use it as is
3310 to find the session.
3313 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3315 if (suffix != string::npos) {
3316 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3317 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3318 session_name = Glib::path_get_basename (session_name);
3320 session_path = ARDOUR_COMMAND_LINE::session_name;
3321 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3326 session_dialog.clear_given ();
3329 if (should_be_new || session_name.empty()) {
3330 /* need the dialog to get info from user */
3332 cerr << "run dialog\n";
3334 switch (session_dialog.run()) {
3335 case RESPONSE_ACCEPT:
3338 /* this is used for async * app->ShouldLoad(). */
3339 continue; // while loop
3342 if (quit_on_cancel) {
3343 ARDOUR_UI::finish ();
3344 Gtkmm2ext::Application::instance()->cleanup();
3346 pthread_cancel_all ();
3347 return -1; // caller is responsible to call exit()
3353 session_dialog.hide ();
3356 /* if we run the startup dialog again, offer more than just "new session" */
3358 should_be_new = false;
3360 session_name = session_dialog.session_name (likely_new);
3361 session_path = session_dialog.session_folder ();
3368 int rv = ARDOUR::inflate_session (session_name,
3369 Config->get_default_session_parent_dir(), session_path, session_name);
3371 MessageDialog msg (session_dialog,
3372 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3377 session_dialog.set_provided_session (session_name, session_path);
3381 // XXX check archive, inflate
3382 string::size_type suffix = session_name.find (statefile_suffix);
3384 if (suffix != string::npos) {
3385 session_name = session_name.substr (0, suffix);
3388 /* this shouldn't happen, but we catch it just in case it does */
3390 if (session_name.empty()) {
3394 if (session_dialog.use_session_template()) {
3395 template_name = session_dialog.session_template_name();
3396 _session_is_new = true;
3399 if (session_name[0] == G_DIR_SEPARATOR ||
3400 #ifdef PLATFORM_WINDOWS
3401 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3403 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3404 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3409 /* absolute path or cwd-relative path specified for session name: infer session folder
3410 from what was given.
3413 session_path = Glib::path_get_dirname (session_name);
3414 session_name = Glib::path_get_basename (session_name);
3418 session_path = session_dialog.session_folder();
3420 char illegal = Session::session_name_is_legal (session_name);
3423 MessageDialog msg (session_dialog,
3424 string_compose (_("To ensure compatibility with various systems\n"
3425 "session names may not contain a '%1' character"),
3428 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3433 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3436 if (likely_new && !nsm) {
3438 std::string existing = Glib::build_filename (session_path, session_name);
3440 if (!ask_about_loading_existing_session (existing)) {
3441 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3446 _session_is_new = false;
3451 pop_back_splash (session_dialog);
3452 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3454 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3458 char illegal = Session::session_name_is_legal(session_name);
3461 pop_back_splash (session_dialog);
3462 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3463 "session names may not contain a '%1' character"), illegal));
3465 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3469 _session_is_new = true;
3472 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3474 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3475 meta_session_setup (template_name.substr (11));
3477 } else if (likely_new && template_name.empty()) {
3479 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3483 ret = load_session (session_path, session_name, template_name);
3486 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3490 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3491 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3495 /* clear this to avoid endless attempts to load the
3499 ARDOUR_COMMAND_LINE::session_name = "";
3503 _session_dialog = NULL;
3509 ARDOUR_UI::close_session()
3511 if (!check_audioengine (_main_window)) {
3515 if (unload_session (true)) {
3519 ARDOUR_COMMAND_LINE::session_name = "";
3521 if (get_session_parameters (true, false)) {
3526 /** @param snap_name Snapshot name (without .ardour suffix).
3527 * @return -2 if the load failed because we are not connected to the AudioEngine.
3530 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3532 /* load_session calls flush_pending() which allows
3533 * GUI interaction and potentially loading another session
3534 * (that was easy via snapshot sidebar).
3535 * Recursing into load_session() from load_session() and recusive
3536 * event loops causes all kind of crashes.
3538 assert (!session_load_in_progress);
3539 if (session_load_in_progress) {
3542 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3544 Session *new_session;
3549 unload_status = unload_session ();
3551 if (unload_status < 0) {
3553 } else if (unload_status > 0) {
3559 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3562 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3565 /* this one is special */
3567 catch (AudioEngine::PortRegistrationFailure const& err) {
3569 MessageDialog msg (err.what(),
3572 Gtk::BUTTONS_CLOSE);
3574 msg.set_title (_("Port Registration Error"));
3575 msg.set_secondary_text (_("Click the Close button to try again."));
3576 msg.set_position (Gtk::WIN_POS_CENTER);
3577 pop_back_splash (msg);
3580 int response = msg.run ();
3585 case RESPONSE_CANCEL:
3592 catch (SessionException const& e) {
3593 MessageDialog msg (string_compose(
3594 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3595 path, snap_name, e.what()),
3600 msg.set_title (_("Loading Error"));
3601 msg.set_position (Gtk::WIN_POS_CENTER);
3602 pop_back_splash (msg);
3614 MessageDialog msg (string_compose(
3615 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3621 msg.set_title (_("Loading Error"));
3622 msg.set_position (Gtk::WIN_POS_CENTER);
3623 pop_back_splash (msg);
3635 list<string> const u = new_session->unknown_processors ();
3637 MissingPluginDialog d (_session, u);
3642 if (!new_session->writable()) {
3643 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3648 msg.set_title (_("Read-only Session"));
3649 msg.set_position (Gtk::WIN_POS_CENTER);
3650 pop_back_splash (msg);
3657 /* Now the session been created, add the transport controls */
3658 new_session->add_controllable(roll_controllable);
3659 new_session->add_controllable(stop_controllable);
3660 new_session->add_controllable(goto_start_controllable);
3661 new_session->add_controllable(goto_end_controllable);
3662 new_session->add_controllable(auto_loop_controllable);
3663 new_session->add_controllable(play_selection_controllable);
3664 new_session->add_controllable(rec_controllable);
3666 set_session (new_session);
3669 _session->set_clean ();
3672 #ifdef WINDOWS_VST_SUPPORT
3673 fst_stop_threading();
3677 Timers::TimerSuspender t;
3681 #ifdef WINDOWS_VST_SUPPORT
3682 fst_start_threading();
3686 if (!mix_template.empty ()) {
3687 /* if mix_template is given, assume this is a new session */
3688 string metascript = Glib::build_filename (mix_template, "template.lua");
3689 meta_session_setup (metascript);
3694 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3695 * which is queued by set_session().
3696 * If session-loading fails we hide it explicitly.
3697 * This covers both cases in a central place.
3706 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3708 Session *new_session;
3711 x = unload_session ();
3719 _session_is_new = true;
3722 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3725 catch (SessionException const& e) {
3726 cerr << "Here are the errors associated with this failed session:\n";
3728 cerr << "---------\n";
3729 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3730 msg.set_title (_("Loading Error"));
3731 msg.set_position (Gtk::WIN_POS_CENTER);
3732 pop_back_splash (msg);
3737 cerr << "Here are the errors associated with this failed session:\n";
3739 cerr << "---------\n";
3740 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3741 msg.set_title (_("Loading Error"));
3742 msg.set_position (Gtk::WIN_POS_CENTER);
3743 pop_back_splash (msg);
3748 /* Give the new session the default GUI state, if such things exist */
3751 n = Config->instant_xml (X_("Editor"));
3753 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3754 new_session->add_instant_xml (*n, false);
3756 n = Config->instant_xml (X_("Mixer"));
3758 new_session->add_instant_xml (*n, false);
3761 n = Config->instant_xml (X_("Preferences"));
3763 new_session->add_instant_xml (*n, false);
3766 /* Put the playhead at 0 and scroll fully left */
3767 n = new_session->instant_xml (X_("Editor"));
3769 n->set_property (X_("playhead"), X_("0"));
3770 n->set_property (X_("left-frame"), X_("0"));
3773 set_session (new_session);
3775 new_session->save_state(new_session->name());
3781 static void _lua_print (std::string s) {
3783 std::cout << "LuaInstance: " << s << "\n";
3785 PBD::info << "LuaInstance: " << s << endmsg;
3788 std::map<std::string, std::string>
3789 ARDOUR_UI::route_setup_info (const std::string& script_path)
3791 std::map<std::string, std::string> rv;
3793 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3798 lua.Print.connect (&_lua_print);
3801 lua_State* L = lua.getState();
3802 LuaInstance::register_classes (L);
3803 LuaBindings::set_session (L, _session);
3804 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3805 lua_setglobal (L, "Editor");
3807 lua.do_command ("function ardour () end");
3808 lua.do_file (script_path);
3811 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3812 if (!fn.isFunction ()) {
3815 luabridge::LuaRef rs = fn ();
3816 if (!rs.isTable ()) {
3819 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3820 if (!i.key().isString()) {
3823 std::string key = i.key().tostring();
3824 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3825 rv[key] = i.value().tostring();
3828 } catch (luabridge::LuaException const& e) {
3829 cerr << "LuaException:" << e.what () << endl;
3835 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3837 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3840 assert (add_route_dialog);
3843 if ((count = add_route_dialog->count()) <= 0) {
3848 lua.Print.connect (&_lua_print);
3851 lua_State* L = lua.getState();
3852 LuaInstance::register_classes (L);
3853 LuaBindings::set_session (L, _session);
3854 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3855 lua_setglobal (L, "Editor");
3857 lua.do_command ("function ardour () end");
3858 lua.do_file (script_path);
3860 luabridge::LuaRef args (luabridge::newTable (L));
3862 args["name"] = add_route_dialog->name_template ();
3863 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3864 args["group"] = add_route_dialog->route_group ();
3865 args["strict_io"] = add_route_dialog->use_strict_io ();
3866 args["instrument"] = add_route_dialog->requested_instrument ();
3867 args["track_mode"] = add_route_dialog->mode ();
3868 args["channels"] = add_route_dialog->channel_count ();
3869 args["how_many"] = count;
3872 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3873 if (fn.isFunction()) {
3876 } catch (luabridge::LuaException const& e) {
3877 cerr << "LuaException:" << e.what () << endl;
3879 display_insufficient_ports_message ();
3884 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3886 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3891 lua.Print.connect (&_lua_print);
3894 lua_State* L = lua.getState();
3895 LuaInstance::register_classes (L);
3896 LuaBindings::set_session (L, _session);
3897 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3898 lua_setglobal (L, "Editor");
3900 lua.do_command ("function ardour () end");
3901 lua.do_file (script_path);
3904 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3905 if (fn.isFunction()) {
3908 } catch (luabridge::LuaException const& e) {
3909 cerr << "LuaException:" << e.what () << endl;
3911 display_insufficient_ports_message ();
3916 ARDOUR_UI::launch_chat ()
3918 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3920 dialog.set_title (_("About the Chat"));
3921 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."));
3923 switch (dialog.run()) {
3925 open_uri("http://webchat.freenode.net/?channels=ardour");
3933 ARDOUR_UI::launch_manual ()
3935 PBD::open_uri (Config->get_tutorial_manual_url());
3939 ARDOUR_UI::launch_reference ()
3941 PBD::open_uri (Config->get_reference_manual_url());
3945 ARDOUR_UI::launch_tracker ()
3947 PBD::open_uri ("http://tracker.ardour.org");
3951 ARDOUR_UI::launch_subscribe ()
3953 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3957 ARDOUR_UI::launch_cheat_sheet ()
3960 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3962 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3967 ARDOUR_UI::launch_website ()
3969 PBD::open_uri ("http://ardour.org");
3973 ARDOUR_UI::launch_website_dev ()
3975 PBD::open_uri ("http://ardour.org/development.html");
3979 ARDOUR_UI::launch_forums ()
3981 PBD::open_uri ("https://community.ardour.org/forums");
3985 ARDOUR_UI::launch_howto_report ()
3987 PBD::open_uri ("http://ardour.org/reporting_bugs");
3991 ARDOUR_UI::loading_message (const std::string& msg)
3993 if (ARDOUR_COMMAND_LINE::no_splash) {
4001 splash->message (msg);
4005 ARDOUR_UI::show_splash ()
4009 splash = new Splash;
4019 ARDOUR_UI::hide_splash ()
4026 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4030 removed = rep.paths.size();
4033 MessageDialog msgd (_main_window,
4034 _("No files were ready for clean-up"),
4038 msgd.set_title (_("Clean-up"));
4039 msgd.set_secondary_text (_("If this seems surprising, \n\
4040 check for any existing snapshots.\n\
4041 These may still include regions that\n\
4042 require some unused files to continue to exist."));
4048 ArdourDialog results (_("Clean-up"), true, false);
4050 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4051 CleanupResultsModelColumns() {
4055 Gtk::TreeModelColumn<std::string> visible_name;
4056 Gtk::TreeModelColumn<std::string> fullpath;
4060 CleanupResultsModelColumns results_columns;
4061 Glib::RefPtr<Gtk::ListStore> results_model;
4062 Gtk::TreeView results_display;
4064 results_model = ListStore::create (results_columns);
4065 results_display.set_model (results_model);
4066 results_display.append_column (list_title, results_columns.visible_name);
4068 results_display.set_name ("CleanupResultsList");
4069 results_display.set_headers_visible (true);
4070 results_display.set_headers_clickable (false);
4071 results_display.set_reorderable (false);
4073 Gtk::ScrolledWindow list_scroller;
4076 Gtk::HBox dhbox; // the hbox for the image and text
4077 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4078 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4080 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4082 const string dead_directory = _session->session_directory().dead_path();
4085 %1 - number of files removed
4086 %2 - location of "dead"
4087 %3 - size of files affected
4088 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4091 const char* bprefix;
4092 double space_adjusted = 0;
4094 if (rep.space < 1000) {
4096 space_adjusted = rep.space;
4097 } else if (rep.space < 1000000) {
4098 bprefix = _("kilo");
4099 space_adjusted = floorf((float)rep.space / 1000.0);
4100 } else if (rep.space < 1000000 * 1000) {
4101 bprefix = _("mega");
4102 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4104 bprefix = _("giga");
4105 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4109 txt.set_markup (string_compose (P_("\
4110 The following file was deleted from %2,\n\
4111 releasing %3 %4bytes of disk space", "\
4112 The following %1 files were deleted from %2,\n\
4113 releasing %3 %4bytes of disk space", removed),
4114 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4116 txt.set_markup (string_compose (P_("\
4117 The following file was not in use and \n\
4118 has been moved to: %2\n\n\
4119 After a restart of %5\n\n\
4120 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4121 will release an additional %3 %4bytes of disk space.\n", "\
4122 The following %1 files were not in use and \n\
4123 have been moved to: %2\n\n\
4124 After a restart of %5\n\n\
4125 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4126 will release an additional %3 %4bytes of disk space.\n", removed),
4127 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4130 dhbox.pack_start (*dimage, true, false, 5);
4131 dhbox.pack_start (txt, true, false, 5);
4133 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4134 TreeModel::Row row = *(results_model->append());
4135 row[results_columns.visible_name] = *i;
4136 row[results_columns.fullpath] = *i;
4139 list_scroller.add (results_display);
4140 list_scroller.set_size_request (-1, 150);
4141 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4143 dvbox.pack_start (dhbox, true, false, 5);
4144 dvbox.pack_start (list_scroller, true, false, 5);
4145 ddhbox.pack_start (dvbox, true, false, 5);
4147 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4148 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4149 results.set_default_response (RESPONSE_CLOSE);
4150 results.set_position (Gtk::WIN_POS_MOUSE);
4152 results_display.show();
4153 list_scroller.show();
4160 //results.get_vbox()->show();
4161 results.set_resizable (false);
4168 ARDOUR_UI::cleanup ()
4170 if (_session == 0) {
4171 /* shouldn't happen: menu item is insensitive */
4176 MessageDialog checker (_("Are you sure you want to clean-up?"),
4178 Gtk::MESSAGE_QUESTION,
4181 checker.set_title (_("Clean-up"));
4183 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4184 ALL undo/redo information will be lost if you clean-up.\n\
4185 Clean-up will move all unused files to a \"dead\" location."));
4187 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4188 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4189 checker.set_default_response (RESPONSE_CANCEL);
4191 checker.set_name (_("CleanupDialog"));
4192 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4193 checker.set_position (Gtk::WIN_POS_MOUSE);
4195 switch (checker.run()) {
4196 case RESPONSE_ACCEPT:
4203 ARDOUR::CleanupReport rep;
4205 editor->prepare_for_cleanup ();
4207 /* do not allow flush until a session is reloaded */
4208 ActionManager::get_action (X_("Main"), X_("FlushWastebasket"))->set_sensitive (false);
4210 if (_session->cleanup_sources (rep)) {
4211 editor->finish_cleanup ();
4215 editor->finish_cleanup ();
4217 display_cleanup_results (rep, _("Cleaned Files"), false);
4221 ARDOUR_UI::flush_trash ()
4223 if (_session == 0) {
4224 /* shouldn't happen: menu item is insensitive */
4228 ARDOUR::CleanupReport rep;
4230 if (_session->cleanup_trash_sources (rep)) {
4234 display_cleanup_results (rep, _("deleted file"), true);
4238 ARDOUR_UI::cleanup_peakfiles ()
4240 if (_session == 0) {
4241 /* shouldn't happen: menu item is insensitive */
4245 if (! _session->can_cleanup_peakfiles ()) {
4249 // get all region-views in this session
4251 TrackViewList empty;
4253 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4254 std::list<RegionView*> views = rs.by_layer();
4256 // remove displayed audio-region-views waveforms
4257 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4258 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4259 if (!arv) { continue ; }
4260 arv->delete_waves();
4263 // cleanup peak files:
4264 // - stop pending peakfile threads
4265 // - close peakfiles if any
4266 // - remove peak dir in session
4267 // - setup peakfiles (background thread)
4268 _session->cleanup_peakfiles ();
4270 // re-add waves to ARV
4271 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4272 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4273 if (!arv) { continue ; }
4274 arv->create_waves();
4278 PresentationInfo::order_t
4279 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4281 if (editor->get_selection().tracks.empty()) {
4282 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4285 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4288 we want the new routes to have their order keys set starting from
4289 the highest order key in the selection + 1 (if available).
4292 if (place == RouteDialogs::AfterSelection) {
4293 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4295 order_hint = rtav->route()->presentation_info().order();
4298 } else if (place == RouteDialogs::BeforeSelection) {
4299 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4301 order_hint = rtav->route()->presentation_info().order();
4303 } else if (place == RouteDialogs::First) {
4306 /* leave order_hint at max_order */
4313 ARDOUR_UI::start_duplicate_routes ()
4315 if (!duplicate_routes_dialog) {
4316 duplicate_routes_dialog = new DuplicateRouteDialog;
4319 if (duplicate_routes_dialog->restart (_session)) {
4323 duplicate_routes_dialog->present ();
4327 ARDOUR_UI::add_route ()
4329 if (!add_route_dialog.get (false)) {
4330 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4337 if (add_route_dialog->is_visible()) {
4338 /* we're already doing this */
4342 add_route_dialog->set_position (WIN_POS_MOUSE);
4343 add_route_dialog->present();
4347 ARDOUR_UI::add_route_dialog_response (int r)
4350 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4354 if (!AudioEngine::instance()->running ()) {
4356 case AddRouteDialog::Add:
4357 case AddRouteDialog::AddAndClose:
4362 add_route_dialog->ArdourDialog::on_response (r);
4363 ARDOUR_UI_UTILS::engine_is_running ();
4370 case AddRouteDialog::Add:
4371 add_route_dialog->reset_name_edited ();
4373 case AddRouteDialog::AddAndClose:
4374 add_route_dialog->ArdourDialog::on_response (r);
4377 add_route_dialog->ArdourDialog::on_response (r);
4381 std::string template_path = add_route_dialog->get_template_path();
4382 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4383 meta_route_setup (template_path.substr (11));
4387 if ((count = add_route_dialog->count()) <= 0) {
4391 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4392 const string name_template = add_route_dialog->name_template ();
4393 DisplaySuspender ds;
4395 if (!template_path.empty ()) {
4396 if (add_route_dialog->name_template_is_default ()) {
4397 _session->new_route_from_template (count, order, template_path, string ());
4399 _session->new_route_from_template (count, order, template_path, name_template);
4404 ChanCount input_chan= add_route_dialog->channels ();
4405 ChanCount output_chan;
4406 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4407 RouteGroup* route_group = add_route_dialog->route_group ();
4408 AutoConnectOption oac = Config->get_output_auto_connect();
4409 bool strict_io = add_route_dialog->use_strict_io ();
4411 if (oac & AutoConnectMaster) {
4412 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4413 output_chan.set (DataType::MIDI, 0);
4415 output_chan = input_chan;
4418 /* XXX do something with name template */
4420 Session::ProcessorChangeBlocker pcb (_session);
4422 switch (add_route_dialog->type_wanted()) {
4423 case AddRouteDialog::AudioTrack:
4424 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);
4426 case AddRouteDialog::MidiTrack:
4427 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4429 case AddRouteDialog::MixedTrack:
4430 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4432 case AddRouteDialog::AudioBus:
4433 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4435 case AddRouteDialog::MidiBus:
4436 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4438 case AddRouteDialog::VCAMaster:
4439 _session->vca_manager().create_vca (count, name_template);
4441 case AddRouteDialog::FoldbackBus:
4442 session_add_foldback_bus (count, name_template);
4448 ARDOUR_UI::stop_video_server (bool ask_confirm)
4450 if (!video_server_process && ask_confirm) {
4451 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4453 if (video_server_process) {
4455 ArdourDialog confirm (_("Stop Video-Server"), true);
4456 Label m (_("Do you really want to stop the Video Server?"));
4457 confirm.get_vbox()->pack_start (m, true, true);
4458 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4459 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4460 confirm.show_all ();
4461 if (confirm.run() == RESPONSE_CANCEL) {
4465 delete video_server_process;
4466 video_server_process =0;
4471 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4473 ARDOUR_UI::start_video_server( float_window, true);
4477 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4483 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4484 if (video_server_process) {
4485 popup_error(_("The Video Server is already started."));
4487 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4493 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4495 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4497 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4499 video_server_dialog->set_transient_for (*float_window);
4502 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4503 video_server_dialog->hide();
4505 ResponseType r = (ResponseType) video_server_dialog->run ();
4506 video_server_dialog->hide();
4507 if (r != RESPONSE_ACCEPT) { return false; }
4508 if (video_server_dialog->show_again()) {
4509 Config->set_show_video_server_dialog(false);
4513 std::string icsd_exec = video_server_dialog->get_exec_path();
4514 std::string icsd_docroot = video_server_dialog->get_docroot();
4515 #ifndef PLATFORM_WINDOWS
4516 if (icsd_docroot.empty()) {
4517 icsd_docroot = VideoUtils::video_get_docroot (Config);
4522 #ifdef PLATFORM_WINDOWS
4523 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4524 /* OK, allow all drive letters */
4527 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4528 warning << _("Specified docroot is not an existing directory.") << endmsg;
4531 #ifndef PLATFORM_WINDOWS
4532 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4533 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4534 warning << _("Given Video Server is not an executable file.") << endmsg;
4538 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4539 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4540 warning << _("Given Video Server is not an executable file.") << endmsg;
4546 argp=(char**) calloc(9,sizeof(char*));
4547 argp[0] = strdup(icsd_exec.c_str());
4548 argp[1] = strdup("-P");
4549 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4550 argp[3] = strdup("-p");
4551 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4552 argp[5] = strdup("-C");
4553 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4554 argp[7] = strdup(icsd_docroot.c_str());
4556 stop_video_server();
4558 #ifdef PLATFORM_WINDOWS
4559 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4560 /* OK, allow all drive letters */
4563 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4564 Config->set_video_advanced_setup(false);
4566 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4567 Config->set_video_server_url(url_str);
4568 Config->set_video_server_docroot(icsd_docroot);
4569 Config->set_video_advanced_setup(true);
4572 if (video_server_process) {
4573 delete video_server_process;
4576 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4577 if (video_server_process->start()) {
4578 warning << _("Cannot launch the video-server") << endmsg;
4581 int timeout = 120; // 6 sec
4582 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4583 Glib::usleep (50000);
4585 if (--timeout <= 0 || !video_server_process->is_running()) break;
4588 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4590 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4591 delete video_server_process;
4592 video_server_process = 0;
4600 ARDOUR_UI::add_video (Gtk::Window* float_window)
4606 if (!start_video_server(float_window, false)) {
4607 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4612 add_video_dialog->set_transient_for (*float_window);
4615 if (add_video_dialog->is_visible()) {
4616 /* we're already doing this */
4620 ResponseType r = (ResponseType) add_video_dialog->run ();
4621 add_video_dialog->hide();
4622 if (r != RESPONSE_ACCEPT) { return; }
4624 bool local_file, orig_local_file;
4625 std::string path = add_video_dialog->file_name(local_file);
4627 std::string orig_path = path;
4628 orig_local_file = local_file;
4630 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4632 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4633 warning << string_compose(_("could not open %1"), path) << endmsg;
4636 if (!local_file && path.length() == 0) {
4637 warning << _("no video-file selected") << endmsg;
4641 std::string audio_from_video;
4642 bool detect_ltc = false;
4644 switch (add_video_dialog->import_option()) {
4645 case VTL_IMPORT_TRANSCODE:
4647 TranscodeVideoDialog *transcode_video_dialog;
4648 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4649 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4650 transcode_video_dialog->hide();
4651 if (r != RESPONSE_ACCEPT) {
4652 delete transcode_video_dialog;
4656 audio_from_video = transcode_video_dialog->get_audiofile();
4658 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4661 else if (!audio_from_video.empty()) {
4662 editor->embed_audio_from_video(
4664 video_timeline->get_offset(),
4665 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4668 switch (transcode_video_dialog->import_option()) {
4669 case VTL_IMPORT_TRANSCODED:
4670 path = transcode_video_dialog->get_filename();
4673 case VTL_IMPORT_REFERENCE:
4676 delete transcode_video_dialog;
4679 delete transcode_video_dialog;
4683 case VTL_IMPORT_NONE:
4687 /* strip _session->session_directory().video_path() from video file if possible */
4688 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4689 path=path.substr(_session->session_directory().video_path().size());
4690 if (path.at(0) == G_DIR_SEPARATOR) {
4691 path=path.substr(1);
4695 video_timeline->set_update_session_fps(auto_set_session_fps);
4697 if (video_timeline->video_file_info(path, local_file)) {
4698 XMLNode* node = new XMLNode(X_("Videotimeline"));
4699 node->set_property (X_("Filename"), path);
4700 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4701 node->set_property (X_("LocalFile"), local_file);
4702 if (orig_local_file) {
4703 node->set_property (X_("OriginalVideoFile"), orig_path);
4705 node->remove_property (X_("OriginalVideoFile"));
4707 _session->add_extra_xml (*node);
4708 _session->set_dirty ();
4710 if (!audio_from_video.empty() && detect_ltc) {
4711 std::vector<LTCFileReader::LTCMap> ltc_seq;
4714 /* TODO ask user about TV standard (LTC alignment if any) */
4715 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4716 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4718 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4720 /* TODO seek near end of file, and read LTC until end.
4721 * if it fails to find any LTC samples, scan complete file
4723 * calculate drift of LTC compared to video-duration,
4724 * ask user for reference (timecode from start/mid/end)
4727 // LTCFileReader will have written error messages
4730 ::g_unlink(audio_from_video.c_str());
4732 if (ltc_seq.size() == 0) {
4733 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4735 /* the very first TC in the file is somteimes not aligned properly */
4736 int i = ltc_seq.size() -1;
4737 ARDOUR::sampleoffset_t video_start_offset =
4738 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4739 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4740 video_timeline->set_offset(video_start_offset);
4744 _session->maybe_update_session_range(
4745 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4746 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4749 if (add_video_dialog->launch_xjadeo() && local_file) {
4750 editor->set_xjadeo_sensitive(true);
4751 editor->toggle_xjadeo_proc(1);
4753 editor->toggle_xjadeo_proc(0);
4755 editor->toggle_ruler_video(true);
4760 ARDOUR_UI::remove_video ()
4762 video_timeline->close_session();
4763 editor->toggle_ruler_video(false);
4766 video_timeline->set_offset_locked(false);
4767 video_timeline->set_offset(0);
4769 /* delete session state */
4770 XMLNode* node = new XMLNode(X_("Videotimeline"));
4771 _session->add_extra_xml(*node);
4772 node = new XMLNode(X_("Videomonitor"));
4773 _session->add_extra_xml(*node);
4774 node = new XMLNode(X_("Videoexport"));
4775 _session->add_extra_xml(*node);
4776 stop_video_server();
4780 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4782 if (localcacheonly) {
4783 video_timeline->vmon_update();
4785 video_timeline->flush_cache();
4787 editor->queue_visual_videotimeline_update();
4791 ARDOUR_UI::export_video (bool range)
4793 if (ARDOUR::Config->get_show_video_export_info()) {
4794 ExportVideoInfobox infobox (_session);
4795 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4796 if (infobox.show_again()) {
4797 ARDOUR::Config->set_show_video_export_info(false);
4800 case GTK_RESPONSE_YES:
4801 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4807 export_video_dialog->set_session (_session);
4808 export_video_dialog->apply_state(editor->get_selection().time, range);
4809 export_video_dialog->run ();
4810 export_video_dialog->hide ();
4814 ARDOUR_UI::preferences_settings () const
4819 node = _session->instant_xml(X_("Preferences"));
4821 node = Config->instant_xml(X_("Preferences"));
4825 node = new XMLNode (X_("Preferences"));
4832 ARDOUR_UI::mixer_settings () const
4837 node = _session->instant_xml(X_("Mixer"));
4839 node = Config->instant_xml(X_("Mixer"));
4843 node = new XMLNode (X_("Mixer"));
4850 ARDOUR_UI::main_window_settings () const
4855 node = _session->instant_xml(X_("Main"));
4857 node = Config->instant_xml(X_("Main"));
4861 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4862 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4867 node = new XMLNode (X_("Main"));
4874 ARDOUR_UI::editor_settings () const
4879 node = _session->instant_xml(X_("Editor"));
4881 node = Config->instant_xml(X_("Editor"));
4885 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4886 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4891 node = new XMLNode (X_("Editor"));
4898 ARDOUR_UI::keyboard_settings () const
4902 node = Config->extra_xml(X_("Keyboard"));
4905 node = new XMLNode (X_("Keyboard"));
4912 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4915 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4916 _session->locations()->add (location);
4921 ARDOUR_UI::halt_on_xrun_message ()
4923 cerr << "HALT on xrun\n";
4924 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4929 ARDOUR_UI::xrun_handler (samplepos_t where)
4935 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4937 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4938 create_xrun_marker(where);
4941 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4942 halt_on_xrun_message ();
4947 ARDOUR_UI::disk_overrun_handler ()
4949 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4951 if (!have_disk_speed_dialog_displayed) {
4952 have_disk_speed_dialog_displayed = true;
4953 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4954 The disk system on your computer\n\
4955 was not able to keep up with %1.\n\
4957 Specifically, it failed to write data to disk\n\
4958 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4959 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4965 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4966 static MessageDialog *scan_dlg = NULL;
4967 static ProgressBar *scan_pbar = NULL;
4968 static HBox *scan_tbox = NULL;
4969 static Gtk::Button *scan_timeout_button;
4972 ARDOUR_UI::cancel_plugin_scan ()
4974 PluginManager::instance().cancel_plugin_scan();
4978 ARDOUR_UI::cancel_plugin_timeout ()
4980 PluginManager::instance().cancel_plugin_timeout();
4981 scan_timeout_button->set_sensitive (false);
4985 ARDOUR_UI::plugin_scan_timeout (int timeout)
4987 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4991 scan_pbar->set_sensitive (false);
4992 scan_timeout_button->set_sensitive (true);
4993 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4996 scan_pbar->set_sensitive (false);
4997 scan_timeout_button->set_sensitive (false);
5003 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5005 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5009 const bool cancelled = PluginManager::instance().cancelled();
5010 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5011 if (cancelled && scan_dlg->is_mapped()) {
5016 if (cancelled || !can_cancel) {
5021 static Gtk::Button *cancel_button;
5023 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5024 VBox* vbox = scan_dlg->get_vbox();
5025 vbox->set_size_request(400,-1);
5026 scan_dlg->set_title (_("Scanning for plugins"));
5028 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5029 cancel_button->set_name ("EditorGTKButton");
5030 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5031 cancel_button->show();
5033 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5035 scan_tbox = manage( new HBox() );
5037 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5038 scan_timeout_button->set_name ("EditorGTKButton");
5039 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5040 scan_timeout_button->show();
5042 scan_pbar = manage(new ProgressBar());
5043 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5044 scan_pbar->set_text(_("Scan Timeout"));
5047 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5048 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5050 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5053 assert(scan_dlg && scan_tbox && cancel_button);
5055 if (type == X_("closeme")) {
5059 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5062 if (!can_cancel || !cancelled) {
5063 scan_timeout_button->set_sensitive(false);
5065 cancel_button->set_sensitive(can_cancel && !cancelled);
5071 ARDOUR_UI::gui_idle_handler ()
5074 /* due to idle calls, gtk_events_pending() may always return true */
5075 while (gtk_events_pending() && --timeout) {
5076 gtk_main_iteration ();
5081 ARDOUR_UI::disk_underrun_handler ()
5083 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5085 if (!have_disk_speed_dialog_displayed) {
5086 have_disk_speed_dialog_displayed = true;
5087 MessageDialog* msg = new MessageDialog (
5088 _main_window, string_compose (_("The disk system on your computer\n\
5089 was not able to keep up with %1.\n\
5091 Specifically, it failed to read data from disk\n\
5092 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5093 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5099 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5101 have_disk_speed_dialog_displayed = false;
5106 ARDOUR_UI::session_dialog (std::string msg)
5108 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5112 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5119 ARDOUR_UI::pending_state_dialog ()
5121 HBox* hbox = manage (new HBox());
5122 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5123 ArdourDialog dialog (_("Crash Recovery"), true);
5124 Label message (string_compose (_("\
5125 This session appears to have been in the\n\
5126 middle of recording when %1 or\n\
5127 the computer was shutdown.\n\
5129 %1 can recover any captured audio for\n\
5130 you, or it can ignore it. Please decide\n\
5131 what you would like to do.\n"), PROGRAM_NAME));
5132 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5133 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5134 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5135 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5136 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5137 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5138 dialog.set_default_response (RESPONSE_ACCEPT);
5139 dialog.set_position (WIN_POS_CENTER);
5144 switch (dialog.run ()) {
5145 case RESPONSE_ACCEPT:
5153 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5155 HBox* hbox = new HBox();
5156 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5157 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5158 Label message (string_compose (_("\
5159 This session was created with a sample rate of %1 Hz, but\n\
5160 %2 is currently running at %3 Hz. If you load this session,\n\
5161 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5163 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5164 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5165 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5166 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5167 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5168 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5169 dialog.set_default_response (RESPONSE_ACCEPT);
5170 dialog.set_position (WIN_POS_CENTER);
5175 switch (dialog.run()) {
5176 case RESPONSE_ACCEPT:
5186 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5188 MessageDialog msg (string_compose (_("\
5189 This session was created with a sample rate of %1 Hz, but\n\
5190 %2 is currently running at %3 Hz.\n\
5191 Audio will be recorded and played at the wrong sample rate.\n\
5192 Re-Configure the Audio Engine in\n\
5193 Menu > Window > Audio/Midi Setup"),
5194 desired, PROGRAM_NAME, actual),
5196 Gtk::MESSAGE_WARNING);
5201 ARDOUR_UI::use_config ()
5203 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5205 set_transport_controllable_state (*node);
5210 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5212 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5214 primary_clock->set (pos);
5216 case DeltaEditPoint:
5217 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5219 case DeltaOriginMarker:
5221 Location* loc = _session->locations()->clock_origin_location ();
5222 primary_clock->set (pos, false, loc ? loc->start() : 0);
5227 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5229 secondary_clock->set (pos);
5231 case DeltaEditPoint:
5232 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5234 case DeltaOriginMarker:
5236 Location* loc = _session->locations()->clock_origin_location ();
5237 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5242 if (big_clock_window) {
5243 big_clock->set (pos);
5245 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5250 ARDOUR_UI::record_state_changed ()
5252 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5255 /* why bother - the clock isn't visible */
5259 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5261 if (big_clock_window) {
5262 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5263 big_clock->set_active (true);
5265 big_clock->set_active (false);
5272 ARDOUR_UI::first_idle ()
5275 _session->allow_auto_play (true);
5279 editor->first_idle();
5282 /* in 1 second, hide the splash screen
5284 * Consider hiding it *now*. If a user opens opens a dialog
5285 * during that one second while the splash is still visible,
5286 * the dialog will push-back the splash.
5287 * Closing the dialog later will pop it back.
5289 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5291 Keyboard::set_can_save_keybindings (true);
5296 ARDOUR_UI::store_clock_modes ()
5298 XMLNode* node = new XMLNode(X_("ClockModes"));
5300 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5301 XMLNode* child = new XMLNode (X_("Clock"));
5303 child->set_property (X_("name"), (*x)->name());
5304 child->set_property (X_("mode"), (*x)->mode());
5305 child->set_property (X_("on"), (*x)->on());
5307 node->add_child_nocopy (*child);
5310 _session->add_extra_xml (*node);
5311 _session->set_dirty ();
5315 ARDOUR_UI::setup_profile ()
5317 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5318 Profile->set_small_screen ();
5321 if (g_getenv ("TRX")) {
5322 Profile->set_trx ();
5325 if (g_getenv ("MIXBUS")) {
5326 Profile->set_mixbus ();
5331 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5333 MissingFileDialog dialog (s, str, type);
5338 int result = dialog.run ();
5345 return 1; // quit entire session load
5348 result = dialog.get_action ();
5354 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5356 AmbiguousFileDialog dialog (file, hits);
5363 return dialog.get_which ();
5366 /** Allocate our thread-local buffers */
5368 ARDOUR_UI::get_process_buffers ()
5370 _process_thread->get_buffers ();
5373 /** Drop our thread-local buffers */
5375 ARDOUR_UI::drop_process_buffers ()
5377 _process_thread->drop_buffers ();
5381 ARDOUR_UI::feedback_detected ()
5383 _feedback_exists = true;
5387 ARDOUR_UI::successful_graph_sort ()
5389 _feedback_exists = false;
5393 ARDOUR_UI::midi_panic ()
5396 _session->midi_panic();
5401 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5403 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5404 const char* end_big = "</span>";
5405 const char* start_mono = "<tt>";
5406 const char* end_mono = "</tt>";
5408 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5409 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5410 "From now on, use the backup copy with older versions of %3"),
5411 xml_path, backup_path, PROGRAM_NAME,
5413 start_mono, end_mono), true);
5419 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5421 using namespace Menu_Helpers;
5423 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5424 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5425 i->set_active (editor_meter->meter_type () == type);
5429 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5431 using namespace Gtk::Menu_Helpers;
5433 Gtk::Menu* m = shared_popup_menu ();
5434 MenuList& items = m->items ();
5436 RadioMenuItem::Group group;
5438 PBD::Unwinder<bool> uw (_suspend_editor_meter_callbacks, true);
5439 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5440 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5441 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5442 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5443 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5444 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5445 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5446 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5447 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5448 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5449 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5451 m->popup (ev->button, ev->time);
5455 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5457 if (ev->button == 3 && editor_meter) {
5458 popup_editor_meter_menu (ev);
5465 ARDOUR_UI::reset_peak_display ()
5467 if (!_session || !_session->master_out() || !editor_meter) return;
5468 editor_meter->clear_meters();
5469 editor_meter_max_peak = -INFINITY;
5470 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5474 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5476 if (!_session || !_session->master_out()) return;
5477 if (group == _session->master_out()->route_group()) {
5478 reset_peak_display ();
5483 ARDOUR_UI::reset_route_peak_display (Route* route)
5485 if (!_session || !_session->master_out()) return;
5486 if (_session->master_out().get() == route) {
5487 reset_peak_display ();
5492 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5494 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5495 audio_midi_setup->set_position (WIN_POS_CENTER);
5497 if (desired_sample_rate != 0) {
5498 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5499 audio_midi_setup->try_autostart ();
5500 if (ARDOUR::AudioEngine::instance()->running()) {
5507 int response = audio_midi_setup->run();
5509 case Gtk::RESPONSE_DELETE_EVENT:
5510 // after latency callibration engine may run,
5511 // Running() signal was emitted, but dialog will not
5512 // have emitted a response. The user needs to close
5513 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5514 if (!AudioEngine::instance()->running()) {
5519 if (!AudioEngine::instance()->running()) {
5522 audio_midi_setup->hide ();
5530 ARDOUR_UI::transport_numpad_timeout ()
5532 _numpad_locate_happening = false;
5533 if (_numpad_timeout_connection.connected() )
5534 _numpad_timeout_connection.disconnect();
5539 ARDOUR_UI::transport_numpad_decimal ()
5541 _numpad_timeout_connection.disconnect();
5543 if (_numpad_locate_happening) {
5544 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5545 _numpad_locate_happening = false;
5547 _pending_locate_num = 0;
5548 _numpad_locate_happening = true;
5549 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5554 ARDOUR_UI::transport_numpad_event (int num)
5556 if ( _numpad_locate_happening ) {
5557 _pending_locate_num = _pending_locate_num*10 + num;
5560 case 0: toggle_roll(false, false); break;
5561 case 1: transport_rewind(1); break;
5562 case 2: transport_forward(1); break;
5563 case 3: transport_record(true); break;
5564 case 4: toggle_session_auto_loop(); break;
5565 case 5: transport_record(false); toggle_session_auto_loop(); break;
5566 case 6: toggle_punch(); break;
5567 case 7: toggle_click(); break;
5568 case 8: toggle_auto_return(); break;
5569 case 9: toggle_follow_edits(); break;
5575 ARDOUR_UI::set_flat_buttons ()
5577 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5581 ARDOUR_UI::audioengine_became_silent ()
5583 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5585 Gtk::MESSAGE_WARNING,
5589 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5591 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5592 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5593 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5594 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5595 Gtk::HBox pay_button_box;
5596 Gtk::HBox subscribe_button_box;
5598 pay_button_box.pack_start (pay_button, true, false);
5599 subscribe_button_box.pack_start (subscribe_button, true, false);
5601 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 */
5603 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5604 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5606 msg.get_vbox()->pack_start (pay_label);
5607 msg.get_vbox()->pack_start (pay_button_box);
5608 msg.get_vbox()->pack_start (subscribe_label);
5609 msg.get_vbox()->pack_start (subscribe_button_box);
5611 msg.get_vbox()->show_all ();
5613 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5614 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5615 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5620 case Gtk::RESPONSE_YES:
5621 AudioEngine::instance()->reset_silence_countdown ();
5624 case Gtk::RESPONSE_NO:
5626 save_state_canfail ("");
5630 case Gtk::RESPONSE_CANCEL:
5632 /* don't reset, save session and exit */
5638 ARDOUR_UI::hide_application ()
5640 Application::instance ()-> hide ();
5644 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5646 /* icons, titles, WM stuff */
5648 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5650 if (window_icons.empty()) {
5651 Glib::RefPtr<Gdk::Pixbuf> icon;
5652 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5653 window_icons.push_back (icon);
5655 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5656 window_icons.push_back (icon);
5658 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5659 window_icons.push_back (icon);
5661 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5662 window_icons.push_back (icon);
5666 if (!window_icons.empty()) {
5667 window.set_default_icon_list (window_icons);
5670 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5672 if (!name.empty()) {
5676 window.set_title (title.get_string());
5677 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5679 window.set_flags (CAN_FOCUS);
5680 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5682 /* This is a hack to ensure that GTK-accelerators continue to
5683 * work. Once we switch over to entirely native bindings, this will be
5684 * unnecessary and should be removed
5686 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5688 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5689 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5690 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5691 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5695 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5697 Gtkmm2ext::Bindings* bindings = 0;
5698 Gtk::Window* window = 0;
5700 /* until we get ardour bindings working, we are not handling key
5704 if (ev->type != GDK_KEY_PRESS) {
5708 if (event_window == &_main_window) {
5710 window = event_window;
5712 /* find current tab contents */
5714 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5716 /* see if it uses the ardour binding system */
5719 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5722 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5726 window = event_window;
5728 /* see if window uses ardour binding system */
5730 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5733 /* An empty binding set is treated as if it doesn't exist */
5735 if (bindings && bindings->empty()) {
5739 return key_press_focus_accelerator_handler (*window, ev, bindings);
5742 static Gtkmm2ext::Bindings*
5743 get_bindings_from_widget_heirarchy (GtkWidget** w)
5748 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5751 *w = gtk_widget_get_parent (*w);
5754 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5758 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5760 GtkWindow* win = window.gobj();
5761 GtkWidget* focus = gtk_window_get_focus (win);
5762 GtkWidget* binding_widget = focus;
5763 bool special_handling_of_unmodified_accelerators = false;
5764 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5768 /* some widget has keyboard focus */
5770 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5772 /* A particular kind of focusable widget currently has keyboard
5773 * focus. All unmodified key events should go to that widget
5774 * first and not be used as an accelerator by default
5777 special_handling_of_unmodified_accelerators = true;
5781 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5782 if (focus_bindings) {
5783 bindings = focus_bindings;
5784 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5789 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",
5792 Gtkmm2ext::show_gdk_event_state (ev->state),
5793 special_handling_of_unmodified_accelerators,
5794 Keyboard::some_magic_widget_has_focus(),
5796 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5797 ((ev->state & mask) ? "yes" : "no"),
5798 window.get_title()));
5800 /* This exists to allow us to override the way GTK handles
5801 key events. The normal sequence is:
5803 a) event is delivered to a GtkWindow
5804 b) accelerators/mnemonics are activated
5805 c) if (b) didn't handle the event, propagate to
5806 the focus widget and/or focus chain
5808 The problem with this is that if the accelerators include
5809 keys without modifiers, such as the space bar or the
5810 letter "e", then pressing the key while typing into
5811 a text entry widget results in the accelerator being
5812 activated, instead of the desired letter appearing
5815 There is no good way of fixing this, but this
5816 represents a compromise. The idea is that
5817 key events involving modifiers (not Shift)
5818 get routed into the activation pathway first, then
5819 get propagated to the focus widget if necessary.
5821 If the key event doesn't involve modifiers,
5822 we deliver to the focus widget first, thus allowing
5823 it to get "normal text" without interference
5826 Of course, this can also be problematic: if there
5827 is a widget with focus, then it will swallow
5828 all "normal text" accelerators.
5832 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5834 /* no special handling or there are modifiers in effect: accelerate first */
5836 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5837 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5838 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5840 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5841 KeyboardKey k (ev->state, ev->keyval);
5845 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5847 if (bindings->activate (k, Bindings::Press)) {
5848 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5852 if (binding_widget) {
5853 binding_widget = gtk_widget_get_parent (binding_widget);
5854 if (binding_widget) {
5855 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5864 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5866 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5867 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5871 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5873 if (gtk_window_propagate_key_event (win, ev)) {
5874 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5880 /* no modifiers, propagate first */
5882 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5884 if (gtk_window_propagate_key_event (win, ev)) {
5885 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5889 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5890 KeyboardKey k (ev->state, ev->keyval);
5894 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5897 if (bindings->activate (k, Bindings::Press)) {
5898 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5902 if (binding_widget) {
5903 binding_widget = gtk_widget_get_parent (binding_widget);
5904 if (binding_widget) {
5905 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5914 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5916 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5917 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5922 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5927 ARDOUR_UI::cancel_solo ()
5930 _session->cancel_all_solo ();
5935 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5937 /* this resets focus to the first focusable parent of the given widget,
5938 * or, if there is no focusable parent, cancels focus in the toplevel
5939 * window that the given widget is packed into (if there is one).
5946 Gtk::Widget* top = w->get_toplevel();
5948 if (!top || !top->is_toplevel()) {
5952 w = w->get_parent ();
5956 if (w->is_toplevel()) {
5957 /* Setting the focus widget to a Gtk::Window causes all
5958 * subsequent calls to ::has_focus() on the nominal
5959 * focus widget in that window to return
5960 * false. Workaround: never set focus to the toplevel
5966 if (w->get_can_focus ()) {
5967 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5968 win->set_focus (*w);
5971 w = w->get_parent ();
5974 if (top == &_main_window) {
5978 /* no focusable parent found, cancel focus in top level window.
5979 C++ API cannot be used for this. Thanks, references.
5982 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
5987 ARDOUR_UI::monitor_dim_all ()
5989 boost::shared_ptr<Route> mon = _session->monitor_out ();
5993 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5995 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
5996 _monitor->set_dim_all (tact->get_active());
6000 ARDOUR_UI::monitor_cut_all ()
6002 boost::shared_ptr<Route> mon = _session->monitor_out ();
6006 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6008 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
6009 _monitor->set_cut_all (tact->get_active());
6013 ARDOUR_UI::monitor_mono ()
6015 boost::shared_ptr<Route> mon = _session->monitor_out ();
6019 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6021 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
6022 _monitor->set_mono (tact->get_active());
6026 ARDOUR_UI::shared_popup_menu ()
6028 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::shared_popup_menu, ignored);
6030 assert (!_shared_popup_menu || !_shared_popup_menu->is_visible());
6031 delete _shared_popup_menu;
6032 _shared_popup_menu = new Gtk::Menu;
6033 return _shared_popup_menu;