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 (session_name.empty()) {
3347 /* need the dialog to get the name (at least) from the user */
3348 switch (session_dialog.run()) {
3349 case RESPONSE_ACCEPT:
3352 /* this is used for async * app->ShouldLoad(). */
3353 continue; // while loop
3356 if (quit_on_cancel) {
3357 ARDOUR_UI::finish ();
3358 Gtkmm2ext::Application::instance()->cleanup();
3360 pthread_cancel_all ();
3361 return -1; // caller is responsible to call exit()
3367 session_dialog.hide ();
3370 /* if we run the startup dialog again, offer more than just "new session" */
3372 should_be_new = false;
3374 session_name = session_dialog.session_name (likely_new);
3375 session_path = session_dialog.session_folder ();
3382 int rv = ARDOUR::inflate_session (session_name,
3383 Config->get_default_session_parent_dir(), session_path, session_name);
3385 MessageDialog msg (session_dialog,
3386 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3391 session_dialog.set_provided_session (session_name, session_path);
3395 // XXX check archive, inflate
3396 string::size_type suffix = session_name.find (statefile_suffix);
3398 if (suffix != string::npos) {
3399 session_name = session_name.substr (0, suffix);
3402 /* this shouldn't happen, but we catch it just in case it does */
3404 if (session_name.empty()) {
3408 if (session_dialog.use_session_template()) {
3409 template_name = session_dialog.session_template_name();
3410 _session_is_new = true;
3413 if (session_name[0] == G_DIR_SEPARATOR ||
3414 #ifdef PLATFORM_WINDOWS
3415 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3417 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3418 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3423 /* absolute path or cwd-relative path specified for session name: infer session folder
3424 from what was given.
3427 session_path = Glib::path_get_dirname (session_name);
3428 session_name = Glib::path_get_basename (session_name);
3432 session_path = session_dialog.session_folder();
3434 char illegal = Session::session_name_is_legal (session_name);
3437 MessageDialog msg (session_dialog,
3438 string_compose (_("To ensure compatibility with various systems\n"
3439 "session names may not contain a '%1' character"),
3442 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3447 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3450 if (likely_new && !nsm) {
3452 std::string existing = Glib::build_filename (session_path, session_name);
3454 if (!ask_about_loading_existing_session (existing)) {
3455 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3460 _session_is_new = false;
3465 pop_back_splash (session_dialog);
3466 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3468 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3472 char illegal = Session::session_name_is_legal(session_name);
3475 pop_back_splash (session_dialog);
3476 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3477 "session names may not contain a '%1' character"), illegal));
3479 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3483 _session_is_new = true;
3486 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3488 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3489 meta_session_setup (template_name.substr (11));
3491 } else if (likely_new && template_name.empty()) {
3493 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3497 ret = load_session (session_path, session_name, template_name);
3500 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3501 exit (EXIT_FAILURE);
3504 /* clear this to avoid endless attempts to load the
3508 ARDOUR_COMMAND_LINE::session_name = "";
3512 _session_dialog = NULL;
3518 ARDOUR_UI::close_session()
3520 if (!check_audioengine (_main_window)) {
3524 if (unload_session (true)) {
3528 ARDOUR_COMMAND_LINE::session_name = "";
3530 if (get_session_parameters (true, false)) {
3531 exit (EXIT_FAILURE);
3535 /** @param snap_name Snapshot name (without .ardour suffix).
3536 * @return -2 if the load failed because we are not connected to the AudioEngine.
3539 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3541 /* load_session calls flush_pending() which allows
3542 * GUI interaction and potentially loading another session
3543 * (that was easy via snapshot sidebar).
3544 * Recursing into load_session() from load_session() and recusive
3545 * event loops causes all kind of crashes.
3547 assert (!session_load_in_progress);
3548 if (session_load_in_progress) {
3551 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3553 Session *new_session;
3558 unload_status = unload_session ();
3560 if (unload_status < 0) {
3562 } else if (unload_status > 0) {
3568 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3571 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3574 /* this one is special */
3576 catch (AudioEngine::PortRegistrationFailure const& err) {
3578 MessageDialog msg (err.what(),
3581 Gtk::BUTTONS_CLOSE);
3583 msg.set_title (_("Port Registration Error"));
3584 msg.set_secondary_text (_("Click the Close button to try again."));
3585 msg.set_position (Gtk::WIN_POS_CENTER);
3586 pop_back_splash (msg);
3589 int response = msg.run ();
3594 case RESPONSE_CANCEL:
3595 exit (EXIT_FAILURE);
3601 catch (SessionException const& e) {
3602 MessageDialog msg (string_compose(
3603 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3604 path, snap_name, e.what()),
3609 msg.set_title (_("Loading Error"));
3610 msg.set_position (Gtk::WIN_POS_CENTER);
3611 pop_back_splash (msg);
3623 MessageDialog msg (string_compose(
3624 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3630 msg.set_title (_("Loading Error"));
3631 msg.set_position (Gtk::WIN_POS_CENTER);
3632 pop_back_splash (msg);
3644 list<string> const u = new_session->unknown_processors ();
3646 MissingPluginDialog d (_session, u);
3651 if (!new_session->writable()) {
3652 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3657 msg.set_title (_("Read-only Session"));
3658 msg.set_position (Gtk::WIN_POS_CENTER);
3659 pop_back_splash (msg);
3666 /* Now the session been created, add the transport controls */
3667 new_session->add_controllable(roll_controllable);
3668 new_session->add_controllable(stop_controllable);
3669 new_session->add_controllable(goto_start_controllable);
3670 new_session->add_controllable(goto_end_controllable);
3671 new_session->add_controllable(auto_loop_controllable);
3672 new_session->add_controllable(play_selection_controllable);
3673 new_session->add_controllable(rec_controllable);
3675 set_session (new_session);
3678 _session->set_clean ();
3681 #ifdef WINDOWS_VST_SUPPORT
3682 fst_stop_threading();
3686 Timers::TimerSuspender t;
3690 #ifdef WINDOWS_VST_SUPPORT
3691 fst_start_threading();
3695 if (!mix_template.empty ()) {
3696 /* if mix_template is given, assume this is a new session */
3697 string metascript = Glib::build_filename (mix_template, "template.lua");
3698 meta_session_setup (metascript);
3703 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3704 * which is queued by set_session().
3705 * If session-loading fails we hide it explicitly.
3706 * This covers both cases in a central place.
3715 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3717 Session *new_session;
3720 x = unload_session ();
3728 _session_is_new = true;
3731 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3734 catch (SessionException const& e) {
3735 cerr << "Here are the errors associated with this failed session:\n";
3737 cerr << "---------\n";
3738 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3739 msg.set_title (_("Loading Error"));
3740 msg.set_position (Gtk::WIN_POS_CENTER);
3741 pop_back_splash (msg);
3746 cerr << "Here are the errors associated with this failed session:\n";
3748 cerr << "---------\n";
3749 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3750 msg.set_title (_("Loading Error"));
3751 msg.set_position (Gtk::WIN_POS_CENTER);
3752 pop_back_splash (msg);
3757 /* Give the new session the default GUI state, if such things exist */
3760 n = Config->instant_xml (X_("Editor"));
3762 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3763 new_session->add_instant_xml (*n, false);
3765 n = Config->instant_xml (X_("Mixer"));
3767 new_session->add_instant_xml (*n, false);
3770 n = Config->instant_xml (X_("Preferences"));
3772 new_session->add_instant_xml (*n, false);
3775 /* Put the playhead at 0 and scroll fully left */
3776 n = new_session->instant_xml (X_("Editor"));
3778 n->set_property (X_("playhead"), X_("0"));
3779 n->set_property (X_("left-frame"), X_("0"));
3782 set_session (new_session);
3784 new_session->save_state(new_session->name());
3790 static void _lua_print (std::string s) {
3792 std::cout << "LuaInstance: " << s << "\n";
3794 PBD::info << "LuaInstance: " << s << endmsg;
3797 std::map<std::string, std::string>
3798 ARDOUR_UI::route_setup_info (const std::string& script_path)
3800 std::map<std::string, std::string> rv;
3802 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3807 lua.Print.connect (&_lua_print);
3810 lua_State* L = lua.getState();
3811 LuaInstance::register_classes (L);
3812 LuaBindings::set_session (L, _session);
3813 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3814 lua_setglobal (L, "Editor");
3816 lua.do_command ("function ardour () end");
3817 lua.do_file (script_path);
3820 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3821 if (!fn.isFunction ()) {
3824 luabridge::LuaRef rs = fn ();
3825 if (!rs.isTable ()) {
3828 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3829 if (!i.key().isString()) {
3832 std::string key = i.key().tostring();
3833 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3834 rv[key] = i.value().tostring();
3837 } catch (luabridge::LuaException const& e) {
3838 cerr << "LuaException:" << e.what () << endl;
3844 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3846 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3849 assert (add_route_dialog);
3852 if ((count = add_route_dialog->count()) <= 0) {
3857 lua.Print.connect (&_lua_print);
3860 lua_State* L = lua.getState();
3861 LuaInstance::register_classes (L);
3862 LuaBindings::set_session (L, _session);
3863 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3864 lua_setglobal (L, "Editor");
3866 lua.do_command ("function ardour () end");
3867 lua.do_file (script_path);
3869 luabridge::LuaRef args (luabridge::newTable (L));
3871 args["name"] = add_route_dialog->name_template ();
3872 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3873 args["group"] = add_route_dialog->route_group ();
3874 args["strict_io"] = add_route_dialog->use_strict_io ();
3875 args["instrument"] = add_route_dialog->requested_instrument ();
3876 args["track_mode"] = add_route_dialog->mode ();
3877 args["channels"] = add_route_dialog->channel_count ();
3878 args["how_many"] = count;
3881 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3882 if (fn.isFunction()) {
3885 } catch (luabridge::LuaException const& e) {
3886 cerr << "LuaException:" << e.what () << endl;
3888 display_insufficient_ports_message ();
3893 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3895 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3900 lua.Print.connect (&_lua_print);
3903 lua_State* L = lua.getState();
3904 LuaInstance::register_classes (L);
3905 LuaBindings::set_session (L, _session);
3906 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3907 lua_setglobal (L, "Editor");
3909 lua.do_command ("function ardour () end");
3910 lua.do_file (script_path);
3913 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3914 if (fn.isFunction()) {
3917 } catch (luabridge::LuaException const& e) {
3918 cerr << "LuaException:" << e.what () << endl;
3920 display_insufficient_ports_message ();
3925 ARDOUR_UI::launch_chat ()
3927 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3929 dialog.set_title (_("About the Chat"));
3930 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."));
3932 switch (dialog.run()) {
3934 open_uri("http://webchat.freenode.net/?channels=ardour");
3942 ARDOUR_UI::launch_manual ()
3944 PBD::open_uri (Config->get_tutorial_manual_url());
3948 ARDOUR_UI::launch_reference ()
3950 PBD::open_uri (Config->get_reference_manual_url());
3954 ARDOUR_UI::launch_tracker ()
3956 PBD::open_uri ("http://tracker.ardour.org");
3960 ARDOUR_UI::launch_subscribe ()
3962 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3966 ARDOUR_UI::launch_cheat_sheet ()
3969 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3971 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3976 ARDOUR_UI::launch_website ()
3978 PBD::open_uri ("http://ardour.org");
3982 ARDOUR_UI::launch_website_dev ()
3984 PBD::open_uri ("http://ardour.org/development.html");
3988 ARDOUR_UI::launch_forums ()
3990 PBD::open_uri ("https://community.ardour.org/forums");
3994 ARDOUR_UI::launch_howto_report ()
3996 PBD::open_uri ("http://ardour.org/reporting_bugs");
4000 ARDOUR_UI::loading_message (const std::string& msg)
4002 if (ARDOUR_COMMAND_LINE::no_splash) {
4010 splash->message (msg);
4014 ARDOUR_UI::show_splash ()
4018 splash = new Splash;
4028 ARDOUR_UI::hide_splash ()
4035 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4039 removed = rep.paths.size();
4042 MessageDialog msgd (_main_window,
4043 _("No files were ready for clean-up"),
4047 msgd.set_title (_("Clean-up"));
4048 msgd.set_secondary_text (_("If this seems surprising, \n\
4049 check for any existing snapshots.\n\
4050 These may still include regions that\n\
4051 require some unused files to continue to exist."));
4057 ArdourDialog results (_("Clean-up"), true, false);
4059 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4060 CleanupResultsModelColumns() {
4064 Gtk::TreeModelColumn<std::string> visible_name;
4065 Gtk::TreeModelColumn<std::string> fullpath;
4069 CleanupResultsModelColumns results_columns;
4070 Glib::RefPtr<Gtk::ListStore> results_model;
4071 Gtk::TreeView results_display;
4073 results_model = ListStore::create (results_columns);
4074 results_display.set_model (results_model);
4075 results_display.append_column (list_title, results_columns.visible_name);
4077 results_display.set_name ("CleanupResultsList");
4078 results_display.set_headers_visible (true);
4079 results_display.set_headers_clickable (false);
4080 results_display.set_reorderable (false);
4082 Gtk::ScrolledWindow list_scroller;
4085 Gtk::HBox dhbox; // the hbox for the image and text
4086 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4087 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4089 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4091 const string dead_directory = _session->session_directory().dead_path();
4094 %1 - number of files removed
4095 %2 - location of "dead"
4096 %3 - size of files affected
4097 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4100 const char* bprefix;
4101 double space_adjusted = 0;
4103 if (rep.space < 1000) {
4105 space_adjusted = rep.space;
4106 } else if (rep.space < 1000000) {
4107 bprefix = _("kilo");
4108 space_adjusted = floorf((float)rep.space / 1000.0);
4109 } else if (rep.space < 1000000 * 1000) {
4110 bprefix = _("mega");
4111 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4113 bprefix = _("giga");
4114 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4118 txt.set_markup (string_compose (P_("\
4119 The following file was deleted from %2,\n\
4120 releasing %3 %4bytes of disk space", "\
4121 The following %1 files were deleted from %2,\n\
4122 releasing %3 %4bytes of disk space", removed),
4123 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4125 txt.set_markup (string_compose (P_("\
4126 The following file was not in use and \n\
4127 has been moved to: %2\n\n\
4128 After a restart of %5\n\n\
4129 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4130 will release an additional %3 %4bytes of disk space.\n", "\
4131 The following %1 files were not in use and \n\
4132 have been moved to: %2\n\n\
4133 After a restart of %5\n\n\
4134 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4135 will release an additional %3 %4bytes of disk space.\n", removed),
4136 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4139 dhbox.pack_start (*dimage, true, false, 5);
4140 dhbox.pack_start (txt, true, false, 5);
4142 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4143 TreeModel::Row row = *(results_model->append());
4144 row[results_columns.visible_name] = *i;
4145 row[results_columns.fullpath] = *i;
4148 list_scroller.add (results_display);
4149 list_scroller.set_size_request (-1, 150);
4150 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4152 dvbox.pack_start (dhbox, true, false, 5);
4153 dvbox.pack_start (list_scroller, true, false, 5);
4154 ddhbox.pack_start (dvbox, true, false, 5);
4156 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4157 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4158 results.set_default_response (RESPONSE_CLOSE);
4159 results.set_position (Gtk::WIN_POS_MOUSE);
4161 results_display.show();
4162 list_scroller.show();
4169 //results.get_vbox()->show();
4170 results.set_resizable (false);
4177 ARDOUR_UI::cleanup ()
4179 if (_session == 0) {
4180 /* shouldn't happen: menu item is insensitive */
4185 MessageDialog checker (_("Are you sure you want to clean-up?"),
4187 Gtk::MESSAGE_QUESTION,
4190 checker.set_title (_("Clean-up"));
4192 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4193 ALL undo/redo information will be lost if you clean-up.\n\
4194 Clean-up will move all unused files to a \"dead\" location."));
4196 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4197 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4198 checker.set_default_response (RESPONSE_CANCEL);
4200 checker.set_name (_("CleanupDialog"));
4201 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4202 checker.set_position (Gtk::WIN_POS_MOUSE);
4204 switch (checker.run()) {
4205 case RESPONSE_ACCEPT:
4212 ARDOUR::CleanupReport rep;
4214 editor->prepare_for_cleanup ();
4216 /* do not allow flush until a session is reloaded */
4217 ActionManager::get_action (X_("Main"), X_("FlushWastebasket"))->set_sensitive (false);
4219 if (_session->cleanup_sources (rep)) {
4220 editor->finish_cleanup ();
4224 editor->finish_cleanup ();
4226 display_cleanup_results (rep, _("Cleaned Files"), false);
4230 ARDOUR_UI::flush_trash ()
4232 if (_session == 0) {
4233 /* shouldn't happen: menu item is insensitive */
4237 ARDOUR::CleanupReport rep;
4239 if (_session->cleanup_trash_sources (rep)) {
4243 display_cleanup_results (rep, _("deleted file"), true);
4247 ARDOUR_UI::cleanup_peakfiles ()
4249 if (_session == 0) {
4250 /* shouldn't happen: menu item is insensitive */
4254 if (! _session->can_cleanup_peakfiles ()) {
4258 // get all region-views in this session
4260 TrackViewList empty;
4262 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4263 std::list<RegionView*> views = rs.by_layer();
4265 // remove displayed audio-region-views waveforms
4266 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4267 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4268 if (!arv) { continue ; }
4269 arv->delete_waves();
4272 // cleanup peak files:
4273 // - stop pending peakfile threads
4274 // - close peakfiles if any
4275 // - remove peak dir in session
4276 // - setup peakfiles (background thread)
4277 _session->cleanup_peakfiles ();
4279 // re-add waves to ARV
4280 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4281 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4282 if (!arv) { continue ; }
4283 arv->create_waves();
4287 PresentationInfo::order_t
4288 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4290 if (editor->get_selection().tracks.empty()) {
4291 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4294 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4297 we want the new routes to have their order keys set starting from
4298 the highest order key in the selection + 1 (if available).
4301 if (place == RouteDialogs::AfterSelection) {
4302 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4304 order_hint = rtav->route()->presentation_info().order();
4307 } else if (place == RouteDialogs::BeforeSelection) {
4308 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4310 order_hint = rtav->route()->presentation_info().order();
4312 } else if (place == RouteDialogs::First) {
4315 /* leave order_hint at max_order */
4322 ARDOUR_UI::start_duplicate_routes ()
4324 if (!duplicate_routes_dialog) {
4325 duplicate_routes_dialog = new DuplicateRouteDialog;
4328 if (duplicate_routes_dialog->restart (_session)) {
4332 duplicate_routes_dialog->present ();
4336 ARDOUR_UI::add_route ()
4338 if (!add_route_dialog.get (false)) {
4339 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4346 if (add_route_dialog->is_visible()) {
4347 /* we're already doing this */
4351 add_route_dialog->set_position (WIN_POS_MOUSE);
4352 add_route_dialog->present();
4356 ARDOUR_UI::add_route_dialog_response (int r)
4359 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4363 if (!AudioEngine::instance()->running ()) {
4365 case AddRouteDialog::Add:
4366 case AddRouteDialog::AddAndClose:
4371 add_route_dialog->ArdourDialog::on_response (r);
4372 ARDOUR_UI_UTILS::engine_is_running ();
4379 case AddRouteDialog::Add:
4380 add_route_dialog->reset_name_edited ();
4382 case AddRouteDialog::AddAndClose:
4383 add_route_dialog->ArdourDialog::on_response (r);
4386 add_route_dialog->ArdourDialog::on_response (r);
4390 std::string template_path = add_route_dialog->get_template_path();
4391 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4392 meta_route_setup (template_path.substr (11));
4396 if ((count = add_route_dialog->count()) <= 0) {
4400 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4401 const string name_template = add_route_dialog->name_template ();
4402 DisplaySuspender ds;
4404 if (!template_path.empty ()) {
4405 if (add_route_dialog->name_template_is_default ()) {
4406 _session->new_route_from_template (count, order, template_path, string ());
4408 _session->new_route_from_template (count, order, template_path, name_template);
4413 ChanCount input_chan= add_route_dialog->channels ();
4414 ChanCount output_chan;
4415 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4416 RouteGroup* route_group = add_route_dialog->route_group ();
4417 AutoConnectOption oac = Config->get_output_auto_connect();
4418 bool strict_io = add_route_dialog->use_strict_io ();
4420 if (oac & AutoConnectMaster) {
4421 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4422 output_chan.set (DataType::MIDI, 0);
4424 output_chan = input_chan;
4427 /* XXX do something with name template */
4429 Session::ProcessorChangeBlocker pcb (_session);
4431 switch (add_route_dialog->type_wanted()) {
4432 case AddRouteDialog::AudioTrack:
4433 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);
4435 case AddRouteDialog::MidiTrack:
4436 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4438 case AddRouteDialog::MixedTrack:
4439 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4441 case AddRouteDialog::AudioBus:
4442 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4444 case AddRouteDialog::MidiBus:
4445 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4447 case AddRouteDialog::VCAMaster:
4448 _session->vca_manager().create_vca (count, name_template);
4450 case AddRouteDialog::FoldbackBus:
4451 session_add_foldback_bus (count, name_template);
4457 ARDOUR_UI::stop_video_server (bool ask_confirm)
4459 if (!video_server_process && ask_confirm) {
4460 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4462 if (video_server_process) {
4464 ArdourDialog confirm (_("Stop Video-Server"), true);
4465 Label m (_("Do you really want to stop the Video Server?"));
4466 confirm.get_vbox()->pack_start (m, true, true);
4467 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4468 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4469 confirm.show_all ();
4470 if (confirm.run() == RESPONSE_CANCEL) {
4474 delete video_server_process;
4475 video_server_process =0;
4480 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4482 ARDOUR_UI::start_video_server( float_window, true);
4486 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4492 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4493 if (video_server_process) {
4494 popup_error(_("The Video Server is already started."));
4496 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4502 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4504 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4506 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4508 video_server_dialog->set_transient_for (*float_window);
4511 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4512 video_server_dialog->hide();
4514 ResponseType r = (ResponseType) video_server_dialog->run ();
4515 video_server_dialog->hide();
4516 if (r != RESPONSE_ACCEPT) { return false; }
4517 if (video_server_dialog->show_again()) {
4518 Config->set_show_video_server_dialog(false);
4522 std::string icsd_exec = video_server_dialog->get_exec_path();
4523 std::string icsd_docroot = video_server_dialog->get_docroot();
4524 #ifndef PLATFORM_WINDOWS
4525 if (icsd_docroot.empty()) {
4526 icsd_docroot = VideoUtils::video_get_docroot (Config);
4531 #ifdef PLATFORM_WINDOWS
4532 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4533 /* OK, allow all drive letters */
4536 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4537 warning << _("Specified docroot is not an existing directory.") << endmsg;
4540 #ifndef PLATFORM_WINDOWS
4541 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4542 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4543 warning << _("Given Video Server is not an executable file.") << endmsg;
4547 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4548 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4549 warning << _("Given Video Server is not an executable file.") << endmsg;
4555 argp=(char**) calloc(9,sizeof(char*));
4556 argp[0] = strdup(icsd_exec.c_str());
4557 argp[1] = strdup("-P");
4558 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4559 argp[3] = strdup("-p");
4560 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4561 argp[5] = strdup("-C");
4562 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4563 argp[7] = strdup(icsd_docroot.c_str());
4565 stop_video_server();
4567 #ifdef PLATFORM_WINDOWS
4568 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4569 /* OK, allow all drive letters */
4572 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4573 Config->set_video_advanced_setup(false);
4575 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4576 Config->set_video_server_url(url_str);
4577 Config->set_video_server_docroot(icsd_docroot);
4578 Config->set_video_advanced_setup(true);
4581 if (video_server_process) {
4582 delete video_server_process;
4585 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4586 if (video_server_process->start()) {
4587 warning << _("Cannot launch the video-server") << endmsg;
4590 int timeout = 120; // 6 sec
4591 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4592 Glib::usleep (50000);
4594 if (--timeout <= 0 || !video_server_process->is_running()) break;
4597 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4599 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4600 delete video_server_process;
4601 video_server_process = 0;
4609 ARDOUR_UI::add_video (Gtk::Window* float_window)
4615 if (!start_video_server(float_window, false)) {
4616 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4621 add_video_dialog->set_transient_for (*float_window);
4624 if (add_video_dialog->is_visible()) {
4625 /* we're already doing this */
4629 ResponseType r = (ResponseType) add_video_dialog->run ();
4630 add_video_dialog->hide();
4631 if (r != RESPONSE_ACCEPT) { return; }
4633 bool local_file, orig_local_file;
4634 std::string path = add_video_dialog->file_name(local_file);
4636 std::string orig_path = path;
4637 orig_local_file = local_file;
4639 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4641 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4642 warning << string_compose(_("could not open %1"), path) << endmsg;
4645 if (!local_file && path.length() == 0) {
4646 warning << _("no video-file selected") << endmsg;
4650 std::string audio_from_video;
4651 bool detect_ltc = false;
4653 switch (add_video_dialog->import_option()) {
4654 case VTL_IMPORT_TRANSCODE:
4656 TranscodeVideoDialog *transcode_video_dialog;
4657 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4658 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4659 transcode_video_dialog->hide();
4660 if (r != RESPONSE_ACCEPT) {
4661 delete transcode_video_dialog;
4665 audio_from_video = transcode_video_dialog->get_audiofile();
4667 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4670 else if (!audio_from_video.empty()) {
4671 editor->embed_audio_from_video(
4673 video_timeline->get_offset(),
4674 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4677 switch (transcode_video_dialog->import_option()) {
4678 case VTL_IMPORT_TRANSCODED:
4679 path = transcode_video_dialog->get_filename();
4682 case VTL_IMPORT_REFERENCE:
4685 delete transcode_video_dialog;
4688 delete transcode_video_dialog;
4692 case VTL_IMPORT_NONE:
4696 /* strip _session->session_directory().video_path() from video file if possible */
4697 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4698 path=path.substr(_session->session_directory().video_path().size());
4699 if (path.at(0) == G_DIR_SEPARATOR) {
4700 path=path.substr(1);
4704 video_timeline->set_update_session_fps(auto_set_session_fps);
4706 if (video_timeline->video_file_info(path, local_file)) {
4707 XMLNode* node = new XMLNode(X_("Videotimeline"));
4708 node->set_property (X_("Filename"), path);
4709 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4710 node->set_property (X_("LocalFile"), local_file);
4711 if (orig_local_file) {
4712 node->set_property (X_("OriginalVideoFile"), orig_path);
4714 node->remove_property (X_("OriginalVideoFile"));
4716 _session->add_extra_xml (*node);
4717 _session->set_dirty ();
4719 if (!audio_from_video.empty() && detect_ltc) {
4720 std::vector<LTCFileReader::LTCMap> ltc_seq;
4723 /* TODO ask user about TV standard (LTC alignment if any) */
4724 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4725 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4727 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4729 /* TODO seek near end of file, and read LTC until end.
4730 * if it fails to find any LTC samples, scan complete file
4732 * calculate drift of LTC compared to video-duration,
4733 * ask user for reference (timecode from start/mid/end)
4736 // LTCFileReader will have written error messages
4739 ::g_unlink(audio_from_video.c_str());
4741 if (ltc_seq.size() == 0) {
4742 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4744 /* the very first TC in the file is somteimes not aligned properly */
4745 int i = ltc_seq.size() -1;
4746 ARDOUR::sampleoffset_t video_start_offset =
4747 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4748 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4749 video_timeline->set_offset(video_start_offset);
4753 _session->maybe_update_session_range(
4754 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4755 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4758 if (add_video_dialog->launch_xjadeo() && local_file) {
4759 editor->set_xjadeo_sensitive(true);
4760 editor->toggle_xjadeo_proc(1);
4762 editor->toggle_xjadeo_proc(0);
4764 editor->toggle_ruler_video(true);
4769 ARDOUR_UI::remove_video ()
4771 video_timeline->close_session();
4772 editor->toggle_ruler_video(false);
4775 video_timeline->set_offset_locked(false);
4776 video_timeline->set_offset(0);
4778 /* delete session state */
4779 XMLNode* node = new XMLNode(X_("Videotimeline"));
4780 _session->add_extra_xml(*node);
4781 node = new XMLNode(X_("Videomonitor"));
4782 _session->add_extra_xml(*node);
4783 node = new XMLNode(X_("Videoexport"));
4784 _session->add_extra_xml(*node);
4785 stop_video_server();
4789 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4791 if (localcacheonly) {
4792 video_timeline->vmon_update();
4794 video_timeline->flush_cache();
4796 editor->queue_visual_videotimeline_update();
4800 ARDOUR_UI::export_video (bool range)
4802 if (ARDOUR::Config->get_show_video_export_info()) {
4803 ExportVideoInfobox infobox (_session);
4804 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4805 if (infobox.show_again()) {
4806 ARDOUR::Config->set_show_video_export_info(false);
4809 case GTK_RESPONSE_YES:
4810 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4816 export_video_dialog->set_session (_session);
4817 export_video_dialog->apply_state(editor->get_selection().time, range);
4818 export_video_dialog->run ();
4819 export_video_dialog->hide ();
4823 ARDOUR_UI::preferences_settings () const
4828 node = _session->instant_xml(X_("Preferences"));
4830 node = Config->instant_xml(X_("Preferences"));
4834 node = new XMLNode (X_("Preferences"));
4841 ARDOUR_UI::mixer_settings () const
4846 node = _session->instant_xml(X_("Mixer"));
4848 node = Config->instant_xml(X_("Mixer"));
4852 node = new XMLNode (X_("Mixer"));
4859 ARDOUR_UI::main_window_settings () const
4864 node = _session->instant_xml(X_("Main"));
4866 node = Config->instant_xml(X_("Main"));
4870 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4871 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4876 node = new XMLNode (X_("Main"));
4883 ARDOUR_UI::editor_settings () const
4888 node = _session->instant_xml(X_("Editor"));
4890 node = Config->instant_xml(X_("Editor"));
4894 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4895 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4900 node = new XMLNode (X_("Editor"));
4907 ARDOUR_UI::keyboard_settings () const
4911 node = Config->extra_xml(X_("Keyboard"));
4914 node = new XMLNode (X_("Keyboard"));
4921 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4924 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4925 _session->locations()->add (location);
4930 ARDOUR_UI::halt_on_xrun_message ()
4932 cerr << "HALT on xrun\n";
4933 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4938 ARDOUR_UI::xrun_handler (samplepos_t where)
4944 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4946 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4947 create_xrun_marker(where);
4950 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4951 halt_on_xrun_message ();
4956 ARDOUR_UI::disk_overrun_handler ()
4958 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4960 if (!have_disk_speed_dialog_displayed) {
4961 have_disk_speed_dialog_displayed = true;
4962 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4963 The disk system on your computer\n\
4964 was not able to keep up with %1.\n\
4966 Specifically, it failed to write data to disk\n\
4967 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4968 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4974 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4975 static MessageDialog *scan_dlg = NULL;
4976 static ProgressBar *scan_pbar = NULL;
4977 static HBox *scan_tbox = NULL;
4978 static Gtk::Button *scan_timeout_button;
4981 ARDOUR_UI::cancel_plugin_scan ()
4983 PluginManager::instance().cancel_plugin_scan();
4987 ARDOUR_UI::cancel_plugin_timeout ()
4989 PluginManager::instance().cancel_plugin_timeout();
4990 scan_timeout_button->set_sensitive (false);
4994 ARDOUR_UI::plugin_scan_timeout (int timeout)
4996 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5000 scan_pbar->set_sensitive (false);
5001 scan_timeout_button->set_sensitive (true);
5002 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5005 scan_pbar->set_sensitive (false);
5006 scan_timeout_button->set_sensitive (false);
5012 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5014 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5018 const bool cancelled = PluginManager::instance().cancelled();
5019 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5020 if (cancelled && scan_dlg->is_mapped()) {
5025 if (cancelled || !can_cancel) {
5030 static Gtk::Button *cancel_button;
5032 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5033 VBox* vbox = scan_dlg->get_vbox();
5034 vbox->set_size_request(400,-1);
5035 scan_dlg->set_title (_("Scanning for plugins"));
5037 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5038 cancel_button->set_name ("EditorGTKButton");
5039 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5040 cancel_button->show();
5042 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5044 scan_tbox = manage( new HBox() );
5046 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5047 scan_timeout_button->set_name ("EditorGTKButton");
5048 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5049 scan_timeout_button->show();
5051 scan_pbar = manage(new ProgressBar());
5052 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5053 scan_pbar->set_text(_("Scan Timeout"));
5056 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5057 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5059 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5062 assert(scan_dlg && scan_tbox && cancel_button);
5064 if (type == X_("closeme")) {
5068 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5071 if (!can_cancel || !cancelled) {
5072 scan_timeout_button->set_sensitive(false);
5074 cancel_button->set_sensitive(can_cancel && !cancelled);
5080 ARDOUR_UI::gui_idle_handler ()
5083 /* due to idle calls, gtk_events_pending() may always return true */
5084 while (gtk_events_pending() && --timeout) {
5085 gtk_main_iteration ();
5090 ARDOUR_UI::disk_underrun_handler ()
5092 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5094 if (!have_disk_speed_dialog_displayed) {
5095 have_disk_speed_dialog_displayed = true;
5096 MessageDialog* msg = new MessageDialog (
5097 _main_window, string_compose (_("The disk system on your computer\n\
5098 was not able to keep up with %1.\n\
5100 Specifically, it failed to read data from disk\n\
5101 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5102 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5108 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5110 have_disk_speed_dialog_displayed = false;
5115 ARDOUR_UI::session_dialog (std::string msg)
5117 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5121 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5128 ARDOUR_UI::pending_state_dialog ()
5130 HBox* hbox = manage (new HBox());
5131 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5132 ArdourDialog dialog (_("Crash Recovery"), true);
5133 Label message (string_compose (_("\
5134 This session appears to have been in the\n\
5135 middle of recording when %1 or\n\
5136 the computer was shutdown.\n\
5138 %1 can recover any captured audio for\n\
5139 you, or it can ignore it. Please decide\n\
5140 what you would like to do.\n"), PROGRAM_NAME));
5141 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5142 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5143 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5144 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5145 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5146 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5147 dialog.set_default_response (RESPONSE_ACCEPT);
5148 dialog.set_position (WIN_POS_CENTER);
5153 switch (dialog.run ()) {
5154 case RESPONSE_ACCEPT:
5162 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5164 HBox* hbox = new HBox();
5165 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5166 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5167 Label message (string_compose (_("\
5168 This session was created with a sample rate of %1 Hz, but\n\
5169 %2 is currently running at %3 Hz. If you load this session,\n\
5170 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5172 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5173 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5174 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5175 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5176 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5177 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5178 dialog.set_default_response (RESPONSE_ACCEPT);
5179 dialog.set_position (WIN_POS_CENTER);
5184 switch (dialog.run()) {
5185 case RESPONSE_ACCEPT:
5195 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5197 MessageDialog msg (string_compose (_("\
5198 This session was created with a sample rate of %1 Hz, but\n\
5199 %2 is currently running at %3 Hz.\n\
5200 Audio will be recorded and played at the wrong sample rate.\n\
5201 Re-Configure the Audio Engine in\n\
5202 Menu > Window > Audio/Midi Setup"),
5203 desired, PROGRAM_NAME, actual),
5205 Gtk::MESSAGE_WARNING);
5210 ARDOUR_UI::use_config ()
5212 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5214 set_transport_controllable_state (*node);
5219 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5221 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5223 primary_clock->set (pos);
5225 case DeltaEditPoint:
5226 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5228 case DeltaOriginMarker:
5230 Location* loc = _session->locations()->clock_origin_location ();
5231 primary_clock->set (pos, false, loc ? loc->start() : 0);
5236 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5238 secondary_clock->set (pos);
5240 case DeltaEditPoint:
5241 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5243 case DeltaOriginMarker:
5245 Location* loc = _session->locations()->clock_origin_location ();
5246 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5251 if (big_clock_window) {
5252 big_clock->set (pos);
5254 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5259 ARDOUR_UI::record_state_changed ()
5261 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5264 /* why bother - the clock isn't visible */
5268 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5270 if (big_clock_window) {
5271 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5272 big_clock->set_active (true);
5274 big_clock->set_active (false);
5281 ARDOUR_UI::first_idle ()
5284 _session->allow_auto_play (true);
5288 editor->first_idle();
5291 /* in 1 second, hide the splash screen
5293 * Consider hiding it *now*. If a user opens opens a dialog
5294 * during that one second while the splash is still visible,
5295 * the dialog will push-back the splash.
5296 * Closing the dialog later will pop it back.
5298 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5300 Keyboard::set_can_save_keybindings (true);
5305 ARDOUR_UI::store_clock_modes ()
5307 XMLNode* node = new XMLNode(X_("ClockModes"));
5309 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5310 XMLNode* child = new XMLNode (X_("Clock"));
5312 child->set_property (X_("name"), (*x)->name());
5313 child->set_property (X_("mode"), (*x)->mode());
5314 child->set_property (X_("on"), (*x)->on());
5316 node->add_child_nocopy (*child);
5319 _session->add_extra_xml (*node);
5320 _session->set_dirty ();
5324 ARDOUR_UI::setup_profile ()
5326 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5327 Profile->set_small_screen ();
5330 if (g_getenv ("TRX")) {
5331 Profile->set_trx ();
5334 if (g_getenv ("MIXBUS")) {
5335 Profile->set_mixbus ();
5340 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5342 MissingFileDialog dialog (s, str, type);
5347 int result = dialog.run ();
5354 return 1; // quit entire session load
5357 result = dialog.get_action ();
5363 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5365 AmbiguousFileDialog dialog (file, hits);
5372 return dialog.get_which ();
5375 /** Allocate our thread-local buffers */
5377 ARDOUR_UI::get_process_buffers ()
5379 _process_thread->get_buffers ();
5382 /** Drop our thread-local buffers */
5384 ARDOUR_UI::drop_process_buffers ()
5386 _process_thread->drop_buffers ();
5390 ARDOUR_UI::feedback_detected ()
5392 _feedback_exists = true;
5396 ARDOUR_UI::successful_graph_sort ()
5398 _feedback_exists = false;
5402 ARDOUR_UI::midi_panic ()
5405 _session->midi_panic();
5410 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5412 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5413 const char* end_big = "</span>";
5414 const char* start_mono = "<tt>";
5415 const char* end_mono = "</tt>";
5417 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5418 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5419 "From now on, use the backup copy with older versions of %3"),
5420 xml_path, backup_path, PROGRAM_NAME,
5422 start_mono, end_mono), true);
5428 ARDOUR_UI::reset_peak_display ()
5430 if (!_session || !_session->master_out() || !editor_meter) return;
5431 editor_meter->clear_meters();
5432 editor_meter_max_peak = -INFINITY;
5433 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5437 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5439 if (!_session || !_session->master_out()) return;
5440 if (group == _session->master_out()->route_group()) {
5441 reset_peak_display ();
5446 ARDOUR_UI::reset_route_peak_display (Route* route)
5448 if (!_session || !_session->master_out()) return;
5449 if (_session->master_out().get() == route) {
5450 reset_peak_display ();
5455 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5457 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5458 audio_midi_setup->set_position (WIN_POS_CENTER);
5460 if (desired_sample_rate != 0) {
5461 if (Config->get_try_autostart_engine () || g_getenv ("ARDOUR_TRY_AUTOSTART_ENGINE")) {
5462 audio_midi_setup->try_autostart ();
5463 if (ARDOUR::AudioEngine::instance()->running()) {
5470 int response = audio_midi_setup->run();
5472 case Gtk::RESPONSE_DELETE_EVENT:
5473 // after latency callibration engine may run,
5474 // Running() signal was emitted, but dialog will not
5475 // have emitted a response. The user needs to close
5476 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5477 if (!AudioEngine::instance()->running()) {
5482 if (!AudioEngine::instance()->running()) {
5485 audio_midi_setup->hide ();
5493 ARDOUR_UI::transport_numpad_timeout ()
5495 _numpad_locate_happening = false;
5496 if (_numpad_timeout_connection.connected() )
5497 _numpad_timeout_connection.disconnect();
5502 ARDOUR_UI::transport_numpad_decimal ()
5504 _numpad_timeout_connection.disconnect();
5506 if (_numpad_locate_happening) {
5507 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5508 _numpad_locate_happening = false;
5510 _pending_locate_num = 0;
5511 _numpad_locate_happening = true;
5512 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5517 ARDOUR_UI::transport_numpad_event (int num)
5519 if ( _numpad_locate_happening ) {
5520 _pending_locate_num = _pending_locate_num*10 + num;
5523 case 0: toggle_roll(false, false); break;
5524 case 1: transport_rewind(1); break;
5525 case 2: transport_forward(1); break;
5526 case 3: transport_record(true); break;
5527 case 4: toggle_session_auto_loop(); break;
5528 case 5: transport_record(false); toggle_session_auto_loop(); break;
5529 case 6: toggle_punch(); break;
5530 case 7: toggle_click(); break;
5531 case 8: toggle_auto_return(); break;
5532 case 9: toggle_follow_edits(); break;
5538 ARDOUR_UI::set_flat_buttons ()
5540 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5544 ARDOUR_UI::audioengine_became_silent ()
5546 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5548 Gtk::MESSAGE_WARNING,
5552 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5554 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5555 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5556 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5557 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5558 Gtk::HBox pay_button_box;
5559 Gtk::HBox subscribe_button_box;
5561 pay_button_box.pack_start (pay_button, true, false);
5562 subscribe_button_box.pack_start (subscribe_button, true, false);
5564 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 */
5566 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5567 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5569 msg.get_vbox()->pack_start (pay_label);
5570 msg.get_vbox()->pack_start (pay_button_box);
5571 msg.get_vbox()->pack_start (subscribe_label);
5572 msg.get_vbox()->pack_start (subscribe_button_box);
5574 msg.get_vbox()->show_all ();
5576 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5577 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5578 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5583 case Gtk::RESPONSE_YES:
5584 AudioEngine::instance()->reset_silence_countdown ();
5587 case Gtk::RESPONSE_NO:
5589 save_state_canfail ("");
5590 exit (EXIT_SUCCESS);
5593 case Gtk::RESPONSE_CANCEL:
5595 /* don't reset, save session and exit */
5601 ARDOUR_UI::hide_application ()
5603 Application::instance ()-> hide ();
5607 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5609 /* icons, titles, WM stuff */
5611 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5613 if (window_icons.empty()) {
5614 Glib::RefPtr<Gdk::Pixbuf> icon;
5615 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5616 window_icons.push_back (icon);
5618 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5619 window_icons.push_back (icon);
5621 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5622 window_icons.push_back (icon);
5624 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5625 window_icons.push_back (icon);
5629 if (!window_icons.empty()) {
5630 window.set_default_icon_list (window_icons);
5633 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5635 if (!name.empty()) {
5639 window.set_title (title.get_string());
5640 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5642 window.set_flags (CAN_FOCUS);
5643 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5645 /* This is a hack to ensure that GTK-accelerators continue to
5646 * work. Once we switch over to entirely native bindings, this will be
5647 * unnecessary and should be removed
5649 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5651 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5652 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5653 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5654 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5658 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5660 Gtkmm2ext::Bindings* bindings = 0;
5661 Gtk::Window* window = 0;
5663 /* until we get ardour bindings working, we are not handling key
5667 if (ev->type != GDK_KEY_PRESS) {
5671 if (event_window == &_main_window) {
5673 window = event_window;
5675 /* find current tab contents */
5677 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5679 /* see if it uses the ardour binding system */
5682 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5685 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5689 window = event_window;
5691 /* see if window uses ardour binding system */
5693 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5696 /* An empty binding set is treated as if it doesn't exist */
5698 if (bindings && bindings->empty()) {
5702 return key_press_focus_accelerator_handler (*window, ev, bindings);
5705 static Gtkmm2ext::Bindings*
5706 get_bindings_from_widget_heirarchy (GtkWidget** w)
5711 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5714 *w = gtk_widget_get_parent (*w);
5717 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5721 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5723 GtkWindow* win = window.gobj();
5724 GtkWidget* focus = gtk_window_get_focus (win);
5725 GtkWidget* binding_widget = focus;
5726 bool special_handling_of_unmodified_accelerators = false;
5727 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5731 /* some widget has keyboard focus */
5733 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5735 /* A particular kind of focusable widget currently has keyboard
5736 * focus. All unmodified key events should go to that widget
5737 * first and not be used as an accelerator by default
5740 special_handling_of_unmodified_accelerators = true;
5744 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5745 if (focus_bindings) {
5746 bindings = focus_bindings;
5747 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5752 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",
5755 Gtkmm2ext::show_gdk_event_state (ev->state),
5756 special_handling_of_unmodified_accelerators,
5757 Keyboard::some_magic_widget_has_focus(),
5759 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5760 ((ev->state & mask) ? "yes" : "no"),
5761 window.get_title()));
5763 /* This exists to allow us to override the way GTK handles
5764 key events. The normal sequence is:
5766 a) event is delivered to a GtkWindow
5767 b) accelerators/mnemonics are activated
5768 c) if (b) didn't handle the event, propagate to
5769 the focus widget and/or focus chain
5771 The problem with this is that if the accelerators include
5772 keys without modifiers, such as the space bar or the
5773 letter "e", then pressing the key while typing into
5774 a text entry widget results in the accelerator being
5775 activated, instead of the desired letter appearing
5778 There is no good way of fixing this, but this
5779 represents a compromise. The idea is that
5780 key events involving modifiers (not Shift)
5781 get routed into the activation pathway first, then
5782 get propagated to the focus widget if necessary.
5784 If the key event doesn't involve modifiers,
5785 we deliver to the focus widget first, thus allowing
5786 it to get "normal text" without interference
5789 Of course, this can also be problematic: if there
5790 is a widget with focus, then it will swallow
5791 all "normal text" accelerators.
5795 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5797 /* no special handling or there are modifiers in effect: accelerate first */
5799 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5800 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5801 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5803 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5804 KeyboardKey k (ev->state, ev->keyval);
5808 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5810 if (bindings->activate (k, Bindings::Press)) {
5811 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5815 if (binding_widget) {
5816 binding_widget = gtk_widget_get_parent (binding_widget);
5817 if (binding_widget) {
5818 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5827 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5829 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5830 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5834 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5836 if (gtk_window_propagate_key_event (win, ev)) {
5837 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5843 /* no modifiers, propagate first */
5845 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5847 if (gtk_window_propagate_key_event (win, ev)) {
5848 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5852 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5853 KeyboardKey k (ev->state, ev->keyval);
5857 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5860 if (bindings->activate (k, Bindings::Press)) {
5861 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5865 if (binding_widget) {
5866 binding_widget = gtk_widget_get_parent (binding_widget);
5867 if (binding_widget) {
5868 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5877 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5879 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5880 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5885 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5890 ARDOUR_UI::cancel_solo ()
5893 _session->cancel_all_solo ();
5898 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5900 /* this resets focus to the first focusable parent of the given widget,
5901 * or, if there is no focusable parent, cancels focus in the toplevel
5902 * window that the given widget is packed into (if there is one).
5909 Gtk::Widget* top = w->get_toplevel();
5911 if (!top || !top->is_toplevel()) {
5915 w = w->get_parent ();
5919 if (w->is_toplevel()) {
5920 /* Setting the focus widget to a Gtk::Window causes all
5921 * subsequent calls to ::has_focus() on the nominal
5922 * focus widget in that window to return
5923 * false. Workaround: never set focus to the toplevel
5929 if (w->get_can_focus ()) {
5930 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5931 win->set_focus (*w);
5934 w = w->get_parent ();
5937 if (top == &_main_window) {
5941 /* no focusable parent found, cancel focus in top level window.
5942 C++ API cannot be used for this. Thanks, references.
5945 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
5950 ARDOUR_UI::monitor_dim_all ()
5952 boost::shared_ptr<Route> mon = _session->monitor_out ();
5956 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5958 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
5959 _monitor->set_dim_all (tact->get_active());
5963 ARDOUR_UI::monitor_cut_all ()
5965 boost::shared_ptr<Route> mon = _session->monitor_out ();
5969 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5971 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
5972 _monitor->set_cut_all (tact->get_active());
5976 ARDOUR_UI::monitor_mono ()
5978 boost::shared_ptr<Route> mon = _session->monitor_out ();
5982 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5984 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
5985 _monitor->set_mono (tact->get_active());
5989 ARDOUR_UI::shared_popup_menu ()
5991 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::shared_popup_menu, ignored);
5993 assert (!_shared_popup_menu || !_shared_popup_menu->is_visible());
5994 delete _shared_popup_menu;
5995 _shared_popup_menu = new Gtk::Menu;
5996 return _shared_popup_menu;