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 , _numpad_locate_happening (false)
303 , _session_is_new (false)
304 , last_key_press_time (0)
308 , rc_option_editor (0)
309 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
310 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
311 , about (X_("about"), _("About"))
312 , location_ui (X_("locations"), S_("Ranges|Locations"))
313 , route_params (X_("inspector"), _("Tracks and Busses"))
314 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
315 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
316 , lua_script_window (X_("script-manager"), _("Script Manager"))
317 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
318 , plugin_dsp_load_window (X_("plugin-dsp-load"), _("Plugin DSP Load"))
319 , transport_masters_window (X_("transport-masters"), _("Transport Masters"))
320 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
321 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
322 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
323 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
324 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
325 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
326 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
327 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
328 , video_server_process (0)
330 , have_configure_timeout (false)
331 , last_configure_time (0)
333 , have_disk_speed_dialog_displayed (false)
334 , _status_bar_visibility (X_("status-bar"))
335 , _feedback_exists (false)
336 , _log_not_acknowledged (LogLevelNone)
337 , duplicate_routes_dialog (0)
338 , editor_visibility_button (S_("Window|Editor"))
339 , mixer_visibility_button (S_("Window|Mixer"))
340 , prefs_visibility_button (S_("Window|Preferences"))
342 Gtkmm2ext::init (localedir);
344 UIConfiguration::instance().post_gui_init ();
346 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
348 /* "touch" the been-here-before path now that config has been migrated */
349 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
351 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
353 /* configuration was modified, exit immediately */
354 _exit (EXIT_SUCCESS);
358 if (string (VERSIONSTRING).find (".pre") != string::npos) {
359 /* check this is not being run from ./ardev etc. */
360 if (!running_from_source_tree ()) {
361 pre_release_dialog ();
365 if (theArdourUI == 0) {
369 /* track main window visibility */
371 main_window_visibility = new VisibilityTracker (_main_window);
373 /* stop libxml from spewing to stdout/stderr */
375 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
376 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
378 /* Set this up early */
380 ActionManager::init ();
382 /* we like keyboards */
384 keyboard = new ArdourKeyboard(*this);
386 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
388 keyboard->set_state (*node, Stateful::loading_state_version);
391 /* actions do not need to be defined when we load keybindings. They
392 * will be lazily discovered. But bindings do need to exist when we
393 * create windows/tabs with their own binding sets.
396 keyboard->setup_keybindings ();
398 if ((global_bindings = Bindings::get_bindings (X_("Global"))) == 0) {
399 error << _("Global keybindings are missing") << endmsg;
404 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
405 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
406 UIConfiguration::instance().map_parameters (pc);
408 transport_ctrl.setup (this);
410 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
411 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
413 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
415 /* handle dialog requests */
417 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
419 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
421 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
423 /* handle Audio/MIDI setup when session requires it */
425 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
427 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
429 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
431 /* handle sr mismatch with a dialog - cross-thread from engine */
432 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
434 /* handle requests to quit (coming from JACK session) */
436 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
438 /* tell the user about feedback */
440 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
441 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
443 /* handle requests to deal with missing files */
445 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
447 /* and ambiguous files */
449 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
451 /* also plugin scan messages */
452 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
453 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
455 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
457 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
460 /* lets get this party started */
462 setup_gtk_ardour_enums ();
465 SessionEvent::create_per_thread_pool ("GUI", 4096);
467 UIConfiguration::instance().reset_dpi ();
469 TimeAxisViewItem::set_constant_heights ();
471 /* The following must happen after ARDOUR::init() so that Config is set up */
473 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
476 key_editor.set_state (*ui_xml, 0);
477 session_option_editor.set_state (*ui_xml, 0);
478 speaker_config_window.set_state (*ui_xml, 0);
479 about.set_state (*ui_xml, 0);
480 add_route_dialog.set_state (*ui_xml, 0);
481 add_video_dialog.set_state (*ui_xml, 0);
482 route_params.set_state (*ui_xml, 0);
483 bundle_manager.set_state (*ui_xml, 0);
484 location_ui.set_state (*ui_xml, 0);
485 big_clock_window.set_state (*ui_xml, 0);
486 big_transport_window.set_state (*ui_xml, 0);
487 audio_port_matrix.set_state (*ui_xml, 0);
488 midi_port_matrix.set_state (*ui_xml, 0);
489 export_video_dialog.set_state (*ui_xml, 0);
490 lua_script_window.set_state (*ui_xml, 0);
491 idleometer.set_state (*ui_xml, 0);
492 plugin_dsp_load_window.set_state (*ui_xml, 0);
493 transport_masters_window.set_state (*ui_xml, 0);
496 /* Separate windows */
498 WM::Manager::instance().register_window (&key_editor);
499 WM::Manager::instance().register_window (&session_option_editor);
500 WM::Manager::instance().register_window (&speaker_config_window);
501 WM::Manager::instance().register_window (&about);
502 WM::Manager::instance().register_window (&add_route_dialog);
503 WM::Manager::instance().register_window (&add_video_dialog);
504 WM::Manager::instance().register_window (&route_params);
505 WM::Manager::instance().register_window (&audio_midi_setup);
506 WM::Manager::instance().register_window (&export_video_dialog);
507 WM::Manager::instance().register_window (&lua_script_window);
508 WM::Manager::instance().register_window (&bundle_manager);
509 WM::Manager::instance().register_window (&location_ui);
510 WM::Manager::instance().register_window (&big_clock_window);
511 WM::Manager::instance().register_window (&big_transport_window);
512 WM::Manager::instance().register_window (&audio_port_matrix);
513 WM::Manager::instance().register_window (&midi_port_matrix);
514 WM::Manager::instance().register_window (&idleometer);
515 WM::Manager::instance().register_window (&plugin_dsp_load_window);
516 WM::Manager::instance().register_window (&transport_masters_window);
518 /* do not retain position for add route dialog */
519 add_route_dialog.set_state_mask (WindowProxy::Size);
521 /* Trigger setting up the color scheme and loading the GTK RC file */
523 UIConfiguration::instance().load_rc_file (false);
525 _process_thread = new ProcessThread ();
526 _process_thread->init ();
528 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
534 ARDOUR_UI::pre_release_dialog ()
536 ArdourDialog d (_("Pre-Release Warning"), true, false);
537 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
539 Label* label = manage (new Label);
540 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
541 There are still several issues and bugs to be worked on,\n\
542 as well as general workflow improvements, before this can be considered\n\
543 release software. So, a few guidelines:\n\
545 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
546 though it may be so, depending on your workflow.\n\
547 2) Please wait for a helpful writeup of new features.\n\
548 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
549 4) <b>Please do NOT file bugs for this alpha-development versions at this point in time</b>.\n\
550 There is no bug triaging before the initial development concludes and\n\
551 reporting issue for incomplete, ongoing work-in-progress is mostly useless.\n\
552 5) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
553 can get there directly from within the program via the Help->Chat menu option.\n\
554 6) Please <b>DO</b> submit patches for issues after discussing them on IRC.\n\
556 Full information on all the above can be found on the support page at\n\
558 http://ardour.org/support\n\
559 "), PROGRAM_NAME, VERSIONSTRING));
561 d.get_vbox()->set_border_width (12);
562 d.get_vbox()->pack_start (*label, false, false, 12);
563 d.get_vbox()->show_all ();
568 GlobalPortMatrixWindow*
569 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
574 return new GlobalPortMatrixWindow (_session, type);
578 ARDOUR_UI::attach_to_engine ()
580 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this, _1), gui_context());
581 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
585 ARDOUR_UI::engine_stopped ()
587 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
588 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
589 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
590 update_sample_rate (0);
595 ARDOUR_UI::engine_running (uint32_t cnt)
602 _session->reset_xrun_count ();
604 update_disk_space ();
606 update_sample_rate (AudioEngine::instance()->sample_rate());
607 update_timecode_format ();
608 update_peak_thread_work ();
609 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
610 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
614 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
616 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
617 /* we can't rely on the original string continuing to exist when we are called
618 again in the GUI thread, so make a copy and note that we need to
621 char *copy = strdup (reason);
622 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
626 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
627 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
629 update_sample_rate (0);
633 /* if the reason is a non-empty string, it means that the backend was shutdown
634 rather than just Ardour.
637 if (strlen (reason)) {
638 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
640 msgstr = string_compose (_("\
641 The audio backend has either been shutdown or it\n\
642 disconnected %1 because %1\n\
643 was not fast enough. Try to restart\n\
644 the audio backend and save the session."), PROGRAM_NAME);
647 MessageDialog msg (_main_window, msgstr);
648 pop_back_splash (msg);
652 free (const_cast<char*> (reason));
657 ARDOUR_UI::post_engine ()
659 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
661 #ifdef AUDIOUNIT_SUPPORT
663 if (AUPluginInfo::au_get_crashlog(au_msg)) {
664 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
665 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
666 info << au_msg << endmsg;
670 /* connect to important signals */
672 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
673 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
674 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
675 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
676 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
678 if (setup_windows ()) {
679 throw failed_constructor ();
682 transport_ctrl.map_actions ();
684 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
685 XMLNode* n = Config->extra_xml (X_("UI"));
687 _status_bar_visibility.set_state (*n);
690 check_memory_locking();
692 /* this is the first point at which all the possible actions are
693 * available, because some of the available actions are dependent on
694 * aspects of the engine/backend.
697 if (ARDOUR_COMMAND_LINE::show_key_actions) {
699 Bindings::save_all_bindings_as_html (sstr);
701 if (sstr.str().empty()) {
708 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
710 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
716 #ifdef PLATFORM_WINDOWS
722 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
723 #ifndef PLATFORM_WINDOWS
726 g_unlink (file_name);
728 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
734 #ifndef PLATFORM_WINDOWS
738 PBD::open_uri (string_compose ("file:///%1", file_name));
740 halt_connection.disconnect ();
741 AudioEngine::instance()->stop ();
746 if (ARDOUR_COMMAND_LINE::show_actions) {
749 vector<string> paths;
750 vector<string> labels;
751 vector<string> tooltips;
753 vector<Glib::RefPtr<Gtk::Action> > actions;
754 string ver_in = revision;
755 string ver = ver_in.substr(0, ver_in.find("-"));
758 output << "\n<h2>Menu actions</h2>" << endl;
759 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
760 output << " surfaces or scripts.\n</p>\n" << endl;
761 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
762 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
763 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
764 output << "<table class=\"dl\">\n <thead>" << endl;
765 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
766 output << " </thead>\n <tbody>" << endl;
768 ActionManager::get_all_actions (paths, labels, tooltips, keys, actions);
770 vector<string>::iterator p;
771 vector<string>::iterator l;
773 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
774 output << " <tr><th><kbd class=\"osc\">" << *p << "</kbd></th><td>" << *l << "</td></tr>" << endl;
776 output << " </tbody>\n </table>" << endl;
778 // output this mess to a browser for easiest X-platform use
779 // it is not pretty HTML, but it works and it's main purpose
780 // is to create raw html to fit in Ardour's manual with no editing
785 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
787 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
793 #ifdef PLATFORM_WINDOWS
799 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
800 #ifndef PLATFORM_WINDOWS
803 g_unlink (file_name);
805 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
811 #ifndef PLATFORM_WINDOWS
815 PBD::open_uri (string_compose ("file:///%1", file_name));
817 halt_connection.disconnect ();
818 AudioEngine::instance()->stop ();
822 /* this being a GUI and all, we want peakfiles */
824 AudioFileSource::set_build_peakfiles (true);
825 AudioFileSource::set_build_missing_peakfiles (true);
827 /* set default clock modes */
829 primary_clock->set_mode (AudioClock::Timecode);
830 secondary_clock->set_mode (AudioClock::BBT);
832 /* start the time-of-day-clock */
835 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
836 update_wall_clock ();
837 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
842 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
843 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
844 Config->map_parameters (pc);
846 UIConfiguration::instance().map_parameters (pc);
850 ARDOUR_UI::~ARDOUR_UI ()
852 UIConfiguration::instance().save_state();
856 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
857 // don't bother at 'real' exit. the OS cleans up for us.
858 delete big_clock; big_clock = 0;
859 delete primary_clock; primary_clock = 0;
860 delete secondary_clock; secondary_clock = 0;
861 delete _process_thread; _process_thread = 0;
862 delete time_info_box; time_info_box = 0;
863 delete meterbridge; meterbridge = 0;
864 delete luawindow; luawindow = 0;
865 delete editor; editor = 0;
866 delete mixer; mixer = 0;
867 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
869 delete gui_object_state; gui_object_state = 0;
870 delete _shared_popup_menu ; _shared_popup_menu = 0;
871 delete main_window_visibility;
872 FastMeter::flush_pattern_cache ();
873 ArdourFader::flush_pattern_cache ();
877 /* Small trick to flush main-thread event pool.
878 * Other thread-pools are destroyed at pthread_exit(),
879 * but tmain thread termination is too late to trigger Pool::~Pool()
881 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.
882 delete ev->event_pool();
887 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
889 if (Splash::instance()) {
890 Splash::instance()->pop_back_for (win);
895 ARDOUR_UI::configure_timeout ()
897 if (last_configure_time == 0) {
898 /* no configure events yet */
902 /* force a gap of 0.5 seconds since the last configure event
905 if (get_microseconds() - last_configure_time < 500000) {
908 have_configure_timeout = false;
909 save_ardour_state ();
915 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
917 if (have_configure_timeout) {
918 last_configure_time = get_microseconds();
920 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
921 have_configure_timeout = true;
928 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
932 if (node.get_property ("roll", str)){
933 roll_controllable->set_id (str);
935 if (node.get_property ("stop", str)) {
936 stop_controllable->set_id (str);
938 if (node.get_property ("goto-start", str)) {
939 goto_start_controllable->set_id (str);
941 if (node.get_property ("goto-end", str)) {
942 goto_end_controllable->set_id (str);
944 if (node.get_property ("auto-loop", str)) {
945 auto_loop_controllable->set_id (str);
947 if (node.get_property ("play-selection", str)) {
948 play_selection_controllable->set_id (str);
950 if (node.get_property ("rec", str)) {
951 rec_controllable->set_id (str);
953 if (node.get_property ("shuttle", str)) {
954 shuttle_box.controllable()->set_id (str);
959 ARDOUR_UI::get_transport_controllable_state ()
961 XMLNode* node = new XMLNode(X_("TransportControllables"));
963 node->set_property (X_("roll"), roll_controllable->id());
964 node->set_property (X_("stop"), stop_controllable->id());
965 node->set_property (X_("goto-start"), goto_start_controllable->id());
966 node->set_property (X_("goto-end"), goto_end_controllable->id());
967 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
968 node->set_property (X_("play-selection"), play_selection_controllable->id());
969 node->set_property (X_("rec"), rec_controllable->id());
970 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
976 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
979 _session->save_state (snapshot_name);
984 ARDOUR_UI::autosave_session ()
986 if (g_main_depth() > 1) {
987 /* inside a recursive main loop,
988 give up because we may not be able to
994 if (!Config->get_periodic_safety_backups()) {
999 _session->maybe_write_autosave();
1006 ARDOUR_UI::session_dirty_changed ()
1013 ARDOUR_UI::update_autosave ()
1015 if (_session && _session->dirty()) {
1016 if (_autosave_connection.connected()) {
1017 _autosave_connection.disconnect();
1020 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1021 Config->get_periodic_safety_backup_interval() * 1000);
1024 if (_autosave_connection.connected()) {
1025 _autosave_connection.disconnect();
1031 ARDOUR_UI::check_announcements ()
1034 string _annc_filename;
1037 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1038 #elif defined PLATFORM_WINDOWS
1039 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1041 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1043 _annc_filename.append (VERSIONSTRING);
1045 _announce_string = "";
1047 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1048 FILE* fin = g_fopen (path.c_str(), "rb");
1050 while (!feof (fin)) {
1053 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1056 _announce_string.append (tmp, len);
1061 pingback (VERSIONSTRING, path);
1066 _hide_splash (gpointer arg)
1068 ((ARDOUR_UI*)arg)->hide_splash();
1073 ARDOUR_UI::starting ()
1075 Application* app = Application::instance ();
1076 const char *nsm_url;
1077 bool brand_new_user = ArdourStartup::required ();
1079 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1080 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1082 if (ARDOUR_COMMAND_LINE::check_announcements) {
1083 check_announcements ();
1088 /* we need to create this early because it may need to set the
1089 * audio backend end up.
1093 audio_midi_setup.get (true);
1095 std::cerr << "audio-midi engine setup failed."<< std::endl;
1099 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1100 nsm = new NSM_Client;
1101 if (!nsm->init (nsm_url)) {
1102 /* the ardour executable may have different names:
1104 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1105 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1106 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1108 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1110 const char *process_name = g_getenv ("ARDOUR_SELF");
1111 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1114 // wait for announce reply from nsm server
1115 for ( i = 0; i < 5000; ++i) {
1119 if (nsm->is_active()) {
1124 error << _("NSM server did not announce itself") << endmsg;
1127 // wait for open command from nsm server
1128 for ( i = 0; i < 5000; ++i) {
1130 Glib::usleep (1000);
1131 if (nsm->client_id ()) {
1137 error << _("NSM: no client ID provided") << endmsg;
1141 if (_session && nsm) {
1142 _session->set_nsm_state( nsm->is_active() );
1144 error << _("NSM: no session created") << endmsg;
1148 // nsm requires these actions disabled
1149 vector<string> action_names;
1150 action_names.push_back("SaveAs");
1151 action_names.push_back("Rename");
1152 action_names.push_back("New");
1153 action_names.push_back("Open");
1154 action_names.push_back("Recent");
1155 action_names.push_back("Close");
1157 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1158 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1160 act->set_sensitive (false);
1167 error << _("NSM: initialization failed") << endmsg;
1173 if (brand_new_user) {
1174 _initial_verbose_plugin_scan = true;
1179 _initial_verbose_plugin_scan = false;
1180 switch (s.response ()) {
1181 case Gtk::RESPONSE_OK:
1188 // TODO: maybe IFF brand_new_user
1189 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1190 std::string dspd (Config->get_default_session_parent_dir());
1191 Searchpath ds (ARDOUR::ardour_data_search_path());
1192 ds.add_subdirectory_to_paths ("sessions");
1193 vector<string> demos;
1194 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1196 ARDOUR::RecentSessions rs;
1197 ARDOUR::read_recent_sessions (rs);
1199 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1200 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1201 std::string name = basename_nosuffix (basename_nosuffix (*i));
1202 std::string path = Glib::build_filename (dspd, name);
1203 /* skip if session-dir already exists */
1204 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1207 /* skip sessions that are already in 'recent'.
1208 * eg. a new user changed <session-default-dir> shorly after installation
1210 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1211 if ((*r).first == name) {
1216 PBD::FileArchive ar (*i);
1217 if (0 == ar.inflate (dspd)) {
1218 store_recent_sessions (name, path);
1219 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1225 #ifdef NO_PLUGIN_STATE
1227 ARDOUR::RecentSessions rs;
1228 ARDOUR::read_recent_sessions (rs);
1230 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1232 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1234 /* already used Ardour, have sessions ... warn about plugin state */
1236 ArdourDialog d (_("Free/Demo Version Warning"), true);
1238 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1239 CheckButton c (_("Don't warn me about this again"));
1241 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"),
1242 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1243 _("It will not restore OR save any plugin settings"),
1244 _("If you load an existing session with plugin settings\n"
1245 "they will not be used and will be lost."),
1246 _("To get full access to updates without this limitation\n"
1247 "consider becoming a subscriber for a low cost every month.")));
1248 l.set_justify (JUSTIFY_CENTER);
1250 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1252 d.get_vbox()->pack_start (l, true, true);
1253 d.get_vbox()->pack_start (b, false, false, 12);
1254 d.get_vbox()->pack_start (c, false, false, 12);
1256 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1257 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1261 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1263 if (d.run () != RESPONSE_OK) {
1264 _exit (EXIT_SUCCESS);
1269 /* go get a session */
1271 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1273 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1274 std::cerr << "Cannot get session parameters."<< std::endl;
1281 WM::Manager::instance().show_visible ();
1283 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1284 * editor window, and we may want stuff to be hidden.
1286 _status_bar_visibility.update ();
1288 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1290 /* all other dialogs are created conditionally */
1296 ARDOUR_UI::check_memory_locking ()
1298 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1299 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1303 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1305 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1307 struct rlimit limits;
1309 long pages, page_size;
1311 size_t pages_len=sizeof(pages);
1312 if ((page_size = getpagesize()) < 0 ||
1313 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1315 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1320 ram = (int64_t) pages * (int64_t) page_size;
1323 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1327 if (limits.rlim_cur != RLIM_INFINITY) {
1329 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1333 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1334 "This might cause %1 to run out of memory before your system "
1335 "runs out of memory. \n\n"
1336 "You can view the memory limit with 'ulimit -l', "
1337 "and it is normally controlled by %2"),
1340 X_("/etc/login.conf")
1342 X_(" /etc/security/limits.conf")
1346 msg.set_default_response (RESPONSE_OK);
1348 VBox* vbox = msg.get_vbox();
1350 CheckButton cb (_("Do not show this window again"));
1351 hbox.pack_start (cb, true, false);
1352 vbox->pack_start (hbox);
1357 pop_back_splash (msg);
1361 if (cb.get_active()) {
1362 XMLNode node (X_("no-memory-warning"));
1363 Config->add_instant_xml (node);
1368 #endif // !__APPLE__
1373 ARDOUR_UI::queue_finish ()
1375 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1379 ARDOUR_UI::idle_finish ()
1382 return false; /* do not call again */
1389 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1391 if (_session->dirty()) {
1392 vector<string> actions;
1393 actions.push_back (_("Don't quit"));
1394 actions.push_back (_("Just quit"));
1395 actions.push_back (_("Save and quit"));
1396 switch (ask_about_saving_session(actions)) {
1401 /* use the default name */
1402 if (save_state_canfail ("")) {
1403 /* failed - don't quit */
1404 MessageDialog msg (_main_window,
1405 string_compose (_("\
1406 %1 was unable to save your session.\n\n\
1407 If you still wish to quit, please use the\n\n\
1408 \"Just quit\" option."), PROGRAM_NAME));
1409 pop_back_splash(msg);
1419 second_connection.disconnect ();
1420 point_one_second_connection.disconnect ();
1421 point_zero_something_second_connection.disconnect();
1422 fps_connection.disconnect();
1425 delete ARDOUR_UI::instance()->video_timeline;
1426 ARDOUR_UI::instance()->video_timeline = NULL;
1427 stop_video_server();
1429 /* Save state before deleting the session, as that causes some
1430 windows to be destroyed before their visible state can be
1433 save_ardour_state ();
1435 if (key_editor.get (false)) {
1436 key_editor->disconnect ();
1439 close_all_dialogs ();
1442 _session->set_clean ();
1443 _session->remove_pending_capture_state ();
1448 halt_connection.disconnect ();
1449 AudioEngine::instance()->stop ();
1450 #ifdef WINDOWS_VST_SUPPORT
1451 fst_stop_threading();
1457 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1459 ArdourDialog window (_("Unsaved Session"));
1460 Gtk::HBox dhbox; // the hbox for the image and text
1461 Gtk::Label prompt_label;
1462 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1466 assert (actions.size() >= 3);
1468 window.add_button (actions[0], RESPONSE_REJECT);
1469 window.add_button (actions[1], RESPONSE_APPLY);
1470 window.add_button (actions[2], RESPONSE_ACCEPT);
1472 window.set_default_response (RESPONSE_ACCEPT);
1474 Gtk::Button noquit_button (msg);
1475 noquit_button.set_name ("EditorGTKButton");
1479 if (_session->snap_name() == _session->name()) {
1480 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?"),
1481 _session->snap_name());
1483 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?"),
1484 _session->snap_name());
1487 prompt_label.set_text (prompt);
1488 prompt_label.set_name (X_("PrompterLabel"));
1489 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1491 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1492 dhbox.set_homogeneous (false);
1493 dhbox.pack_start (*dimage, false, false, 5);
1494 dhbox.pack_start (prompt_label, true, false, 5);
1495 window.get_vbox()->pack_start (dhbox);
1497 window.set_name (_("Prompter"));
1498 window.set_modal (true);
1499 window.set_resizable (false);
1502 prompt_label.show();
1507 ResponseType r = (ResponseType) window.run();
1512 case RESPONSE_ACCEPT: // save and get out of here
1514 case RESPONSE_APPLY: // get out of here
1525 ARDOUR_UI::every_second ()
1528 update_disk_space ();
1529 update_timecode_format ();
1530 update_peak_thread_work ();
1532 if (nsm && nsm->is_active ()) {
1535 if (!_was_dirty && _session->dirty ()) {
1539 else if (_was_dirty && !_session->dirty ()){
1547 ARDOUR_UI::every_point_one_seconds ()
1549 if (editor) editor->build_region_boundary_cache();
1553 ARDOUR_UI::every_point_zero_something_seconds ()
1555 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1557 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1558 float mpeak = editor_meter->update_meters();
1559 if (mpeak > editor_meter_max_peak) {
1560 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1561 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1568 ARDOUR_UI::set_fps_timeout_connection ()
1570 unsigned int interval = 40;
1571 if (!_session) return;
1572 if (_session->timecode_frames_per_second() != 0) {
1573 /* ideally we'll use a select() to sleep and not accumulate
1574 * idle time to provide a regular periodic signal.
1575 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1576 * However, that'll require a dedicated thread and cross-thread
1577 * signals to the GUI Thread..
1579 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1580 * _session->sample_rate() / _session->nominal_sample_rate()
1581 / _session->timecode_frames_per_second()
1583 #ifdef PLATFORM_WINDOWS
1584 // the smallest windows scheduler time-slice is ~15ms.
1585 // periodic GUI timeouts shorter than that will cause
1586 // WaitForSingleObject to spinlock (100% of one CPU Core)
1587 // and gtk never enters idle mode.
1588 // also changing timeBeginPeriod(1) does not affect that in
1589 // any beneficial way, so we just limit the max rate for now.
1590 interval = std::max(30u, interval); // at most ~33Hz.
1592 interval = std::max(8u, interval); // at most 120Hz.
1595 fps_connection.disconnect();
1596 Timers::set_fps_interval (interval);
1600 ARDOUR_UI::update_sample_rate (samplecnt_t)
1604 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1606 if (!AudioEngine::instance()->running()) {
1608 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1612 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1615 /* no sample rate available */
1616 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1619 if (fmod (rate, 1000.0) != 0.0) {
1620 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1621 (float) rate / 1000.0f,
1622 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1624 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1626 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1630 sample_rate_label.set_markup (buf);
1634 ARDOUR_UI::update_format ()
1637 format_label.set_text ("");
1642 s << _("File:") << X_(" <span foreground=\"green\">");
1644 switch (_session->config.get_native_file_header_format ()) {
1679 switch (_session->config.get_native_file_data_format ()) {
1693 format_label.set_markup (s.str ());
1697 ARDOUR_UI::update_cpu_load ()
1699 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1700 double const c = AudioEngine::instance()->get_dsp_load ();
1702 const char* const bg = c > 90 ? " background=\"red\"" : "";
1706 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1708 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1710 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1713 dsp_load_label.set_markup (buf);
1716 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1718 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1720 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1723 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1727 ARDOUR_UI::update_peak_thread_work ()
1730 const int c = SourceFactory::peak_work_queue_length ();
1732 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1733 peak_thread_work_label.set_markup (buf);
1735 peak_thread_work_label.set_markup (X_(""));
1740 ARDOUR_UI::count_recenabled_streams (Route& route)
1742 Track* track = dynamic_cast<Track*>(&route);
1743 if (track && track->rec_enable_control()->get_value()) {
1744 rec_enabled_streams += track->n_inputs().n_total();
1749 ARDOUR_UI::format_disk_space_label (float remain_sec)
1751 if (remain_sec < 0) {
1752 disk_space_label.set_text (_("N/A"));
1753 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1759 int sec = floor (remain_sec);
1760 int hrs = sec / 3600;
1761 int mins = (sec / 60) % 60;
1762 int secs = sec % 60;
1763 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1764 ArdourWidgets::set_tooltip (disk_space_label, buf);
1766 if (remain_sec > 86400) {
1767 disk_space_label.set_text (_("Rec: >24h"));
1769 } else if (remain_sec > 32400 /* 9 hours */) {
1770 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1771 } else if (remain_sec > 5940 /* 99 mins */) {
1772 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1774 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1776 disk_space_label.set_text (buf);
1781 ARDOUR_UI::update_disk_space()
1783 if (_session == 0) {
1784 format_disk_space_label (-1);
1788 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1789 samplecnt_t fr = _session->sample_rate();
1792 /* skip update - no SR available */
1793 format_disk_space_label (-1);
1798 /* Available space is unknown */
1799 format_disk_space_label (-1);
1800 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1801 format_disk_space_label (max_samplecnt);
1803 rec_enabled_streams = 0;
1804 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1806 samplecnt_t samples = opt_samples.get_value_or (0);
1808 if (rec_enabled_streams) {
1809 samples /= rec_enabled_streams;
1812 format_disk_space_label (samples / (float)fr);
1818 ARDOUR_UI::update_timecode_format ()
1824 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1825 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1827 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1828 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1833 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1834 matching ? X_("green") : X_("red"),
1835 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1837 snprintf (buf, sizeof (buf), "TC: n/a");
1840 timecode_format_label.set_markup (buf);
1844 ARDOUR_UI::update_wall_clock ()
1848 static int last_min = -1;
1851 tm_now = localtime (&now);
1852 if (last_min != tm_now->tm_min) {
1854 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1855 wall_clock_label.set_text (buf);
1856 last_min = tm_now->tm_min;
1863 ARDOUR_UI::open_recent_session ()
1865 bool can_return = (_session != 0);
1867 SessionDialog recent_session_dialog;
1871 ResponseType r = (ResponseType) recent_session_dialog.run ();
1874 case RESPONSE_ACCEPT:
1878 recent_session_dialog.hide();
1881 exit (EXIT_FAILURE);
1885 recent_session_dialog.hide();
1889 std::string path = recent_session_dialog.session_folder();
1890 std::string state = recent_session_dialog.session_name (should_be_new);
1892 if (should_be_new == true) {
1896 _session_is_new = false;
1898 if (load_session (path, state) == 0) {
1907 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1909 if (!AudioEngine::instance()->running()) {
1910 MessageDialog msg (parent, string_compose (
1911 _("%1 is not connected to any audio backend.\n"
1912 "You cannot open or close sessions in this condition"),
1914 pop_back_splash (msg);
1922 ARDOUR_UI::open_session ()
1924 if (!check_audioengine (_main_window)) {
1928 /* ardour sessions are folders */
1929 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1930 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1931 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1932 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1935 string session_parent_dir = Glib::path_get_dirname(_session->path());
1936 open_session_selector.set_current_folder(session_parent_dir);
1938 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1941 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1943 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1944 string default_session_folder = Config->get_default_session_parent_dir();
1945 open_session_selector.add_shortcut_folder (default_session_folder);
1947 catch (Glib::Error const& e) {
1948 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1951 FileFilter session_filter;
1952 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1953 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1954 open_session_selector.add_filter (session_filter);
1956 FileFilter archive_filter;
1957 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1958 archive_filter.set_name (_("Session Archives"));
1960 open_session_selector.add_filter (archive_filter);
1962 open_session_selector.set_filter (session_filter);
1964 int response = open_session_selector.run();
1965 open_session_selector.hide ();
1967 if (response == Gtk::RESPONSE_CANCEL) {
1971 string session_path = open_session_selector.get_filename();
1975 if (session_path.length() > 0) {
1976 int rv = ARDOUR::inflate_session (session_path,
1977 Config->get_default_session_parent_dir(), path, name);
1979 _session_is_new = false;
1980 load_session (path, name);
1983 MessageDialog msg (_main_window,
1984 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1987 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1988 _session_is_new = isnew;
1989 load_session (path, name);
1995 ARDOUR_UI::session_add_mixed_track (
1996 const ChanCount& input,
1997 const ChanCount& output,
1998 RouteGroup* route_group,
2000 const string& name_template,
2002 PluginInfoPtr instrument,
2003 Plugin::PresetRecord* pset,
2004 ARDOUR::PresentationInfo::order_t order)
2008 if (Profile->get_mixbus ()) {
2013 list<boost::shared_ptr<MidiTrack> > tracks;
2014 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2016 if (tracks.size() != how_many) {
2017 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2022 display_insufficient_ports_message ();
2028 ARDOUR_UI::session_add_midi_bus (
2029 RouteGroup* route_group,
2031 const string& name_template,
2033 PluginInfoPtr instrument,
2034 Plugin::PresetRecord* pset,
2035 ARDOUR::PresentationInfo::order_t order)
2037 if (_session == 0) {
2038 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2042 if (Profile->get_mixbus ()) {
2048 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2049 if (routes.size() != how_many) {
2050 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2055 display_insufficient_ports_message ();
2061 ARDOUR_UI::session_add_midi_route (
2063 RouteGroup* route_group,
2065 const string& name_template,
2067 PluginInfoPtr instrument,
2068 Plugin::PresetRecord* pset,
2069 ARDOUR::PresentationInfo::order_t order)
2071 ChanCount one_midi_channel;
2072 one_midi_channel.set (DataType::MIDI, 1);
2075 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2077 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2082 ARDOUR_UI::session_add_audio_route (
2084 int32_t input_channels,
2085 int32_t output_channels,
2086 ARDOUR::TrackMode mode,
2087 RouteGroup* route_group,
2089 string const & name_template,
2091 ARDOUR::PresentationInfo::order_t order)
2093 list<boost::shared_ptr<AudioTrack> > tracks;
2100 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2102 if (tracks.size() != how_many) {
2103 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2109 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2111 if (routes.size() != how_many) {
2112 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2119 display_insufficient_ports_message ();
2124 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2125 (*i)->set_strict_io (true);
2127 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2128 (*i)->set_strict_io (true);
2134 ARDOUR_UI::session_add_foldback_bus (uint32_t how_many, string const & name_template)
2141 routes = _session->new_audio_route (2, 2, 0, how_many, name_template, PresentationInfo::FoldbackBus, -1);
2143 if (routes.size() != how_many) {
2144 error << string_compose (P_("could not create %1 new foldback bus", "could not create %1 new foldback busses", how_many), how_many)
2150 display_insufficient_ports_message ();
2154 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2155 (*i)->set_strict_io (true);
2160 ARDOUR_UI::display_insufficient_ports_message ()
2162 MessageDialog msg (_main_window,
2163 string_compose (_("There are insufficient ports available\n\
2164 to create a new track or bus.\n\
2165 You should save %1, exit and\n\
2166 restart with more ports."), PROGRAM_NAME));
2167 pop_back_splash (msg);
2172 ARDOUR_UI::transport_goto_start ()
2175 _session->goto_start();
2177 /* force displayed area in editor to start no matter
2178 what "follow playhead" setting is.
2182 editor->center_screen (_session->current_start_sample ());
2188 ARDOUR_UI::transport_goto_zero ()
2191 _session->request_locate (0);
2193 /* force displayed area in editor to start no matter
2194 what "follow playhead" setting is.
2198 editor->reset_x_origin (0);
2204 ARDOUR_UI::transport_goto_wallclock ()
2206 if (_session && editor) {
2210 samplepos_t samples;
2213 localtime_r (&now, &tmnow);
2215 samplecnt_t sample_rate = _session->sample_rate();
2217 if (sample_rate == 0) {
2218 /* no frame rate available */
2222 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2223 samples += tmnow.tm_min * (60 * sample_rate);
2224 samples += tmnow.tm_sec * sample_rate;
2226 _session->request_locate (samples, _session->transport_rolling ());
2228 /* force displayed area in editor to start no matter
2229 what "follow playhead" setting is.
2233 editor->center_screen (samples);
2239 ARDOUR_UI::transport_goto_end ()
2242 samplepos_t const sample = _session->current_end_sample();
2243 _session->request_locate (sample);
2245 /* force displayed area in editor to start no matter
2246 what "follow playhead" setting is.
2250 editor->center_screen (sample);
2256 ARDOUR_UI::transport_stop ()
2262 if (_session->is_auditioning()) {
2263 _session->cancel_audition ();
2267 _session->request_stop (false, true);
2270 /** Check if any tracks are record enabled. If none are, record enable all of them.
2271 * @return true if track record-enabled status was changed, false otherwise.
2274 ARDOUR_UI::trx_record_enable_all_tracks ()
2280 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2281 bool none_record_enabled = true;
2283 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2284 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2287 if (t->rec_enable_control()->get_value()) {
2288 none_record_enabled = false;
2293 if (none_record_enabled) {
2294 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2297 return none_record_enabled;
2301 ARDOUR_UI::transport_record (bool roll)
2304 switch (_session->record_status()) {
2305 case Session::Disabled:
2306 if (_session->ntracks() == 0) {
2307 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."));
2311 if (Profile->get_trx()) {
2312 roll = trx_record_enable_all_tracks ();
2314 _session->maybe_enable_record ();
2319 case Session::Recording:
2321 _session->request_stop();
2323 _session->disable_record (false, true);
2327 case Session::Enabled:
2328 _session->disable_record (false, true);
2334 ARDOUR_UI::transport_roll ()
2340 if (_session->is_auditioning()) {
2344 if (_session->config.get_external_sync()) {
2345 switch (TransportMasterManager::instance().current()->type()) {
2349 /* transport controlled by the master */
2354 bool rolling = _session->transport_rolling();
2356 if (_session->get_play_loop()) {
2358 /* If loop playback is not a mode, then we should cancel
2359 it when this action is requested. If it is a mode
2360 we just leave it in place.
2363 if (!Config->get_loop_is_mode()) {
2364 /* XXX it is not possible to just leave seamless loop and keep
2365 playing at present (nov 4th 2009)
2367 if (!Config->get_seamless_loop()) {
2368 /* stop loop playback and stop rolling */
2369 _session->request_play_loop (false, true);
2370 } else if (rolling) {
2371 /* stop loop playback but keep rolling */
2372 _session->request_play_loop (false, false);
2376 } else if (_session->get_play_range () ) {
2377 /* stop playing a range if we currently are */
2378 _session->request_play_range (0, true);
2382 _session->request_transport_speed (1.0f);
2387 ARDOUR_UI::get_smart_mode() const
2389 return ( editor->get_smart_mode() );
2394 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2400 if (_session->is_auditioning()) {
2401 _session->cancel_audition ();
2405 if (_session->config.get_external_sync()) {
2406 switch (TransportMasterManager::instance().current()->type()) {
2410 /* transport controlled by the master */
2415 bool rolling = _session->transport_rolling();
2416 bool affect_transport = true;
2418 if (rolling && roll_out_of_bounded_mode) {
2419 /* drop out of loop/range playback but leave transport rolling */
2420 if (_session->get_play_loop()) {
2421 if (_session->actively_recording()) {
2423 /* just stop using the loop, then actually stop
2426 _session->request_play_loop (false, affect_transport);
2429 if (Config->get_seamless_loop()) {
2430 /* the disk buffers contain copies of the loop - we can't
2431 just keep playing, so stop the transport. the user
2432 can restart as they wish.
2434 affect_transport = true;
2436 /* disk buffers are normal, so we can keep playing */
2437 affect_transport = false;
2439 _session->request_play_loop (false, affect_transport);
2441 } else if (_session->get_play_range ()) {
2442 affect_transport = false;
2443 _session->request_play_range (0, true);
2447 if (affect_transport) {
2449 _session->request_stop (with_abort, true);
2451 } else if (!with_abort) { /* with_abort == true means the
2452 * command was intended to stop
2453 * transport, not start.
2456 /* the only external sync condition we can be in here
2457 * would be Engine (JACK) sync, in which case we still
2461 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
2462 _session->request_play_range (&editor->get_selection().time, true);
2463 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2465 _session->request_transport_speed (1.0f);
2471 ARDOUR_UI::toggle_session_auto_loop ()
2477 Location * looploc = _session->locations()->auto_loop_location();
2483 if (_session->get_play_loop()) {
2485 /* looping enabled, our job is to disable it */
2487 _session->request_play_loop (false);
2491 /* looping not enabled, our job is to enable it.
2493 loop-is-NOT-mode: this action always starts the transport rolling.
2494 loop-IS-mode: this action simply sets the loop play mechanism, but
2495 does not start transport.
2497 if (Config->get_loop_is_mode()) {
2498 _session->request_play_loop (true, false);
2500 _session->request_play_loop (true, true);
2504 //show the loop markers
2505 looploc->set_hidden (false, this);
2509 ARDOUR_UI::transport_play_selection ()
2515 editor->play_selection ();
2519 ARDOUR_UI::transport_play_preroll ()
2524 editor->play_with_preroll ();
2528 ARDOUR_UI::transport_rec_preroll ()
2533 editor->rec_with_preroll ();
2537 ARDOUR_UI::transport_rec_count_in ()
2542 editor->rec_with_count_in ();
2546 ARDOUR_UI::transport_rewind (int option)
2548 float current_transport_speed;
2551 current_transport_speed = _session->transport_speed();
2553 if (current_transport_speed >= 0.0f) {
2556 _session->request_transport_speed (-1.0f);
2559 _session->request_transport_speed (-4.0f);
2562 _session->request_transport_speed (-0.5f);
2567 _session->request_transport_speed (current_transport_speed * 1.5f);
2573 ARDOUR_UI::transport_forward (int option)
2579 float current_transport_speed = _session->transport_speed();
2581 if (current_transport_speed <= 0.0f) {
2584 _session->request_transport_speed (1.0f);
2587 _session->request_transport_speed (4.0f);
2590 _session->request_transport_speed (0.5f);
2595 _session->request_transport_speed (current_transport_speed * 1.5f);
2600 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2606 boost::shared_ptr<Route> r;
2608 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2610 boost::shared_ptr<Track> t;
2612 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2613 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2619 ARDOUR_UI::map_transport_state ()
2622 layered_button.set_sensitive (false);
2626 shuttle_box.map_transport_state ();
2628 float sp = _session->transport_speed();
2631 layered_button.set_sensitive (!_session->actively_recording ());
2633 layered_button.set_sensitive (true);
2634 update_disk_space ();
2639 ARDOUR_UI::blink_handler (bool blink_on)
2641 sync_blink (blink_on);
2643 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2646 error_blink (blink_on);
2647 solo_blink (blink_on);
2648 audition_blink (blink_on);
2649 feedback_blink (blink_on);
2653 ARDOUR_UI::update_clocks ()
2655 if (!_session) return;
2657 if (editor && !editor->dragging_playhead()) {
2658 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2663 ARDOUR_UI::start_clocking ()
2665 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2666 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2668 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2673 ARDOUR_UI::stop_clocking ()
2675 clock_signal_connection.disconnect ();
2679 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2683 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2685 label->set_text (buf);
2686 bar->set_fraction (fraction);
2688 /* process events, redraws, etc. */
2690 while (gtk_events_pending()) {
2691 gtk_main_iteration ();
2694 return true; /* continue with save-as */
2698 ARDOUR_UI::save_session_as ()
2704 if (_session->dirty()) {
2705 vector<string> actions;
2706 actions.push_back (_("Abort save-as"));
2707 actions.push_back (_("Don't save now, just save-as"));
2708 actions.push_back (_("Save it first"));
2709 switch (ask_about_saving_session(actions)) {
2714 if (save_state_canfail ("")) {
2715 MessageDialog msg (_main_window,
2716 string_compose (_("\
2717 %1 was unable to save your session.\n\n\
2718 If you still wish to proceed, please use the\n\n\
2719 \"Don't save now\" option."), PROGRAM_NAME));
2720 pop_back_splash(msg);
2726 _session->remove_pending_capture_state ();
2731 if (!save_as_dialog) {
2732 save_as_dialog = new SaveAsDialog;
2735 save_as_dialog->set_name (_session->name());
2737 int response = save_as_dialog->run ();
2739 save_as_dialog->hide ();
2742 case Gtk::RESPONSE_OK:
2751 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2752 sa.new_name = save_as_dialog->new_name ();
2753 sa.switch_to = save_as_dialog->switch_to();
2754 sa.copy_media = save_as_dialog->copy_media();
2755 sa.copy_external = save_as_dialog->copy_external();
2756 sa.include_media = save_as_dialog->include_media ();
2758 /* Only bother with a progress dialog if we're going to copy
2759 media into the save-as target. Without that choice, this
2760 will be very fast because we're only talking about a few kB's to
2761 perhaps a couple of MB's of data.
2764 ArdourDialog progress_dialog (_("Save As"), true);
2767 if (sa.include_media && sa.copy_media) {
2769 Gtk::Label* label = manage (new Gtk::Label());
2770 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2772 progress_dialog.get_vbox()->pack_start (*label);
2773 progress_dialog.get_vbox()->pack_start (*progress_bar);
2775 progress_bar->show ();
2777 /* this signal will be emitted from within this, the calling thread,
2778 * after every file is copied. It provides information on percentage
2779 * complete (in terms of total data to copy), the number of files
2780 * copied so far, and the total number to copy.
2783 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2785 progress_dialog.show_all ();
2786 progress_dialog.present ();
2789 if (_session->save_as (sa)) {
2791 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2795 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2796 * the trick is this: if the new session was copy with media included,
2797 * then Session::save_as() will have already done a neat trick to avoid
2798 * us having to unload and load the new state. But if the media was not
2799 * included, then this is required (it avoids us having to otherwise
2800 * drop all references to media (sources).
2803 if (!sa.include_media && sa.switch_to) {
2804 unload_session (false);
2805 load_session (sa.final_session_folder_name, sa.new_name);
2810 ARDOUR_UI::archive_session ()
2818 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2820 SessionArchiveDialog sad;
2821 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2822 int response = sad.run ();
2824 if (response != Gtk::RESPONSE_OK) {
2829 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2830 MessageDialog msg (_("Session Archiving failed."));
2836 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2840 struct tm local_time;
2843 localtime_r (&n, &local_time);
2844 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2845 if (switch_to_it && _session->dirty ()) {
2846 save_state_canfail ("");
2849 save_state (timebuf, switch_to_it);
2854 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2858 prompter.get_result (snapname);
2860 bool do_save = (snapname.length() != 0);
2863 char illegal = Session::session_name_is_legal(snapname);
2865 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2866 "snapshot names may not contain a '%1' character"), illegal));
2872 vector<std::string> p;
2873 get_state_files_in_directory (_session->session_directory().root_path(), p);
2874 vector<string> n = get_file_names_no_extension (p);
2876 if (find (n.begin(), n.end(), snapname) != n.end()) {
2878 do_save = overwrite_file_dialog (prompter,
2879 _("Confirm Snapshot Overwrite"),
2880 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2884 save_state (snapname, switch_to_it);
2894 /** Ask the user for the name of a new snapshot and then take it.
2898 ARDOUR_UI::snapshot_session (bool switch_to_it)
2900 if (switch_to_it && _session->dirty()) {
2901 vector<string> actions;
2902 actions.push_back (_("Abort saving snapshot"));
2903 actions.push_back (_("Don't save now, just snapshot"));
2904 actions.push_back (_("Save it first"));
2905 switch (ask_about_saving_session(actions)) {
2910 if (save_state_canfail ("")) {
2911 MessageDialog msg (_main_window,
2912 string_compose (_("\
2913 %1 was unable to save your session.\n\n\
2914 If you still wish to proceed, please use the\n\n\
2915 \"Don't save now\" option."), PROGRAM_NAME));
2916 pop_back_splash(msg);
2922 _session->remove_pending_capture_state ();
2927 Prompter prompter (true);
2928 prompter.set_name ("Prompter");
2929 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2931 prompter.set_title (_("Snapshot and switch"));
2932 prompter.set_prompt (_("New session name"));
2934 prompter.set_title (_("Take Snapshot"));
2935 prompter.set_prompt (_("Name of new snapshot"));
2939 prompter.set_initial_text (_session->snap_name());
2941 Glib::DateTime tm (g_date_time_new_now_local ());
2942 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2945 bool finished = false;
2947 switch (prompter.run()) {
2948 case RESPONSE_ACCEPT:
2950 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2961 /** Ask the user for a new session name and then rename the session to it.
2965 ARDOUR_UI::rename_session ()
2971 Prompter prompter (true);
2974 prompter.set_name ("Prompter");
2975 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2976 prompter.set_title (_("Rename Session"));
2977 prompter.set_prompt (_("New session name"));
2980 switch (prompter.run()) {
2981 case RESPONSE_ACCEPT:
2983 prompter.get_result (name);
2985 bool do_rename = (name.length() != 0);
2988 char illegal = Session::session_name_is_legal (name);
2991 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2992 "session names may not contain a '%1' character"), illegal));
2997 switch (_session->rename (name)) {
2999 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3000 msg.set_position (WIN_POS_MOUSE);
3008 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3009 msg.set_position (WIN_POS_MOUSE);
3025 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3027 if (!_session || _session->deletion_in_progress()) {
3031 XMLNode* node = new XMLNode (X_("UI"));
3033 WM::Manager::instance().add_state (*node);
3035 node->add_child_nocopy (gui_object_state->get_state());
3037 _session->add_extra_xml (*node);
3039 if (export_video_dialog) {
3040 _session->add_extra_xml (export_video_dialog->get_state());
3043 save_state_canfail (name, switch_to_it);
3047 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3052 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3057 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3062 ARDOUR_UI::primary_clock_value_changed ()
3065 _session->request_locate (primary_clock->current_time ());
3070 ARDOUR_UI::big_clock_value_changed ()
3073 _session->request_locate (big_clock->current_time ());
3078 ARDOUR_UI::secondary_clock_value_changed ()
3081 _session->request_locate (secondary_clock->current_time ());
3085 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3087 if (response == RESPONSE_ACCEPT) {
3088 const string name = d->get_template_name ();
3089 const string desc = d->get_description ();
3091 int failed = _session->save_template (name, desc);
3093 if (failed == -2) { /* file already exists. */
3094 bool overwrite = overwrite_file_dialog (*d,
3095 _("Confirm Template Overwrite"),
3096 _("A template already exists with that name. Do you want to overwrite it?"));
3099 _session->save_template (name, desc, true);
3111 ARDOUR_UI::save_template ()
3113 if (!check_audioengine (_main_window)) {
3117 const std::string desc = SessionMetadata::Metadata()->description ();
3118 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3119 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3123 void ARDOUR_UI::manage_templates ()
3130 ARDOUR_UI::edit_metadata ()
3132 SessionMetadataEditor dialog;
3133 dialog.set_session (_session);
3134 dialog.grab_focus ();
3139 ARDOUR_UI::import_metadata ()
3141 SessionMetadataImporter dialog;
3142 dialog.set_session (_session);
3147 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3149 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3151 MessageDialog msg (str,
3153 Gtk::MESSAGE_WARNING,
3154 Gtk::BUTTONS_YES_NO,
3158 msg.set_name (X_("OpenExistingDialog"));
3159 msg.set_title (_("Open Existing Session"));
3160 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3161 msg.set_position (Gtk::WIN_POS_CENTER);
3162 pop_back_splash (msg);
3164 switch (msg.run()) {
3173 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3175 BusProfile bus_profile;
3178 bus_profile.master_out_channels = 2;
3180 /* get settings from advanced section of NSD */
3181 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3184 // NULL profile: no master, no monitor
3185 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3193 ARDOUR_UI::load_from_application_api (const std::string& path)
3195 /* OS X El Capitan (and probably later) now somehow passes the command
3196 line arguments to an app via the openFile delegate protocol. Ardour
3197 already does its own command line processing, and having both
3198 pathways active causes crashes. So, if the command line was already
3199 set, do nothing here.
3202 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3206 ARDOUR_COMMAND_LINE::session_name = path;
3208 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3210 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3212 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3213 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3214 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3215 * -> SessionDialog is not displayed
3218 if (_session_dialog) {
3219 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3220 std::string session_path = path;
3221 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3222 session_path = Glib::path_get_dirname (session_path);
3224 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3225 _session_dialog->set_provided_session (session_name, session_path);
3226 _session_dialog->response (RESPONSE_NONE);
3227 _session_dialog->hide();
3232 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3233 /* /path/to/foo => /path/to/foo, foo */
3234 rv = load_session (path, basename_nosuffix (path));
3236 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3237 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3240 // if load_session fails -> pop up SessionDialog.
3242 ARDOUR_COMMAND_LINE::session_name = "";
3244 if (get_session_parameters (true, false)) {
3245 exit (EXIT_FAILURE);
3250 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3252 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3254 string session_name;
3255 string session_path;
3256 string template_name;
3258 bool likely_new = false;
3259 bool cancel_not_quit;
3261 /* deal with any existing DIRTY session now, rather than later. don't
3262 * treat a non-dirty session this way, so that it stays visible
3263 * as we bring up the new session dialog.
3266 if (_session && ARDOUR_UI::instance()->video_timeline) {
3267 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3270 /* if there is already a session, relabel the button
3271 on the SessionDialog so that we don't Quit directly
3273 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3275 if (_session && _session->dirty()) {
3276 if (unload_session (false)) {
3277 /* unload cancelled by user */
3280 ARDOUR_COMMAND_LINE::session_name = "";
3283 if (!load_template.empty()) {
3284 should_be_new = true;
3285 template_name = load_template;
3288 session_path = ARDOUR_COMMAND_LINE::session_name;
3290 if (!session_path.empty()) {
3292 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3294 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3296 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3297 /* session/snapshot file, change path to be dir */
3298 session_path = Glib::path_get_dirname (session_path);
3302 /* session (file or folder) does not exist ... did the
3303 * user give us a path or just a name?
3306 if (session_path.find (G_DIR_SEPARATOR) == string::npos) {
3307 /* user gave session name with no path info, use
3308 default session folder.
3310 session_name = ARDOUR_COMMAND_LINE::session_name;
3311 session_path = Glib::build_filename (Config->get_default_session_parent_dir (), session_name);
3313 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3318 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3320 _session_dialog = &session_dialog;
3323 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3325 /* if they named a specific statefile, use it, otherwise they are
3326 just giving a session folder, and we want to use it as is
3327 to find the session.
3330 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3332 if (suffix != string::npos) {
3333 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3334 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3335 session_name = Glib::path_get_basename (session_name);
3337 session_path = ARDOUR_COMMAND_LINE::session_name;
3338 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3343 session_dialog.clear_given ();
3346 if (should_be_new || session_name.empty()) {
3347 /* need the dialog to get info from user */
3349 cerr << "run dialog\n";
3351 switch (session_dialog.run()) {
3352 case RESPONSE_ACCEPT:
3355 /* this is used for async * app->ShouldLoad(). */
3356 continue; // while loop
3359 if (quit_on_cancel) {
3360 ARDOUR_UI::finish ();
3361 Gtkmm2ext::Application::instance()->cleanup();
3363 pthread_cancel_all ();
3364 return -1; // caller is responsible to call exit()
3370 session_dialog.hide ();
3373 /* if we run the startup dialog again, offer more than just "new session" */
3375 should_be_new = false;
3377 session_name = session_dialog.session_name (likely_new);
3378 session_path = session_dialog.session_folder ();
3385 int rv = ARDOUR::inflate_session (session_name,
3386 Config->get_default_session_parent_dir(), session_path, session_name);
3388 MessageDialog msg (session_dialog,
3389 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3394 session_dialog.set_provided_session (session_name, session_path);
3398 // XXX check archive, inflate
3399 string::size_type suffix = session_name.find (statefile_suffix);
3401 if (suffix != string::npos) {
3402 session_name = session_name.substr (0, suffix);
3405 /* this shouldn't happen, but we catch it just in case it does */
3407 if (session_name.empty()) {
3411 if (session_dialog.use_session_template()) {
3412 template_name = session_dialog.session_template_name();
3413 _session_is_new = true;
3416 if (session_name[0] == G_DIR_SEPARATOR ||
3417 #ifdef PLATFORM_WINDOWS
3418 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3420 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3421 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3426 /* absolute path or cwd-relative path specified for session name: infer session folder
3427 from what was given.
3430 session_path = Glib::path_get_dirname (session_name);
3431 session_name = Glib::path_get_basename (session_name);
3435 session_path = session_dialog.session_folder();
3437 char illegal = Session::session_name_is_legal (session_name);
3440 MessageDialog msg (session_dialog,
3441 string_compose (_("To ensure compatibility with various systems\n"
3442 "session names may not contain a '%1' character"),
3445 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3450 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3453 if (likely_new && !nsm) {
3455 std::string existing = Glib::build_filename (session_path, session_name);
3457 if (!ask_about_loading_existing_session (existing)) {
3458 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3463 _session_is_new = false;
3468 pop_back_splash (session_dialog);
3469 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3471 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3475 char illegal = Session::session_name_is_legal(session_name);
3478 pop_back_splash (session_dialog);
3479 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3480 "session names may not contain a '%1' character"), illegal));
3482 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3486 _session_is_new = true;
3489 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3491 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3492 meta_session_setup (template_name.substr (11));
3494 } else if (likely_new && template_name.empty()) {
3496 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3500 ret = load_session (session_path, session_name, template_name);
3503 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3504 exit (EXIT_FAILURE);
3507 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3508 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3509 exit (EXIT_FAILURE);
3512 /* clear this to avoid endless attempts to load the
3516 ARDOUR_COMMAND_LINE::session_name = "";
3520 _session_dialog = NULL;
3526 ARDOUR_UI::close_session()
3528 if (!check_audioengine (_main_window)) {
3532 if (unload_session (true)) {
3536 ARDOUR_COMMAND_LINE::session_name = "";
3538 if (get_session_parameters (true, false)) {
3539 exit (EXIT_FAILURE);
3543 /** @param snap_name Snapshot name (without .ardour suffix).
3544 * @return -2 if the load failed because we are not connected to the AudioEngine.
3547 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3549 /* load_session calls flush_pending() which allows
3550 * GUI interaction and potentially loading another session
3551 * (that was easy via snapshot sidebar).
3552 * Recursing into load_session() from load_session() and recusive
3553 * event loops causes all kind of crashes.
3555 assert (!session_load_in_progress);
3556 if (session_load_in_progress) {
3559 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3561 Session *new_session;
3566 unload_status = unload_session ();
3568 if (unload_status < 0) {
3570 } else if (unload_status > 0) {
3576 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3579 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3582 /* this one is special */
3584 catch (AudioEngine::PortRegistrationFailure const& err) {
3586 MessageDialog msg (err.what(),
3589 Gtk::BUTTONS_CLOSE);
3591 msg.set_title (_("Port Registration Error"));
3592 msg.set_secondary_text (_("Click the Close button to try again."));
3593 msg.set_position (Gtk::WIN_POS_CENTER);
3594 pop_back_splash (msg);
3597 int response = msg.run ();
3602 case RESPONSE_CANCEL:
3603 exit (EXIT_FAILURE);
3609 catch (SessionException const& e) {
3610 MessageDialog msg (string_compose(
3611 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3612 path, snap_name, e.what()),
3617 msg.set_title (_("Loading Error"));
3618 msg.set_position (Gtk::WIN_POS_CENTER);
3619 pop_back_splash (msg);
3631 MessageDialog msg (string_compose(
3632 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3638 msg.set_title (_("Loading Error"));
3639 msg.set_position (Gtk::WIN_POS_CENTER);
3640 pop_back_splash (msg);
3652 list<string> const u = new_session->unknown_processors ();
3654 MissingPluginDialog d (_session, u);
3659 if (!new_session->writable()) {
3660 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3665 msg.set_title (_("Read-only Session"));
3666 msg.set_position (Gtk::WIN_POS_CENTER);
3667 pop_back_splash (msg);
3674 /* Now the session been created, add the transport controls */
3675 new_session->add_controllable(roll_controllable);
3676 new_session->add_controllable(stop_controllable);
3677 new_session->add_controllable(goto_start_controllable);
3678 new_session->add_controllable(goto_end_controllable);
3679 new_session->add_controllable(auto_loop_controllable);
3680 new_session->add_controllable(play_selection_controllable);
3681 new_session->add_controllable(rec_controllable);
3683 set_session (new_session);
3686 _session->set_clean ();
3689 #ifdef WINDOWS_VST_SUPPORT
3690 fst_stop_threading();
3694 Timers::TimerSuspender t;
3698 #ifdef WINDOWS_VST_SUPPORT
3699 fst_start_threading();
3703 if (!mix_template.empty ()) {
3704 /* if mix_template is given, assume this is a new session */
3705 string metascript = Glib::build_filename (mix_template, "template.lua");
3706 meta_session_setup (metascript);
3711 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3712 * which is queued by set_session().
3713 * If session-loading fails we hide it explicitly.
3714 * This covers both cases in a central place.
3723 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3725 Session *new_session;
3728 x = unload_session ();
3736 _session_is_new = true;
3739 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3742 catch (SessionException const& e) {
3743 cerr << "Here are the errors associated with this failed session:\n";
3745 cerr << "---------\n";
3746 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3747 msg.set_title (_("Loading Error"));
3748 msg.set_position (Gtk::WIN_POS_CENTER);
3749 pop_back_splash (msg);
3754 cerr << "Here are the errors associated with this failed session:\n";
3756 cerr << "---------\n";
3757 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3758 msg.set_title (_("Loading Error"));
3759 msg.set_position (Gtk::WIN_POS_CENTER);
3760 pop_back_splash (msg);
3765 /* Give the new session the default GUI state, if such things exist */
3768 n = Config->instant_xml (X_("Editor"));
3770 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3771 new_session->add_instant_xml (*n, false);
3773 n = Config->instant_xml (X_("Mixer"));
3775 new_session->add_instant_xml (*n, false);
3778 n = Config->instant_xml (X_("Preferences"));
3780 new_session->add_instant_xml (*n, false);
3783 /* Put the playhead at 0 and scroll fully left */
3784 n = new_session->instant_xml (X_("Editor"));
3786 n->set_property (X_("playhead"), X_("0"));
3787 n->set_property (X_("left-frame"), X_("0"));
3790 set_session (new_session);
3792 new_session->save_state(new_session->name());
3798 static void _lua_print (std::string s) {
3800 std::cout << "LuaInstance: " << s << "\n";
3802 PBD::info << "LuaInstance: " << s << endmsg;
3805 std::map<std::string, std::string>
3806 ARDOUR_UI::route_setup_info (const std::string& script_path)
3808 std::map<std::string, std::string> rv;
3810 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3815 lua.Print.connect (&_lua_print);
3818 lua_State* L = lua.getState();
3819 LuaInstance::register_classes (L);
3820 LuaBindings::set_session (L, _session);
3821 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3822 lua_setglobal (L, "Editor");
3824 lua.do_command ("function ardour () end");
3825 lua.do_file (script_path);
3828 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3829 if (!fn.isFunction ()) {
3832 luabridge::LuaRef rs = fn ();
3833 if (!rs.isTable ()) {
3836 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3837 if (!i.key().isString()) {
3840 std::string key = i.key().tostring();
3841 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3842 rv[key] = i.value().tostring();
3845 } catch (luabridge::LuaException const& e) {
3846 cerr << "LuaException:" << e.what () << endl;
3852 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3854 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3857 assert (add_route_dialog);
3860 if ((count = add_route_dialog->count()) <= 0) {
3865 lua.Print.connect (&_lua_print);
3868 lua_State* L = lua.getState();
3869 LuaInstance::register_classes (L);
3870 LuaBindings::set_session (L, _session);
3871 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3872 lua_setglobal (L, "Editor");
3874 lua.do_command ("function ardour () end");
3875 lua.do_file (script_path);
3877 luabridge::LuaRef args (luabridge::newTable (L));
3879 args["name"] = add_route_dialog->name_template ();
3880 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3881 args["group"] = add_route_dialog->route_group ();
3882 args["strict_io"] = add_route_dialog->use_strict_io ();
3883 args["instrument"] = add_route_dialog->requested_instrument ();
3884 args["track_mode"] = add_route_dialog->mode ();
3885 args["channels"] = add_route_dialog->channel_count ();
3886 args["how_many"] = count;
3889 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3890 if (fn.isFunction()) {
3893 } catch (luabridge::LuaException const& e) {
3894 cerr << "LuaException:" << e.what () << endl;
3896 display_insufficient_ports_message ();
3901 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3903 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3908 lua.Print.connect (&_lua_print);
3911 lua_State* L = lua.getState();
3912 LuaInstance::register_classes (L);
3913 LuaBindings::set_session (L, _session);
3914 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3915 lua_setglobal (L, "Editor");
3917 lua.do_command ("function ardour () end");
3918 lua.do_file (script_path);
3921 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3922 if (fn.isFunction()) {
3925 } catch (luabridge::LuaException const& e) {
3926 cerr << "LuaException:" << e.what () << endl;
3928 display_insufficient_ports_message ();
3933 ARDOUR_UI::launch_chat ()
3935 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3937 dialog.set_title (_("About the Chat"));
3938 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."));
3940 switch (dialog.run()) {
3942 open_uri("http://webchat.freenode.net/?channels=ardour");
3950 ARDOUR_UI::launch_manual ()
3952 PBD::open_uri (Config->get_tutorial_manual_url());
3956 ARDOUR_UI::launch_reference ()
3958 PBD::open_uri (Config->get_reference_manual_url());
3962 ARDOUR_UI::launch_tracker ()
3964 PBD::open_uri ("http://tracker.ardour.org");
3968 ARDOUR_UI::launch_subscribe ()
3970 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3974 ARDOUR_UI::launch_cheat_sheet ()
3977 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3979 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3984 ARDOUR_UI::launch_website ()
3986 PBD::open_uri ("http://ardour.org");
3990 ARDOUR_UI::launch_website_dev ()
3992 PBD::open_uri ("http://ardour.org/development.html");
3996 ARDOUR_UI::launch_forums ()
3998 PBD::open_uri ("https://community.ardour.org/forums");
4002 ARDOUR_UI::launch_howto_report ()
4004 PBD::open_uri ("http://ardour.org/reporting_bugs");
4008 ARDOUR_UI::loading_message (const std::string& msg)
4010 if (ARDOUR_COMMAND_LINE::no_splash) {
4018 splash->message (msg);
4022 ARDOUR_UI::show_splash ()
4026 splash = new Splash;
4036 ARDOUR_UI::hide_splash ()
4043 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4047 removed = rep.paths.size();
4050 MessageDialog msgd (_main_window,
4051 _("No files were ready for clean-up"),
4055 msgd.set_title (_("Clean-up"));
4056 msgd.set_secondary_text (_("If this seems surprising, \n\
4057 check for any existing snapshots.\n\
4058 These may still include regions that\n\
4059 require some unused files to continue to exist."));
4065 ArdourDialog results (_("Clean-up"), true, false);
4067 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4068 CleanupResultsModelColumns() {
4072 Gtk::TreeModelColumn<std::string> visible_name;
4073 Gtk::TreeModelColumn<std::string> fullpath;
4077 CleanupResultsModelColumns results_columns;
4078 Glib::RefPtr<Gtk::ListStore> results_model;
4079 Gtk::TreeView results_display;
4081 results_model = ListStore::create (results_columns);
4082 results_display.set_model (results_model);
4083 results_display.append_column (list_title, results_columns.visible_name);
4085 results_display.set_name ("CleanupResultsList");
4086 results_display.set_headers_visible (true);
4087 results_display.set_headers_clickable (false);
4088 results_display.set_reorderable (false);
4090 Gtk::ScrolledWindow list_scroller;
4093 Gtk::HBox dhbox; // the hbox for the image and text
4094 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4095 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4097 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4099 const string dead_directory = _session->session_directory().dead_path();
4102 %1 - number of files removed
4103 %2 - location of "dead"
4104 %3 - size of files affected
4105 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4108 const char* bprefix;
4109 double space_adjusted = 0;
4111 if (rep.space < 1000) {
4113 space_adjusted = rep.space;
4114 } else if (rep.space < 1000000) {
4115 bprefix = _("kilo");
4116 space_adjusted = floorf((float)rep.space / 1000.0);
4117 } else if (rep.space < 1000000 * 1000) {
4118 bprefix = _("mega");
4119 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4121 bprefix = _("giga");
4122 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4126 txt.set_markup (string_compose (P_("\
4127 The following file was deleted from %2,\n\
4128 releasing %3 %4bytes of disk space", "\
4129 The following %1 files were deleted from %2,\n\
4130 releasing %3 %4bytes of disk space", removed),
4131 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4133 txt.set_markup (string_compose (P_("\
4134 The following file was not in use and \n\
4135 has been moved to: %2\n\n\
4136 After a restart of %5\n\n\
4137 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4138 will release an additional %3 %4bytes of disk space.\n", "\
4139 The following %1 files were not in use and \n\
4140 have been moved to: %2\n\n\
4141 After a restart of %5\n\n\
4142 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4143 will release an additional %3 %4bytes of disk space.\n", removed),
4144 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4147 dhbox.pack_start (*dimage, true, false, 5);
4148 dhbox.pack_start (txt, true, false, 5);
4150 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4151 TreeModel::Row row = *(results_model->append());
4152 row[results_columns.visible_name] = *i;
4153 row[results_columns.fullpath] = *i;
4156 list_scroller.add (results_display);
4157 list_scroller.set_size_request (-1, 150);
4158 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4160 dvbox.pack_start (dhbox, true, false, 5);
4161 dvbox.pack_start (list_scroller, true, false, 5);
4162 ddhbox.pack_start (dvbox, true, false, 5);
4164 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4165 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4166 results.set_default_response (RESPONSE_CLOSE);
4167 results.set_position (Gtk::WIN_POS_MOUSE);
4169 results_display.show();
4170 list_scroller.show();
4177 //results.get_vbox()->show();
4178 results.set_resizable (false);
4185 ARDOUR_UI::cleanup ()
4187 if (_session == 0) {
4188 /* shouldn't happen: menu item is insensitive */
4193 MessageDialog checker (_("Are you sure you want to clean-up?"),
4195 Gtk::MESSAGE_QUESTION,
4198 checker.set_title (_("Clean-up"));
4200 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4201 ALL undo/redo information will be lost if you clean-up.\n\
4202 Clean-up will move all unused files to a \"dead\" location."));
4204 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4205 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4206 checker.set_default_response (RESPONSE_CANCEL);
4208 checker.set_name (_("CleanupDialog"));
4209 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4210 checker.set_position (Gtk::WIN_POS_MOUSE);
4212 switch (checker.run()) {
4213 case RESPONSE_ACCEPT:
4220 ARDOUR::CleanupReport rep;
4222 editor->prepare_for_cleanup ();
4224 /* do not allow flush until a session is reloaded */
4225 ActionManager::get_action (X_("Main"), X_("FlushWastebasket"))->set_sensitive (false);
4227 if (_session->cleanup_sources (rep)) {
4228 editor->finish_cleanup ();
4232 editor->finish_cleanup ();
4234 display_cleanup_results (rep, _("Cleaned Files"), false);
4238 ARDOUR_UI::flush_trash ()
4240 if (_session == 0) {
4241 /* shouldn't happen: menu item is insensitive */
4245 ARDOUR::CleanupReport rep;
4247 if (_session->cleanup_trash_sources (rep)) {
4251 display_cleanup_results (rep, _("deleted file"), true);
4255 ARDOUR_UI::cleanup_peakfiles ()
4257 if (_session == 0) {
4258 /* shouldn't happen: menu item is insensitive */
4262 if (! _session->can_cleanup_peakfiles ()) {
4266 // get all region-views in this session
4268 TrackViewList empty;
4270 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4271 std::list<RegionView*> views = rs.by_layer();
4273 // remove displayed audio-region-views waveforms
4274 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4275 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4276 if (!arv) { continue ; }
4277 arv->delete_waves();
4280 // cleanup peak files:
4281 // - stop pending peakfile threads
4282 // - close peakfiles if any
4283 // - remove peak dir in session
4284 // - setup peakfiles (background thread)
4285 _session->cleanup_peakfiles ();
4287 // re-add waves to ARV
4288 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4289 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4290 if (!arv) { continue ; }
4291 arv->create_waves();
4295 PresentationInfo::order_t
4296 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4298 if (editor->get_selection().tracks.empty()) {
4299 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4302 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4305 we want the new routes to have their order keys set starting from
4306 the highest order key in the selection + 1 (if available).
4309 if (place == RouteDialogs::AfterSelection) {
4310 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4312 order_hint = rtav->route()->presentation_info().order();
4315 } else if (place == RouteDialogs::BeforeSelection) {
4316 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4318 order_hint = rtav->route()->presentation_info().order();
4320 } else if (place == RouteDialogs::First) {
4323 /* leave order_hint at max_order */
4330 ARDOUR_UI::start_duplicate_routes ()
4332 if (!duplicate_routes_dialog) {
4333 duplicate_routes_dialog = new DuplicateRouteDialog;
4336 if (duplicate_routes_dialog->restart (_session)) {
4340 duplicate_routes_dialog->present ();
4344 ARDOUR_UI::add_route ()
4346 if (!add_route_dialog.get (false)) {
4347 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4354 if (add_route_dialog->is_visible()) {
4355 /* we're already doing this */
4359 add_route_dialog->set_position (WIN_POS_MOUSE);
4360 add_route_dialog->present();
4364 ARDOUR_UI::add_route_dialog_response (int r)
4367 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4371 if (!AudioEngine::instance()->running ()) {
4373 case AddRouteDialog::Add:
4374 case AddRouteDialog::AddAndClose:
4379 add_route_dialog->ArdourDialog::on_response (r);
4380 ARDOUR_UI_UTILS::engine_is_running ();
4387 case AddRouteDialog::Add:
4388 add_route_dialog->reset_name_edited ();
4390 case AddRouteDialog::AddAndClose:
4391 add_route_dialog->ArdourDialog::on_response (r);
4394 add_route_dialog->ArdourDialog::on_response (r);
4398 std::string template_path = add_route_dialog->get_template_path();
4399 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4400 meta_route_setup (template_path.substr (11));
4404 if ((count = add_route_dialog->count()) <= 0) {
4408 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4409 const string name_template = add_route_dialog->name_template ();
4410 DisplaySuspender ds;
4412 if (!template_path.empty ()) {
4413 if (add_route_dialog->name_template_is_default ()) {
4414 _session->new_route_from_template (count, order, template_path, string ());
4416 _session->new_route_from_template (count, order, template_path, name_template);
4421 ChanCount input_chan= add_route_dialog->channels ();
4422 ChanCount output_chan;
4423 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4424 RouteGroup* route_group = add_route_dialog->route_group ();
4425 AutoConnectOption oac = Config->get_output_auto_connect();
4426 bool strict_io = add_route_dialog->use_strict_io ();
4428 if (oac & AutoConnectMaster) {
4429 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4430 output_chan.set (DataType::MIDI, 0);
4432 output_chan = input_chan;
4435 /* XXX do something with name template */
4437 Session::ProcessorChangeBlocker pcb (_session);
4439 switch (add_route_dialog->type_wanted()) {
4440 case AddRouteDialog::AudioTrack:
4441 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);
4443 case AddRouteDialog::MidiTrack:
4444 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4446 case AddRouteDialog::MixedTrack:
4447 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4449 case AddRouteDialog::AudioBus:
4450 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4452 case AddRouteDialog::MidiBus:
4453 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4455 case AddRouteDialog::VCAMaster:
4456 _session->vca_manager().create_vca (count, name_template);
4458 case AddRouteDialog::FoldbackBus:
4459 session_add_foldback_bus (count, name_template);
4465 ARDOUR_UI::stop_video_server (bool ask_confirm)
4467 if (!video_server_process && ask_confirm) {
4468 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4470 if (video_server_process) {
4472 ArdourDialog confirm (_("Stop Video-Server"), true);
4473 Label m (_("Do you really want to stop the Video Server?"));
4474 confirm.get_vbox()->pack_start (m, true, true);
4475 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4476 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4477 confirm.show_all ();
4478 if (confirm.run() == RESPONSE_CANCEL) {
4482 delete video_server_process;
4483 video_server_process =0;
4488 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4490 ARDOUR_UI::start_video_server( float_window, true);
4494 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4500 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4501 if (video_server_process) {
4502 popup_error(_("The Video Server is already started."));
4504 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4510 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4512 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4514 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4516 video_server_dialog->set_transient_for (*float_window);
4519 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4520 video_server_dialog->hide();
4522 ResponseType r = (ResponseType) video_server_dialog->run ();
4523 video_server_dialog->hide();
4524 if (r != RESPONSE_ACCEPT) { return false; }
4525 if (video_server_dialog->show_again()) {
4526 Config->set_show_video_server_dialog(false);
4530 std::string icsd_exec = video_server_dialog->get_exec_path();
4531 std::string icsd_docroot = video_server_dialog->get_docroot();
4532 #ifndef PLATFORM_WINDOWS
4533 if (icsd_docroot.empty()) {
4534 icsd_docroot = VideoUtils::video_get_docroot (Config);
4539 #ifdef PLATFORM_WINDOWS
4540 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4541 /* OK, allow all drive letters */
4544 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4545 warning << _("Specified docroot is not an existing directory.") << endmsg;
4548 #ifndef PLATFORM_WINDOWS
4549 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4550 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4551 warning << _("Given Video Server is not an executable file.") << endmsg;
4555 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4556 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4557 warning << _("Given Video Server is not an executable file.") << endmsg;
4563 argp=(char**) calloc(9,sizeof(char*));
4564 argp[0] = strdup(icsd_exec.c_str());
4565 argp[1] = strdup("-P");
4566 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4567 argp[3] = strdup("-p");
4568 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4569 argp[5] = strdup("-C");
4570 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4571 argp[7] = strdup(icsd_docroot.c_str());
4573 stop_video_server();
4575 #ifdef PLATFORM_WINDOWS
4576 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4577 /* OK, allow all drive letters */
4580 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4581 Config->set_video_advanced_setup(false);
4583 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4584 Config->set_video_server_url(url_str);
4585 Config->set_video_server_docroot(icsd_docroot);
4586 Config->set_video_advanced_setup(true);
4589 if (video_server_process) {
4590 delete video_server_process;
4593 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4594 if (video_server_process->start()) {
4595 warning << _("Cannot launch the video-server") << endmsg;
4598 int timeout = 120; // 6 sec
4599 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4600 Glib::usleep (50000);
4602 if (--timeout <= 0 || !video_server_process->is_running()) break;
4605 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4607 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4608 delete video_server_process;
4609 video_server_process = 0;
4617 ARDOUR_UI::add_video (Gtk::Window* float_window)
4623 if (!start_video_server(float_window, false)) {
4624 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4629 add_video_dialog->set_transient_for (*float_window);
4632 if (add_video_dialog->is_visible()) {
4633 /* we're already doing this */
4637 ResponseType r = (ResponseType) add_video_dialog->run ();
4638 add_video_dialog->hide();
4639 if (r != RESPONSE_ACCEPT) { return; }
4641 bool local_file, orig_local_file;
4642 std::string path = add_video_dialog->file_name(local_file);
4644 std::string orig_path = path;
4645 orig_local_file = local_file;
4647 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4649 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4650 warning << string_compose(_("could not open %1"), path) << endmsg;
4653 if (!local_file && path.length() == 0) {
4654 warning << _("no video-file selected") << endmsg;
4658 std::string audio_from_video;
4659 bool detect_ltc = false;
4661 switch (add_video_dialog->import_option()) {
4662 case VTL_IMPORT_TRANSCODE:
4664 TranscodeVideoDialog *transcode_video_dialog;
4665 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4666 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4667 transcode_video_dialog->hide();
4668 if (r != RESPONSE_ACCEPT) {
4669 delete transcode_video_dialog;
4673 audio_from_video = transcode_video_dialog->get_audiofile();
4675 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4678 else if (!audio_from_video.empty()) {
4679 editor->embed_audio_from_video(
4681 video_timeline->get_offset(),
4682 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4685 switch (transcode_video_dialog->import_option()) {
4686 case VTL_IMPORT_TRANSCODED:
4687 path = transcode_video_dialog->get_filename();
4690 case VTL_IMPORT_REFERENCE:
4693 delete transcode_video_dialog;
4696 delete transcode_video_dialog;
4700 case VTL_IMPORT_NONE:
4704 /* strip _session->session_directory().video_path() from video file if possible */
4705 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4706 path=path.substr(_session->session_directory().video_path().size());
4707 if (path.at(0) == G_DIR_SEPARATOR) {
4708 path=path.substr(1);
4712 video_timeline->set_update_session_fps(auto_set_session_fps);
4714 if (video_timeline->video_file_info(path, local_file)) {
4715 XMLNode* node = new XMLNode(X_("Videotimeline"));
4716 node->set_property (X_("Filename"), path);
4717 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4718 node->set_property (X_("LocalFile"), local_file);
4719 if (orig_local_file) {
4720 node->set_property (X_("OriginalVideoFile"), orig_path);
4722 node->remove_property (X_("OriginalVideoFile"));
4724 _session->add_extra_xml (*node);
4725 _session->set_dirty ();
4727 if (!audio_from_video.empty() && detect_ltc) {
4728 std::vector<LTCFileReader::LTCMap> ltc_seq;
4731 /* TODO ask user about TV standard (LTC alignment if any) */
4732 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4733 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4735 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4737 /* TODO seek near end of file, and read LTC until end.
4738 * if it fails to find any LTC samples, scan complete file
4740 * calculate drift of LTC compared to video-duration,
4741 * ask user for reference (timecode from start/mid/end)
4744 // LTCFileReader will have written error messages
4747 ::g_unlink(audio_from_video.c_str());
4749 if (ltc_seq.size() == 0) {
4750 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4752 /* the very first TC in the file is somteimes not aligned properly */
4753 int i = ltc_seq.size() -1;
4754 ARDOUR::sampleoffset_t video_start_offset =
4755 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4756 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4757 video_timeline->set_offset(video_start_offset);
4761 _session->maybe_update_session_range(
4762 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4763 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4766 if (add_video_dialog->launch_xjadeo() && local_file) {
4767 editor->set_xjadeo_sensitive(true);
4768 editor->toggle_xjadeo_proc(1);
4770 editor->toggle_xjadeo_proc(0);
4772 editor->toggle_ruler_video(true);
4777 ARDOUR_UI::remove_video ()
4779 video_timeline->close_session();
4780 editor->toggle_ruler_video(false);
4783 video_timeline->set_offset_locked(false);
4784 video_timeline->set_offset(0);
4786 /* delete session state */
4787 XMLNode* node = new XMLNode(X_("Videotimeline"));
4788 _session->add_extra_xml(*node);
4789 node = new XMLNode(X_("Videomonitor"));
4790 _session->add_extra_xml(*node);
4791 node = new XMLNode(X_("Videoexport"));
4792 _session->add_extra_xml(*node);
4793 stop_video_server();
4797 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4799 if (localcacheonly) {
4800 video_timeline->vmon_update();
4802 video_timeline->flush_cache();
4804 editor->queue_visual_videotimeline_update();
4808 ARDOUR_UI::export_video (bool range)
4810 if (ARDOUR::Config->get_show_video_export_info()) {
4811 ExportVideoInfobox infobox (_session);
4812 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4813 if (infobox.show_again()) {
4814 ARDOUR::Config->set_show_video_export_info(false);
4817 case GTK_RESPONSE_YES:
4818 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4824 export_video_dialog->set_session (_session);
4825 export_video_dialog->apply_state(editor->get_selection().time, range);
4826 export_video_dialog->run ();
4827 export_video_dialog->hide ();
4831 ARDOUR_UI::preferences_settings () const
4836 node = _session->instant_xml(X_("Preferences"));
4838 node = Config->instant_xml(X_("Preferences"));
4842 node = new XMLNode (X_("Preferences"));
4849 ARDOUR_UI::mixer_settings () const
4854 node = _session->instant_xml(X_("Mixer"));
4856 node = Config->instant_xml(X_("Mixer"));
4860 node = new XMLNode (X_("Mixer"));
4867 ARDOUR_UI::main_window_settings () const
4872 node = _session->instant_xml(X_("Main"));
4874 node = Config->instant_xml(X_("Main"));
4878 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4879 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4884 node = new XMLNode (X_("Main"));
4891 ARDOUR_UI::editor_settings () const
4896 node = _session->instant_xml(X_("Editor"));
4898 node = Config->instant_xml(X_("Editor"));
4902 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4903 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4908 node = new XMLNode (X_("Editor"));
4915 ARDOUR_UI::keyboard_settings () const
4919 node = Config->extra_xml(X_("Keyboard"));
4922 node = new XMLNode (X_("Keyboard"));
4929 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4932 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4933 _session->locations()->add (location);
4938 ARDOUR_UI::halt_on_xrun_message ()
4940 cerr << "HALT on xrun\n";
4941 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4946 ARDOUR_UI::xrun_handler (samplepos_t where)
4952 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4954 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4955 create_xrun_marker(where);
4958 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4959 halt_on_xrun_message ();
4964 ARDOUR_UI::disk_overrun_handler ()
4966 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4968 if (!have_disk_speed_dialog_displayed) {
4969 have_disk_speed_dialog_displayed = true;
4970 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4971 The disk system on your computer\n\
4972 was not able to keep up with %1.\n\
4974 Specifically, it failed to write data to disk\n\
4975 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4976 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4982 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4983 static MessageDialog *scan_dlg = NULL;
4984 static ProgressBar *scan_pbar = NULL;
4985 static HBox *scan_tbox = NULL;
4986 static Gtk::Button *scan_timeout_button;
4989 ARDOUR_UI::cancel_plugin_scan ()
4991 PluginManager::instance().cancel_plugin_scan();
4995 ARDOUR_UI::cancel_plugin_timeout ()
4997 PluginManager::instance().cancel_plugin_timeout();
4998 scan_timeout_button->set_sensitive (false);
5002 ARDOUR_UI::plugin_scan_timeout (int timeout)
5004 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5008 scan_pbar->set_sensitive (false);
5009 scan_timeout_button->set_sensitive (true);
5010 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5013 scan_pbar->set_sensitive (false);
5014 scan_timeout_button->set_sensitive (false);
5020 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5022 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5026 const bool cancelled = PluginManager::instance().cancelled();
5027 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5028 if (cancelled && scan_dlg->is_mapped()) {
5033 if (cancelled || !can_cancel) {
5038 static Gtk::Button *cancel_button;
5040 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5041 VBox* vbox = scan_dlg->get_vbox();
5042 vbox->set_size_request(400,-1);
5043 scan_dlg->set_title (_("Scanning for plugins"));
5045 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5046 cancel_button->set_name ("EditorGTKButton");
5047 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5048 cancel_button->show();
5050 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5052 scan_tbox = manage( new HBox() );
5054 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5055 scan_timeout_button->set_name ("EditorGTKButton");
5056 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5057 scan_timeout_button->show();
5059 scan_pbar = manage(new ProgressBar());
5060 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5061 scan_pbar->set_text(_("Scan Timeout"));
5064 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5065 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5067 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5070 assert(scan_dlg && scan_tbox && cancel_button);
5072 if (type == X_("closeme")) {
5076 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5079 if (!can_cancel || !cancelled) {
5080 scan_timeout_button->set_sensitive(false);
5082 cancel_button->set_sensitive(can_cancel && !cancelled);
5088 ARDOUR_UI::gui_idle_handler ()
5091 /* due to idle calls, gtk_events_pending() may always return true */
5092 while (gtk_events_pending() && --timeout) {
5093 gtk_main_iteration ();
5098 ARDOUR_UI::disk_underrun_handler ()
5100 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5102 if (!have_disk_speed_dialog_displayed) {
5103 have_disk_speed_dialog_displayed = true;
5104 MessageDialog* msg = new MessageDialog (
5105 _main_window, string_compose (_("The disk system on your computer\n\
5106 was not able to keep up with %1.\n\
5108 Specifically, it failed to read data from disk\n\
5109 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5110 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5116 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5118 have_disk_speed_dialog_displayed = false;
5123 ARDOUR_UI::session_dialog (std::string msg)
5125 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5129 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5136 ARDOUR_UI::pending_state_dialog ()
5138 HBox* hbox = manage (new HBox());
5139 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5140 ArdourDialog dialog (_("Crash Recovery"), true);
5141 Label message (string_compose (_("\
5142 This session appears to have been in the\n\
5143 middle of recording when %1 or\n\
5144 the computer was shutdown.\n\
5146 %1 can recover any captured audio for\n\
5147 you, or it can ignore it. Please decide\n\
5148 what you would like to do.\n"), PROGRAM_NAME));
5149 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5150 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5151 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5152 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5153 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5154 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5155 dialog.set_default_response (RESPONSE_ACCEPT);
5156 dialog.set_position (WIN_POS_CENTER);
5161 switch (dialog.run ()) {
5162 case RESPONSE_ACCEPT:
5170 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5172 HBox* hbox = new HBox();
5173 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5174 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5175 Label message (string_compose (_("\
5176 This session was created with a sample rate of %1 Hz, but\n\
5177 %2 is currently running at %3 Hz. If you load this session,\n\
5178 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5180 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5181 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5182 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5183 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5184 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5185 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5186 dialog.set_default_response (RESPONSE_ACCEPT);
5187 dialog.set_position (WIN_POS_CENTER);
5192 switch (dialog.run()) {
5193 case RESPONSE_ACCEPT:
5203 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5205 MessageDialog msg (string_compose (_("\
5206 This session was created with a sample rate of %1 Hz, but\n\
5207 %2 is currently running at %3 Hz.\n\
5208 Audio will be recorded and played at the wrong sample rate.\n\
5209 Re-Configure the Audio Engine in\n\
5210 Menu > Window > Audio/Midi Setup"),
5211 desired, PROGRAM_NAME, actual),
5213 Gtk::MESSAGE_WARNING);
5218 ARDOUR_UI::use_config ()
5220 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5222 set_transport_controllable_state (*node);
5227 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5229 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5231 primary_clock->set (pos);
5233 case DeltaEditPoint:
5234 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5236 case DeltaOriginMarker:
5238 Location* loc = _session->locations()->clock_origin_location ();
5239 primary_clock->set (pos, false, loc ? loc->start() : 0);
5244 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5246 secondary_clock->set (pos);
5248 case DeltaEditPoint:
5249 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5251 case DeltaOriginMarker:
5253 Location* loc = _session->locations()->clock_origin_location ();
5254 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5259 if (big_clock_window) {
5260 big_clock->set (pos);
5262 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5267 ARDOUR_UI::record_state_changed ()
5269 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5272 /* why bother - the clock isn't visible */
5276 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5278 if (big_clock_window) {
5279 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5280 big_clock->set_active (true);
5282 big_clock->set_active (false);
5289 ARDOUR_UI::first_idle ()
5292 _session->allow_auto_play (true);
5296 editor->first_idle();
5299 /* in 1 second, hide the splash screen
5301 * Consider hiding it *now*. If a user opens opens a dialog
5302 * during that one second while the splash is still visible,
5303 * the dialog will push-back the splash.
5304 * Closing the dialog later will pop it back.
5306 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5308 Keyboard::set_can_save_keybindings (true);
5313 ARDOUR_UI::store_clock_modes ()
5315 XMLNode* node = new XMLNode(X_("ClockModes"));
5317 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5318 XMLNode* child = new XMLNode (X_("Clock"));
5320 child->set_property (X_("name"), (*x)->name());
5321 child->set_property (X_("mode"), (*x)->mode());
5322 child->set_property (X_("on"), (*x)->on());
5324 node->add_child_nocopy (*child);
5327 _session->add_extra_xml (*node);
5328 _session->set_dirty ();
5332 ARDOUR_UI::setup_profile ()
5334 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5335 Profile->set_small_screen ();
5338 if (g_getenv ("TRX")) {
5339 Profile->set_trx ();
5342 if (g_getenv ("MIXBUS")) {
5343 Profile->set_mixbus ();
5348 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5350 MissingFileDialog dialog (s, str, type);
5355 int result = dialog.run ();
5362 return 1; // quit entire session load
5365 result = dialog.get_action ();
5371 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5373 AmbiguousFileDialog dialog (file, hits);
5380 return dialog.get_which ();
5383 /** Allocate our thread-local buffers */
5385 ARDOUR_UI::get_process_buffers ()
5387 _process_thread->get_buffers ();
5390 /** Drop our thread-local buffers */
5392 ARDOUR_UI::drop_process_buffers ()
5394 _process_thread->drop_buffers ();
5398 ARDOUR_UI::feedback_detected ()
5400 _feedback_exists = true;
5404 ARDOUR_UI::successful_graph_sort ()
5406 _feedback_exists = false;
5410 ARDOUR_UI::midi_panic ()
5413 _session->midi_panic();
5418 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5420 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5421 const char* end_big = "</span>";
5422 const char* start_mono = "<tt>";
5423 const char* end_mono = "</tt>";
5425 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5426 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5427 "From now on, use the backup copy with older versions of %3"),
5428 xml_path, backup_path, PROGRAM_NAME,
5430 start_mono, end_mono), true);
5436 ARDOUR_UI::reset_peak_display ()
5438 if (!_session || !_session->master_out() || !editor_meter) return;
5439 editor_meter->clear_meters();
5440 editor_meter_max_peak = -INFINITY;
5441 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5445 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5447 if (!_session || !_session->master_out()) return;
5448 if (group == _session->master_out()->route_group()) {
5449 reset_peak_display ();
5454 ARDOUR_UI::reset_route_peak_display (Route* route)
5456 if (!_session || !_session->master_out()) return;
5457 if (_session->master_out().get() == route) {
5458 reset_peak_display ();
5463 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5465 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5466 audio_midi_setup->set_position (WIN_POS_CENTER);
5468 if (desired_sample_rate != 0) {
5469 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5470 audio_midi_setup->try_autostart ();
5471 if (ARDOUR::AudioEngine::instance()->running()) {
5478 int response = audio_midi_setup->run();
5480 case Gtk::RESPONSE_DELETE_EVENT:
5481 // after latency callibration engine may run,
5482 // Running() signal was emitted, but dialog will not
5483 // have emitted a response. The user needs to close
5484 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5485 if (!AudioEngine::instance()->running()) {
5490 if (!AudioEngine::instance()->running()) {
5493 audio_midi_setup->hide ();
5501 ARDOUR_UI::transport_numpad_timeout ()
5503 _numpad_locate_happening = false;
5504 if (_numpad_timeout_connection.connected() )
5505 _numpad_timeout_connection.disconnect();
5510 ARDOUR_UI::transport_numpad_decimal ()
5512 _numpad_timeout_connection.disconnect();
5514 if (_numpad_locate_happening) {
5515 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5516 _numpad_locate_happening = false;
5518 _pending_locate_num = 0;
5519 _numpad_locate_happening = true;
5520 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5525 ARDOUR_UI::transport_numpad_event (int num)
5527 if ( _numpad_locate_happening ) {
5528 _pending_locate_num = _pending_locate_num*10 + num;
5531 case 0: toggle_roll(false, false); break;
5532 case 1: transport_rewind(1); break;
5533 case 2: transport_forward(1); break;
5534 case 3: transport_record(true); break;
5535 case 4: toggle_session_auto_loop(); break;
5536 case 5: transport_record(false); toggle_session_auto_loop(); break;
5537 case 6: toggle_punch(); break;
5538 case 7: toggle_click(); break;
5539 case 8: toggle_auto_return(); break;
5540 case 9: toggle_follow_edits(); break;
5546 ARDOUR_UI::set_flat_buttons ()
5548 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5552 ARDOUR_UI::audioengine_became_silent ()
5554 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5556 Gtk::MESSAGE_WARNING,
5560 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5562 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5563 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5564 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5565 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5566 Gtk::HBox pay_button_box;
5567 Gtk::HBox subscribe_button_box;
5569 pay_button_box.pack_start (pay_button, true, false);
5570 subscribe_button_box.pack_start (subscribe_button, true, false);
5572 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 */
5574 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5575 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5577 msg.get_vbox()->pack_start (pay_label);
5578 msg.get_vbox()->pack_start (pay_button_box);
5579 msg.get_vbox()->pack_start (subscribe_label);
5580 msg.get_vbox()->pack_start (subscribe_button_box);
5582 msg.get_vbox()->show_all ();
5584 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5585 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5586 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5591 case Gtk::RESPONSE_YES:
5592 AudioEngine::instance()->reset_silence_countdown ();
5595 case Gtk::RESPONSE_NO:
5597 save_state_canfail ("");
5598 exit (EXIT_SUCCESS);
5601 case Gtk::RESPONSE_CANCEL:
5603 /* don't reset, save session and exit */
5609 ARDOUR_UI::hide_application ()
5611 Application::instance ()-> hide ();
5615 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5617 /* icons, titles, WM stuff */
5619 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5621 if (window_icons.empty()) {
5622 Glib::RefPtr<Gdk::Pixbuf> icon;
5623 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5624 window_icons.push_back (icon);
5626 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5627 window_icons.push_back (icon);
5629 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5630 window_icons.push_back (icon);
5632 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5633 window_icons.push_back (icon);
5637 if (!window_icons.empty()) {
5638 window.set_default_icon_list (window_icons);
5641 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5643 if (!name.empty()) {
5647 window.set_title (title.get_string());
5648 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5650 window.set_flags (CAN_FOCUS);
5651 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5653 /* This is a hack to ensure that GTK-accelerators continue to
5654 * work. Once we switch over to entirely native bindings, this will be
5655 * unnecessary and should be removed
5657 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5659 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5660 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5661 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5662 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5666 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5668 Gtkmm2ext::Bindings* bindings = 0;
5669 Gtk::Window* window = 0;
5671 /* until we get ardour bindings working, we are not handling key
5675 if (ev->type != GDK_KEY_PRESS) {
5679 if (event_window == &_main_window) {
5681 window = event_window;
5683 /* find current tab contents */
5685 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5687 /* see if it uses the ardour binding system */
5690 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5693 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5697 window = event_window;
5699 /* see if window uses ardour binding system */
5701 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5704 /* An empty binding set is treated as if it doesn't exist */
5706 if (bindings && bindings->empty()) {
5710 return key_press_focus_accelerator_handler (*window, ev, bindings);
5713 static Gtkmm2ext::Bindings*
5714 get_bindings_from_widget_heirarchy (GtkWidget** w)
5719 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5722 *w = gtk_widget_get_parent (*w);
5725 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5729 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5731 GtkWindow* win = window.gobj();
5732 GtkWidget* focus = gtk_window_get_focus (win);
5733 GtkWidget* binding_widget = focus;
5734 bool special_handling_of_unmodified_accelerators = false;
5735 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5739 /* some widget has keyboard focus */
5741 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5743 /* A particular kind of focusable widget currently has keyboard
5744 * focus. All unmodified key events should go to that widget
5745 * first and not be used as an accelerator by default
5748 special_handling_of_unmodified_accelerators = true;
5752 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5753 if (focus_bindings) {
5754 bindings = focus_bindings;
5755 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5760 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",
5763 Gtkmm2ext::show_gdk_event_state (ev->state),
5764 special_handling_of_unmodified_accelerators,
5765 Keyboard::some_magic_widget_has_focus(),
5767 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5768 ((ev->state & mask) ? "yes" : "no"),
5769 window.get_title()));
5771 /* This exists to allow us to override the way GTK handles
5772 key events. The normal sequence is:
5774 a) event is delivered to a GtkWindow
5775 b) accelerators/mnemonics are activated
5776 c) if (b) didn't handle the event, propagate to
5777 the focus widget and/or focus chain
5779 The problem with this is that if the accelerators include
5780 keys without modifiers, such as the space bar or the
5781 letter "e", then pressing the key while typing into
5782 a text entry widget results in the accelerator being
5783 activated, instead of the desired letter appearing
5786 There is no good way of fixing this, but this
5787 represents a compromise. The idea is that
5788 key events involving modifiers (not Shift)
5789 get routed into the activation pathway first, then
5790 get propagated to the focus widget if necessary.
5792 If the key event doesn't involve modifiers,
5793 we deliver to the focus widget first, thus allowing
5794 it to get "normal text" without interference
5797 Of course, this can also be problematic: if there
5798 is a widget with focus, then it will swallow
5799 all "normal text" accelerators.
5803 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5805 /* no special handling or there are modifiers in effect: accelerate first */
5807 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5808 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5809 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5811 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5812 KeyboardKey k (ev->state, ev->keyval);
5816 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5818 if (bindings->activate (k, Bindings::Press)) {
5819 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5823 if (binding_widget) {
5824 binding_widget = gtk_widget_get_parent (binding_widget);
5825 if (binding_widget) {
5826 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5835 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5837 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5838 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5842 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5844 if (gtk_window_propagate_key_event (win, ev)) {
5845 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5851 /* no modifiers, propagate first */
5853 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5855 if (gtk_window_propagate_key_event (win, ev)) {
5856 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5860 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5861 KeyboardKey k (ev->state, ev->keyval);
5865 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5868 if (bindings->activate (k, Bindings::Press)) {
5869 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5873 if (binding_widget) {
5874 binding_widget = gtk_widget_get_parent (binding_widget);
5875 if (binding_widget) {
5876 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5885 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5887 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5888 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5893 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5898 ARDOUR_UI::cancel_solo ()
5901 _session->cancel_all_solo ();
5906 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5908 /* this resets focus to the first focusable parent of the given widget,
5909 * or, if there is no focusable parent, cancels focus in the toplevel
5910 * window that the given widget is packed into (if there is one).
5917 Gtk::Widget* top = w->get_toplevel();
5919 if (!top || !top->is_toplevel()) {
5923 w = w->get_parent ();
5927 if (w->is_toplevel()) {
5928 /* Setting the focus widget to a Gtk::Window causes all
5929 * subsequent calls to ::has_focus() on the nominal
5930 * focus widget in that window to return
5931 * false. Workaround: never set focus to the toplevel
5937 if (w->get_can_focus ()) {
5938 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5939 win->set_focus (*w);
5942 w = w->get_parent ();
5945 if (top == &_main_window) {
5949 /* no focusable parent found, cancel focus in top level window.
5950 C++ API cannot be used for this. Thanks, references.
5953 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
5958 ARDOUR_UI::monitor_dim_all ()
5960 boost::shared_ptr<Route> mon = _session->monitor_out ();
5964 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5966 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
5967 _monitor->set_dim_all (tact->get_active());
5971 ARDOUR_UI::monitor_cut_all ()
5973 boost::shared_ptr<Route> mon = _session->monitor_out ();
5977 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5979 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
5980 _monitor->set_cut_all (tact->get_active());
5984 ARDOUR_UI::monitor_mono ()
5986 boost::shared_ptr<Route> mon = _session->monitor_out ();
5990 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5992 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
5993 _monitor->set_mono (tact->get_active());
5997 ARDOUR_UI::shared_popup_menu ()
5999 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::shared_popup_menu, ignored);
6001 assert (!_shared_popup_menu || !_shared_popup_menu->is_visible());
6002 delete _shared_popup_menu;
6003 _shared_popup_menu = new Gtk::Menu;
6004 return _shared_popup_menu;