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 , secondary_clock_spacer (0)
291 , auto_input_button (ArdourButton::led_default_elements)
293 , auto_return_button (ArdourButton::led_default_elements)
294 , follow_edits_button (ArdourButton::led_default_elements)
295 , auditioning_alert_button (_("Audition"))
296 , solo_alert_button (_("Solo"))
297 , feedback_alert_button (_("Feedback"))
298 , error_alert_button ( ArdourButton::just_led_default_elements )
299 , editor_meter_peak_display()
301 , _suspend_editor_meter_callbacks (false)
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 */
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).substr (10, string::npos);
775 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
777 output << " </tbody>\n </table>" << endl;
779 // output this mess to a browser for easiest X-platform use
780 // it is not pretty HTML, but it works and it's main purpose
781 // is to create raw html to fit in Ardour's manual with no editing
786 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
788 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
794 #ifdef PLATFORM_WINDOWS
800 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
801 #ifndef PLATFORM_WINDOWS
804 g_unlink (file_name);
806 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
812 #ifndef PLATFORM_WINDOWS
816 PBD::open_uri (string_compose ("file:///%1", file_name));
818 halt_connection.disconnect ();
819 AudioEngine::instance()->stop ();
823 /* this being a GUI and all, we want peakfiles */
825 AudioFileSource::set_build_peakfiles (true);
826 AudioFileSource::set_build_missing_peakfiles (true);
828 /* set default clock modes */
830 primary_clock->set_mode (AudioClock::Timecode);
831 secondary_clock->set_mode (AudioClock::BBT);
833 /* start the time-of-day-clock */
836 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
837 update_wall_clock ();
838 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
843 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
844 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
845 Config->map_parameters (pc);
847 UIConfiguration::instance().map_parameters (pc);
851 ARDOUR_UI::~ARDOUR_UI ()
853 UIConfiguration::instance().save_state();
857 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
858 // don't bother at 'real' exit. the OS cleans up for us.
859 delete big_clock; big_clock = 0;
860 delete primary_clock; primary_clock = 0;
861 delete secondary_clock; secondary_clock = 0;
862 delete _process_thread; _process_thread = 0;
863 delete time_info_box; time_info_box = 0;
864 delete meterbridge; meterbridge = 0;
865 delete luawindow; luawindow = 0;
866 delete editor; editor = 0;
867 delete mixer; mixer = 0;
868 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
870 delete gui_object_state; gui_object_state = 0;
871 delete 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) {
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();
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)) {
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_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3289 session_path = ARDOUR_COMMAND_LINE::session_name;
3291 if (!session_path.empty()) {
3292 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3293 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3294 /* session/snapshot file, change path to be dir */
3295 session_path = Glib::path_get_dirname (session_path);
3300 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3302 _session_dialog = &session_dialog;
3305 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3307 /* if they named a specific statefile, use it, otherwise they are
3308 just giving a session folder, and we want to use it as is
3309 to find the session.
3312 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3314 if (suffix != string::npos) {
3315 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3316 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3317 session_name = Glib::path_get_basename (session_name);
3319 session_path = ARDOUR_COMMAND_LINE::session_name;
3320 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3325 session_dialog.clear_given ();
3328 if (should_be_new || session_name.empty()) {
3329 /* need the dialog to get info from user */
3331 cerr << "run dialog\n";
3333 switch (session_dialog.run()) {
3334 case RESPONSE_ACCEPT:
3337 /* this is used for async * app->ShouldLoad(). */
3338 continue; // while loop
3341 if (quit_on_cancel) {
3342 ARDOUR_UI::finish ();
3343 Gtkmm2ext::Application::instance()->cleanup();
3345 pthread_cancel_all ();
3346 return -1; // caller is responsible to call exit()
3352 session_dialog.hide ();
3355 /* if we run the startup dialog again, offer more than just "new session" */
3357 should_be_new = false;
3359 session_name = session_dialog.session_name (likely_new);
3360 session_path = session_dialog.session_folder ();
3367 int rv = ARDOUR::inflate_session (session_name,
3368 Config->get_default_session_parent_dir(), session_path, session_name);
3370 MessageDialog msg (session_dialog,
3371 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3376 session_dialog.set_provided_session (session_name, session_path);
3380 // XXX check archive, inflate
3381 string::size_type suffix = session_name.find (statefile_suffix);
3383 if (suffix != string::npos) {
3384 session_name = session_name.substr (0, suffix);
3387 /* this shouldn't happen, but we catch it just in case it does */
3389 if (session_name.empty()) {
3393 if (session_dialog.use_session_template()) {
3394 template_name = session_dialog.session_template_name();
3395 _session_is_new = true;
3398 if (session_name[0] == G_DIR_SEPARATOR ||
3399 #ifdef PLATFORM_WINDOWS
3400 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3402 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3403 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3408 /* absolute path or cwd-relative path specified for session name: infer session folder
3409 from what was given.
3412 session_path = Glib::path_get_dirname (session_name);
3413 session_name = Glib::path_get_basename (session_name);
3417 session_path = session_dialog.session_folder();
3419 char illegal = Session::session_name_is_legal (session_name);
3422 MessageDialog msg (session_dialog,
3423 string_compose (_("To ensure compatibility with various systems\n"
3424 "session names may not contain a '%1' character"),
3427 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3432 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3435 if (likely_new && !nsm) {
3437 std::string existing = Glib::build_filename (session_path, session_name);
3439 if (!ask_about_loading_existing_session (existing)) {
3440 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3445 _session_is_new = false;
3450 pop_back_splash (session_dialog);
3451 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3453 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3457 char illegal = Session::session_name_is_legal(session_name);
3460 pop_back_splash (session_dialog);
3461 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3462 "session names may not contain a '%1' character"), illegal));
3464 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3468 _session_is_new = true;
3471 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3473 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3474 meta_session_setup (template_name.substr (11));
3476 } else if (likely_new && template_name.empty()) {
3478 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3482 ret = load_session (session_path, session_name, template_name);
3485 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3489 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3490 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3494 /* clear this to avoid endless attempts to load the
3498 ARDOUR_COMMAND_LINE::session_name = "";
3502 _session_dialog = NULL;
3508 ARDOUR_UI::close_session()
3510 if (!check_audioengine (_main_window)) {
3514 if (unload_session (true)) {
3518 ARDOUR_COMMAND_LINE::session_name = "";
3520 if (get_session_parameters (true, false)) {
3525 /** @param snap_name Snapshot name (without .ardour suffix).
3526 * @return -2 if the load failed because we are not connected to the AudioEngine.
3529 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3531 /* load_session calls flush_pending() which allows
3532 * GUI interaction and potentially loading another session
3533 * (that was easy via snapshot sidebar).
3534 * Recursing into load_session() from load_session() and recusive
3535 * event loops causes all kind of crashes.
3537 assert (!session_load_in_progress);
3538 if (session_load_in_progress) {
3541 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3543 Session *new_session;
3548 unload_status = unload_session ();
3550 if (unload_status < 0) {
3552 } else if (unload_status > 0) {
3558 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3561 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3564 /* this one is special */
3566 catch (AudioEngine::PortRegistrationFailure const& err) {
3568 MessageDialog msg (err.what(),
3571 Gtk::BUTTONS_CLOSE);
3573 msg.set_title (_("Port Registration Error"));
3574 msg.set_secondary_text (_("Click the Close button to try again."));
3575 msg.set_position (Gtk::WIN_POS_CENTER);
3576 pop_back_splash (msg);
3579 int response = msg.run ();
3584 case RESPONSE_CANCEL:
3591 catch (SessionException const& e) {
3592 MessageDialog msg (string_compose(
3593 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3594 path, snap_name, e.what()),
3599 msg.set_title (_("Loading Error"));
3600 msg.set_position (Gtk::WIN_POS_CENTER);
3601 pop_back_splash (msg);
3613 MessageDialog msg (string_compose(
3614 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3620 msg.set_title (_("Loading Error"));
3621 msg.set_position (Gtk::WIN_POS_CENTER);
3622 pop_back_splash (msg);
3634 list<string> const u = new_session->unknown_processors ();
3636 MissingPluginDialog d (_session, u);
3641 if (!new_session->writable()) {
3642 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3647 msg.set_title (_("Read-only Session"));
3648 msg.set_position (Gtk::WIN_POS_CENTER);
3649 pop_back_splash (msg);
3656 /* Now the session been created, add the transport controls */
3657 new_session->add_controllable(roll_controllable);
3658 new_session->add_controllable(stop_controllable);
3659 new_session->add_controllable(goto_start_controllable);
3660 new_session->add_controllable(goto_end_controllable);
3661 new_session->add_controllable(auto_loop_controllable);
3662 new_session->add_controllable(play_selection_controllable);
3663 new_session->add_controllable(rec_controllable);
3665 set_session (new_session);
3668 _session->set_clean ();
3671 #ifdef WINDOWS_VST_SUPPORT
3672 fst_stop_threading();
3676 Timers::TimerSuspender t;
3680 #ifdef WINDOWS_VST_SUPPORT
3681 fst_start_threading();
3685 if (!mix_template.empty ()) {
3686 /* if mix_template is given, assume this is a new session */
3687 string metascript = Glib::build_filename (mix_template, "template.lua");
3688 meta_session_setup (metascript);
3693 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3694 * which is queued by set_session().
3695 * If session-loading fails we hide it explicitly.
3696 * This covers both cases in a central place.
3705 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3707 Session *new_session;
3710 x = unload_session ();
3718 _session_is_new = true;
3721 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3724 catch (SessionException const& e) {
3725 cerr << "Here are the errors associated with this failed session:\n";
3727 cerr << "---------\n";
3728 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3729 msg.set_title (_("Loading Error"));
3730 msg.set_position (Gtk::WIN_POS_CENTER);
3731 pop_back_splash (msg);
3736 cerr << "Here are the errors associated with this failed session:\n";
3738 cerr << "---------\n";
3739 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3740 msg.set_title (_("Loading Error"));
3741 msg.set_position (Gtk::WIN_POS_CENTER);
3742 pop_back_splash (msg);
3747 /* Give the new session the default GUI state, if such things exist */
3750 n = Config->instant_xml (X_("Editor"));
3752 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3753 new_session->add_instant_xml (*n, false);
3755 n = Config->instant_xml (X_("Mixer"));
3757 new_session->add_instant_xml (*n, false);
3760 n = Config->instant_xml (X_("Preferences"));
3762 new_session->add_instant_xml (*n, false);
3765 /* Put the playhead at 0 and scroll fully left */
3766 n = new_session->instant_xml (X_("Editor"));
3768 n->set_property (X_("playhead"), X_("0"));
3769 n->set_property (X_("left-frame"), X_("0"));
3772 set_session (new_session);
3774 new_session->save_state(new_session->name());
3780 static void _lua_print (std::string s) {
3782 std::cout << "LuaInstance: " << s << "\n";
3784 PBD::info << "LuaInstance: " << s << endmsg;
3787 std::map<std::string, std::string>
3788 ARDOUR_UI::route_setup_info (const std::string& script_path)
3790 std::map<std::string, std::string> rv;
3792 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3797 lua.Print.connect (&_lua_print);
3800 lua_State* L = lua.getState();
3801 LuaInstance::register_classes (L);
3802 LuaBindings::set_session (L, _session);
3803 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3804 lua_setglobal (L, "Editor");
3806 lua.do_command ("function ardour () end");
3807 lua.do_file (script_path);
3810 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3811 if (!fn.isFunction ()) {
3814 luabridge::LuaRef rs = fn ();
3815 if (!rs.isTable ()) {
3818 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3819 if (!i.key().isString()) {
3822 std::string key = i.key().tostring();
3823 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3824 rv[key] = i.value().tostring();
3827 } catch (luabridge::LuaException const& e) {
3828 cerr << "LuaException:" << e.what () << endl;
3834 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3836 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3839 assert (add_route_dialog);
3842 if ((count = add_route_dialog->count()) <= 0) {
3847 lua.Print.connect (&_lua_print);
3850 lua_State* L = lua.getState();
3851 LuaInstance::register_classes (L);
3852 LuaBindings::set_session (L, _session);
3853 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3854 lua_setglobal (L, "Editor");
3856 lua.do_command ("function ardour () end");
3857 lua.do_file (script_path);
3859 luabridge::LuaRef args (luabridge::newTable (L));
3861 args["name"] = add_route_dialog->name_template ();
3862 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3863 args["group"] = add_route_dialog->route_group ();
3864 args["strict_io"] = add_route_dialog->use_strict_io ();
3865 args["instrument"] = add_route_dialog->requested_instrument ();
3866 args["track_mode"] = add_route_dialog->mode ();
3867 args["channels"] = add_route_dialog->channel_count ();
3868 args["how_many"] = count;
3871 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3872 if (fn.isFunction()) {
3875 } catch (luabridge::LuaException const& e) {
3876 cerr << "LuaException:" << e.what () << endl;
3878 display_insufficient_ports_message ();
3883 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3885 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3890 lua.Print.connect (&_lua_print);
3893 lua_State* L = lua.getState();
3894 LuaInstance::register_classes (L);
3895 LuaBindings::set_session (L, _session);
3896 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3897 lua_setglobal (L, "Editor");
3899 lua.do_command ("function ardour () end");
3900 lua.do_file (script_path);
3903 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3904 if (fn.isFunction()) {
3907 } catch (luabridge::LuaException const& e) {
3908 cerr << "LuaException:" << e.what () << endl;
3910 display_insufficient_ports_message ();
3915 ARDOUR_UI::launch_chat ()
3917 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3919 dialog.set_title (_("About the Chat"));
3920 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."));
3922 switch (dialog.run()) {
3924 open_uri("http://webchat.freenode.net/?channels=ardour");
3932 ARDOUR_UI::launch_manual ()
3934 PBD::open_uri (Config->get_tutorial_manual_url());
3938 ARDOUR_UI::launch_reference ()
3940 PBD::open_uri (Config->get_reference_manual_url());
3944 ARDOUR_UI::launch_tracker ()
3946 PBD::open_uri ("http://tracker.ardour.org");
3950 ARDOUR_UI::launch_subscribe ()
3952 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3956 ARDOUR_UI::launch_cheat_sheet ()
3959 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3961 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3966 ARDOUR_UI::launch_website ()
3968 PBD::open_uri ("http://ardour.org");
3972 ARDOUR_UI::launch_website_dev ()
3974 PBD::open_uri ("http://ardour.org/development.html");
3978 ARDOUR_UI::launch_forums ()
3980 PBD::open_uri ("https://community.ardour.org/forums");
3984 ARDOUR_UI::launch_howto_report ()
3986 PBD::open_uri ("http://ardour.org/reporting_bugs");
3990 ARDOUR_UI::loading_message (const std::string& msg)
3992 if (ARDOUR_COMMAND_LINE::no_splash) {
4000 splash->message (msg);
4004 ARDOUR_UI::show_splash ()
4008 splash = new Splash;
4018 ARDOUR_UI::hide_splash ()
4025 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4029 removed = rep.paths.size();
4032 MessageDialog msgd (_main_window,
4033 _("No files were ready for clean-up"),
4037 msgd.set_title (_("Clean-up"));
4038 msgd.set_secondary_text (_("If this seems surprising, \n\
4039 check for any existing snapshots.\n\
4040 These may still include regions that\n\
4041 require some unused files to continue to exist."));
4047 ArdourDialog results (_("Clean-up"), true, false);
4049 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4050 CleanupResultsModelColumns() {
4054 Gtk::TreeModelColumn<std::string> visible_name;
4055 Gtk::TreeModelColumn<std::string> fullpath;
4059 CleanupResultsModelColumns results_columns;
4060 Glib::RefPtr<Gtk::ListStore> results_model;
4061 Gtk::TreeView results_display;
4063 results_model = ListStore::create (results_columns);
4064 results_display.set_model (results_model);
4065 results_display.append_column (list_title, results_columns.visible_name);
4067 results_display.set_name ("CleanupResultsList");
4068 results_display.set_headers_visible (true);
4069 results_display.set_headers_clickable (false);
4070 results_display.set_reorderable (false);
4072 Gtk::ScrolledWindow list_scroller;
4075 Gtk::HBox dhbox; // the hbox for the image and text
4076 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4077 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4079 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4081 const string dead_directory = _session->session_directory().dead_path();
4084 %1 - number of files removed
4085 %2 - location of "dead"
4086 %3 - size of files affected
4087 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4090 const char* bprefix;
4091 double space_adjusted = 0;
4093 if (rep.space < 1000) {
4095 space_adjusted = rep.space;
4096 } else if (rep.space < 1000000) {
4097 bprefix = _("kilo");
4098 space_adjusted = floorf((float)rep.space / 1000.0);
4099 } else if (rep.space < 1000000 * 1000) {
4100 bprefix = _("mega");
4101 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4103 bprefix = _("giga");
4104 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4108 txt.set_markup (string_compose (P_("\
4109 The following file was deleted from %2,\n\
4110 releasing %3 %4bytes of disk space", "\
4111 The following %1 files were deleted from %2,\n\
4112 releasing %3 %4bytes of disk space", removed),
4113 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4115 txt.set_markup (string_compose (P_("\
4116 The following file was not in use and \n\
4117 has been moved to: %2\n\n\
4118 After a restart of %5\n\n\
4119 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4120 will release an additional %3 %4bytes of disk space.\n", "\
4121 The following %1 files were not in use and \n\
4122 have been moved to: %2\n\n\
4123 After a restart of %5\n\n\
4124 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4125 will release an additional %3 %4bytes of disk space.\n", removed),
4126 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4129 dhbox.pack_start (*dimage, true, false, 5);
4130 dhbox.pack_start (txt, true, false, 5);
4132 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4133 TreeModel::Row row = *(results_model->append());
4134 row[results_columns.visible_name] = *i;
4135 row[results_columns.fullpath] = *i;
4138 list_scroller.add (results_display);
4139 list_scroller.set_size_request (-1, 150);
4140 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4142 dvbox.pack_start (dhbox, true, false, 5);
4143 dvbox.pack_start (list_scroller, true, false, 5);
4144 ddhbox.pack_start (dvbox, true, false, 5);
4146 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4147 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4148 results.set_default_response (RESPONSE_CLOSE);
4149 results.set_position (Gtk::WIN_POS_MOUSE);
4151 results_display.show();
4152 list_scroller.show();
4159 //results.get_vbox()->show();
4160 results.set_resizable (false);
4167 ARDOUR_UI::cleanup ()
4169 if (_session == 0) {
4170 /* shouldn't happen: menu item is insensitive */
4175 MessageDialog checker (_("Are you sure you want to clean-up?"),
4177 Gtk::MESSAGE_QUESTION,
4180 checker.set_title (_("Clean-up"));
4182 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4183 ALL undo/redo information will be lost if you clean-up.\n\
4184 Clean-up will move all unused files to a \"dead\" location."));
4186 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4187 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4188 checker.set_default_response (RESPONSE_CANCEL);
4190 checker.set_name (_("CleanupDialog"));
4191 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4192 checker.set_position (Gtk::WIN_POS_MOUSE);
4194 switch (checker.run()) {
4195 case RESPONSE_ACCEPT:
4201 ARDOUR::CleanupReport rep;
4203 editor->prepare_for_cleanup ();
4205 /* do not allow flush until a session is reloaded */
4207 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4209 act->set_sensitive (false);
4212 if (_session->cleanup_sources (rep)) {
4213 editor->finish_cleanup ();
4217 editor->finish_cleanup ();
4220 display_cleanup_results (rep, _("Cleaned Files"), false);
4224 ARDOUR_UI::flush_trash ()
4226 if (_session == 0) {
4227 /* shouldn't happen: menu item is insensitive */
4231 ARDOUR::CleanupReport rep;
4233 if (_session->cleanup_trash_sources (rep)) {
4237 display_cleanup_results (rep, _("deleted file"), true);
4241 ARDOUR_UI::cleanup_peakfiles ()
4243 if (_session == 0) {
4244 /* shouldn't happen: menu item is insensitive */
4248 if (! _session->can_cleanup_peakfiles ()) {
4252 // get all region-views in this session
4254 TrackViewList empty;
4256 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4257 std::list<RegionView*> views = rs.by_layer();
4259 // remove displayed audio-region-views waveforms
4260 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4261 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4262 if (!arv) { continue ; }
4263 arv->delete_waves();
4266 // cleanup peak files:
4267 // - stop pending peakfile threads
4268 // - close peakfiles if any
4269 // - remove peak dir in session
4270 // - setup peakfiles (background thread)
4271 _session->cleanup_peakfiles ();
4273 // re-add waves to ARV
4274 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4275 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4276 if (!arv) { continue ; }
4277 arv->create_waves();
4281 PresentationInfo::order_t
4282 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4284 if (editor->get_selection().tracks.empty()) {
4285 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4288 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4291 we want the new routes to have their order keys set starting from
4292 the highest order key in the selection + 1 (if available).
4295 if (place == RouteDialogs::AfterSelection) {
4296 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4298 order_hint = rtav->route()->presentation_info().order();
4301 } else if (place == RouteDialogs::BeforeSelection) {
4302 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4304 order_hint = rtav->route()->presentation_info().order();
4306 } else if (place == RouteDialogs::First) {
4309 /* leave order_hint at max_order */
4316 ARDOUR_UI::start_duplicate_routes ()
4318 if (!duplicate_routes_dialog) {
4319 duplicate_routes_dialog = new DuplicateRouteDialog;
4322 if (duplicate_routes_dialog->restart (_session)) {
4326 duplicate_routes_dialog->present ();
4330 ARDOUR_UI::add_route ()
4332 if (!add_route_dialog.get (false)) {
4333 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4340 if (add_route_dialog->is_visible()) {
4341 /* we're already doing this */
4345 add_route_dialog->set_position (WIN_POS_MOUSE);
4346 add_route_dialog->present();
4350 ARDOUR_UI::add_route_dialog_response (int r)
4353 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4357 if (!AudioEngine::instance()->running ()) {
4359 case AddRouteDialog::Add:
4360 case AddRouteDialog::AddAndClose:
4365 add_route_dialog->ArdourDialog::on_response (r);
4366 ARDOUR_UI_UTILS::engine_is_running ();
4373 case AddRouteDialog::Add:
4374 add_route_dialog->reset_name_edited ();
4376 case AddRouteDialog::AddAndClose:
4377 add_route_dialog->ArdourDialog::on_response (r);
4380 add_route_dialog->ArdourDialog::on_response (r);
4384 std::string template_path = add_route_dialog->get_template_path();
4385 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4386 meta_route_setup (template_path.substr (11));
4390 if ((count = add_route_dialog->count()) <= 0) {
4394 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4395 const string name_template = add_route_dialog->name_template ();
4396 DisplaySuspender ds;
4398 if (!template_path.empty ()) {
4399 if (add_route_dialog->name_template_is_default ()) {
4400 _session->new_route_from_template (count, order, template_path, string ());
4402 _session->new_route_from_template (count, order, template_path, name_template);
4407 ChanCount input_chan= add_route_dialog->channels ();
4408 ChanCount output_chan;
4409 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4410 RouteGroup* route_group = add_route_dialog->route_group ();
4411 AutoConnectOption oac = Config->get_output_auto_connect();
4412 bool strict_io = add_route_dialog->use_strict_io ();
4414 if (oac & AutoConnectMaster) {
4415 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4416 output_chan.set (DataType::MIDI, 0);
4418 output_chan = input_chan;
4421 /* XXX do something with name template */
4423 Session::ProcessorChangeBlocker pcb (_session);
4425 switch (add_route_dialog->type_wanted()) {
4426 case AddRouteDialog::AudioTrack:
4427 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);
4429 case AddRouteDialog::MidiTrack:
4430 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4432 case AddRouteDialog::MixedTrack:
4433 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4435 case AddRouteDialog::AudioBus:
4436 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4438 case AddRouteDialog::MidiBus:
4439 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4441 case AddRouteDialog::VCAMaster:
4442 _session->vca_manager().create_vca (count, name_template);
4444 case AddRouteDialog::FoldbackBus:
4445 session_add_foldback_bus (count, name_template);
4451 ARDOUR_UI::stop_video_server (bool ask_confirm)
4453 if (!video_server_process && ask_confirm) {
4454 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4456 if (video_server_process) {
4458 ArdourDialog confirm (_("Stop Video-Server"), true);
4459 Label m (_("Do you really want to stop the Video Server?"));
4460 confirm.get_vbox()->pack_start (m, true, true);
4461 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4462 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4463 confirm.show_all ();
4464 if (confirm.run() == RESPONSE_CANCEL) {
4468 delete video_server_process;
4469 video_server_process =0;
4474 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4476 ARDOUR_UI::start_video_server( float_window, true);
4480 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4486 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4487 if (video_server_process) {
4488 popup_error(_("The Video Server is already started."));
4490 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4496 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4498 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4500 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4502 video_server_dialog->set_transient_for (*float_window);
4505 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4506 video_server_dialog->hide();
4508 ResponseType r = (ResponseType) video_server_dialog->run ();
4509 video_server_dialog->hide();
4510 if (r != RESPONSE_ACCEPT) { return false; }
4511 if (video_server_dialog->show_again()) {
4512 Config->set_show_video_server_dialog(false);
4516 std::string icsd_exec = video_server_dialog->get_exec_path();
4517 std::string icsd_docroot = video_server_dialog->get_docroot();
4518 #ifndef PLATFORM_WINDOWS
4519 if (icsd_docroot.empty()) {
4520 icsd_docroot = VideoUtils::video_get_docroot (Config);
4525 #ifdef PLATFORM_WINDOWS
4526 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4527 /* OK, allow all drive letters */
4530 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4531 warning << _("Specified docroot is not an existing directory.") << endmsg;
4534 #ifndef PLATFORM_WINDOWS
4535 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4536 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4537 warning << _("Given Video Server is not an executable file.") << endmsg;
4541 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4542 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4543 warning << _("Given Video Server is not an executable file.") << endmsg;
4549 argp=(char**) calloc(9,sizeof(char*));
4550 argp[0] = strdup(icsd_exec.c_str());
4551 argp[1] = strdup("-P");
4552 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4553 argp[3] = strdup("-p");
4554 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4555 argp[5] = strdup("-C");
4556 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4557 argp[7] = strdup(icsd_docroot.c_str());
4559 stop_video_server();
4561 #ifdef PLATFORM_WINDOWS
4562 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4563 /* OK, allow all drive letters */
4566 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4567 Config->set_video_advanced_setup(false);
4569 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4570 Config->set_video_server_url(url_str);
4571 Config->set_video_server_docroot(icsd_docroot);
4572 Config->set_video_advanced_setup(true);
4575 if (video_server_process) {
4576 delete video_server_process;
4579 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4580 if (video_server_process->start()) {
4581 warning << _("Cannot launch the video-server") << endmsg;
4584 int timeout = 120; // 6 sec
4585 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4586 Glib::usleep (50000);
4588 if (--timeout <= 0 || !video_server_process->is_running()) break;
4591 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4593 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4594 delete video_server_process;
4595 video_server_process = 0;
4603 ARDOUR_UI::add_video (Gtk::Window* float_window)
4609 if (!start_video_server(float_window, false)) {
4610 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4615 add_video_dialog->set_transient_for (*float_window);
4618 if (add_video_dialog->is_visible()) {
4619 /* we're already doing this */
4623 ResponseType r = (ResponseType) add_video_dialog->run ();
4624 add_video_dialog->hide();
4625 if (r != RESPONSE_ACCEPT) { return; }
4627 bool local_file, orig_local_file;
4628 std::string path = add_video_dialog->file_name(local_file);
4630 std::string orig_path = path;
4631 orig_local_file = local_file;
4633 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4635 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4636 warning << string_compose(_("could not open %1"), path) << endmsg;
4639 if (!local_file && path.length() == 0) {
4640 warning << _("no video-file selected") << endmsg;
4644 std::string audio_from_video;
4645 bool detect_ltc = false;
4647 switch (add_video_dialog->import_option()) {
4648 case VTL_IMPORT_TRANSCODE:
4650 TranscodeVideoDialog *transcode_video_dialog;
4651 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4652 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4653 transcode_video_dialog->hide();
4654 if (r != RESPONSE_ACCEPT) {
4655 delete transcode_video_dialog;
4659 audio_from_video = transcode_video_dialog->get_audiofile();
4661 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4664 else if (!audio_from_video.empty()) {
4665 editor->embed_audio_from_video(
4667 video_timeline->get_offset(),
4668 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4671 switch (transcode_video_dialog->import_option()) {
4672 case VTL_IMPORT_TRANSCODED:
4673 path = transcode_video_dialog->get_filename();
4676 case VTL_IMPORT_REFERENCE:
4679 delete transcode_video_dialog;
4682 delete transcode_video_dialog;
4686 case VTL_IMPORT_NONE:
4690 /* strip _session->session_directory().video_path() from video file if possible */
4691 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4692 path=path.substr(_session->session_directory().video_path().size());
4693 if (path.at(0) == G_DIR_SEPARATOR) {
4694 path=path.substr(1);
4698 video_timeline->set_update_session_fps(auto_set_session_fps);
4700 if (video_timeline->video_file_info(path, local_file)) {
4701 XMLNode* node = new XMLNode(X_("Videotimeline"));
4702 node->set_property (X_("Filename"), path);
4703 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4704 node->set_property (X_("LocalFile"), local_file);
4705 if (orig_local_file) {
4706 node->set_property (X_("OriginalVideoFile"), orig_path);
4708 node->remove_property (X_("OriginalVideoFile"));
4710 _session->add_extra_xml (*node);
4711 _session->set_dirty ();
4713 if (!audio_from_video.empty() && detect_ltc) {
4714 std::vector<LTCFileReader::LTCMap> ltc_seq;
4717 /* TODO ask user about TV standard (LTC alignment if any) */
4718 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4719 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4721 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4723 /* TODO seek near end of file, and read LTC until end.
4724 * if it fails to find any LTC samples, scan complete file
4726 * calculate drift of LTC compared to video-duration,
4727 * ask user for reference (timecode from start/mid/end)
4730 // LTCFileReader will have written error messages
4733 ::g_unlink(audio_from_video.c_str());
4735 if (ltc_seq.size() == 0) {
4736 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4738 /* the very first TC in the file is somteimes not aligned properly */
4739 int i = ltc_seq.size() -1;
4740 ARDOUR::sampleoffset_t video_start_offset =
4741 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4742 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4743 video_timeline->set_offset(video_start_offset);
4747 _session->maybe_update_session_range(
4748 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4749 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4752 if (add_video_dialog->launch_xjadeo() && local_file) {
4753 editor->set_xjadeo_sensitive(true);
4754 editor->toggle_xjadeo_proc(1);
4756 editor->toggle_xjadeo_proc(0);
4758 editor->toggle_ruler_video(true);
4763 ARDOUR_UI::remove_video ()
4765 video_timeline->close_session();
4766 editor->toggle_ruler_video(false);
4769 video_timeline->set_offset_locked(false);
4770 video_timeline->set_offset(0);
4772 /* delete session state */
4773 XMLNode* node = new XMLNode(X_("Videotimeline"));
4774 _session->add_extra_xml(*node);
4775 node = new XMLNode(X_("Videomonitor"));
4776 _session->add_extra_xml(*node);
4777 node = new XMLNode(X_("Videoexport"));
4778 _session->add_extra_xml(*node);
4779 stop_video_server();
4783 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4785 if (localcacheonly) {
4786 video_timeline->vmon_update();
4788 video_timeline->flush_cache();
4790 editor->queue_visual_videotimeline_update();
4794 ARDOUR_UI::export_video (bool range)
4796 if (ARDOUR::Config->get_show_video_export_info()) {
4797 ExportVideoInfobox infobox (_session);
4798 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4799 if (infobox.show_again()) {
4800 ARDOUR::Config->set_show_video_export_info(false);
4803 case GTK_RESPONSE_YES:
4804 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4810 export_video_dialog->set_session (_session);
4811 export_video_dialog->apply_state(editor->get_selection().time, range);
4812 export_video_dialog->run ();
4813 export_video_dialog->hide ();
4817 ARDOUR_UI::preferences_settings () const
4822 node = _session->instant_xml(X_("Preferences"));
4824 node = Config->instant_xml(X_("Preferences"));
4828 node = new XMLNode (X_("Preferences"));
4835 ARDOUR_UI::mixer_settings () const
4840 node = _session->instant_xml(X_("Mixer"));
4842 node = Config->instant_xml(X_("Mixer"));
4846 node = new XMLNode (X_("Mixer"));
4853 ARDOUR_UI::main_window_settings () const
4858 node = _session->instant_xml(X_("Main"));
4860 node = Config->instant_xml(X_("Main"));
4864 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4865 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4870 node = new XMLNode (X_("Main"));
4877 ARDOUR_UI::editor_settings () const
4882 node = _session->instant_xml(X_("Editor"));
4884 node = Config->instant_xml(X_("Editor"));
4888 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4889 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4894 node = new XMLNode (X_("Editor"));
4901 ARDOUR_UI::keyboard_settings () const
4905 node = Config->extra_xml(X_("Keyboard"));
4908 node = new XMLNode (X_("Keyboard"));
4915 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4918 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4919 _session->locations()->add (location);
4924 ARDOUR_UI::halt_on_xrun_message ()
4926 cerr << "HALT on xrun\n";
4927 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4932 ARDOUR_UI::xrun_handler (samplepos_t where)
4938 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4940 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4941 create_xrun_marker(where);
4944 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4945 halt_on_xrun_message ();
4950 ARDOUR_UI::disk_overrun_handler ()
4952 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4954 if (!have_disk_speed_dialog_displayed) {
4955 have_disk_speed_dialog_displayed = true;
4956 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4957 The disk system on your computer\n\
4958 was not able to keep up with %1.\n\
4960 Specifically, it failed to write data to disk\n\
4961 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4962 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4968 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4969 static MessageDialog *scan_dlg = NULL;
4970 static ProgressBar *scan_pbar = NULL;
4971 static HBox *scan_tbox = NULL;
4972 static Gtk::Button *scan_timeout_button;
4975 ARDOUR_UI::cancel_plugin_scan ()
4977 PluginManager::instance().cancel_plugin_scan();
4981 ARDOUR_UI::cancel_plugin_timeout ()
4983 PluginManager::instance().cancel_plugin_timeout();
4984 scan_timeout_button->set_sensitive (false);
4988 ARDOUR_UI::plugin_scan_timeout (int timeout)
4990 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4994 scan_pbar->set_sensitive (false);
4995 scan_timeout_button->set_sensitive (true);
4996 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4999 scan_pbar->set_sensitive (false);
5000 scan_timeout_button->set_sensitive (false);
5006 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5008 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5012 const bool cancelled = PluginManager::instance().cancelled();
5013 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5014 if (cancelled && scan_dlg->is_mapped()) {
5019 if (cancelled || !can_cancel) {
5024 static Gtk::Button *cancel_button;
5026 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5027 VBox* vbox = scan_dlg->get_vbox();
5028 vbox->set_size_request(400,-1);
5029 scan_dlg->set_title (_("Scanning for plugins"));
5031 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5032 cancel_button->set_name ("EditorGTKButton");
5033 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5034 cancel_button->show();
5036 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5038 scan_tbox = manage( new HBox() );
5040 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5041 scan_timeout_button->set_name ("EditorGTKButton");
5042 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5043 scan_timeout_button->show();
5045 scan_pbar = manage(new ProgressBar());
5046 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5047 scan_pbar->set_text(_("Scan Timeout"));
5050 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5051 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5053 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5056 assert(scan_dlg && scan_tbox && cancel_button);
5058 if (type == X_("closeme")) {
5062 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5065 if (!can_cancel || !cancelled) {
5066 scan_timeout_button->set_sensitive(false);
5068 cancel_button->set_sensitive(can_cancel && !cancelled);
5074 ARDOUR_UI::gui_idle_handler ()
5077 /* due to idle calls, gtk_events_pending() may always return true */
5078 while (gtk_events_pending() && --timeout) {
5079 gtk_main_iteration ();
5084 ARDOUR_UI::disk_underrun_handler ()
5086 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5088 if (!have_disk_speed_dialog_displayed) {
5089 have_disk_speed_dialog_displayed = true;
5090 MessageDialog* msg = new MessageDialog (
5091 _main_window, string_compose (_("The disk system on your computer\n\
5092 was not able to keep up with %1.\n\
5094 Specifically, it failed to read data from disk\n\
5095 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5096 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5102 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5104 have_disk_speed_dialog_displayed = false;
5109 ARDOUR_UI::session_dialog (std::string msg)
5111 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5115 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5122 ARDOUR_UI::pending_state_dialog ()
5124 HBox* hbox = manage (new HBox());
5125 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5126 ArdourDialog dialog (_("Crash Recovery"), true);
5127 Label message (string_compose (_("\
5128 This session appears to have been in the\n\
5129 middle of recording when %1 or\n\
5130 the computer was shutdown.\n\
5132 %1 can recover any captured audio for\n\
5133 you, or it can ignore it. Please decide\n\
5134 what you would like to do.\n"), PROGRAM_NAME));
5135 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5136 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5137 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5138 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5139 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5140 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5141 dialog.set_default_response (RESPONSE_ACCEPT);
5142 dialog.set_position (WIN_POS_CENTER);
5147 switch (dialog.run ()) {
5148 case RESPONSE_ACCEPT:
5156 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5158 HBox* hbox = new HBox();
5159 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5160 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5161 Label message (string_compose (_("\
5162 This session was created with a sample rate of %1 Hz, but\n\
5163 %2 is currently running at %3 Hz. If you load this session,\n\
5164 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5166 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5167 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5168 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5169 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5170 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5171 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5172 dialog.set_default_response (RESPONSE_ACCEPT);
5173 dialog.set_position (WIN_POS_CENTER);
5178 switch (dialog.run()) {
5179 case RESPONSE_ACCEPT:
5189 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5191 MessageDialog msg (string_compose (_("\
5192 This session was created with a sample rate of %1 Hz, but\n\
5193 %2 is currently running at %3 Hz.\n\
5194 Audio will be recorded and played at the wrong sample rate.\n\
5195 Re-Configure the Audio Engine in\n\
5196 Menu > Window > Audio/Midi Setup"),
5197 desired, PROGRAM_NAME, actual),
5199 Gtk::MESSAGE_WARNING);
5204 ARDOUR_UI::use_config ()
5206 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5208 set_transport_controllable_state (*node);
5213 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5215 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5217 primary_clock->set (pos);
5219 case DeltaEditPoint:
5220 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5222 case DeltaOriginMarker:
5224 Location* loc = _session->locations()->clock_origin_location ();
5225 primary_clock->set (pos, false, loc ? loc->start() : 0);
5230 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5232 secondary_clock->set (pos);
5234 case DeltaEditPoint:
5235 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5237 case DeltaOriginMarker:
5239 Location* loc = _session->locations()->clock_origin_location ();
5240 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5245 if (big_clock_window) {
5246 big_clock->set (pos);
5248 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5253 ARDOUR_UI::record_state_changed ()
5255 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5258 /* why bother - the clock isn't visible */
5262 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5264 if (big_clock_window) {
5265 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5266 big_clock->set_active (true);
5268 big_clock->set_active (false);
5275 ARDOUR_UI::first_idle ()
5278 _session->allow_auto_play (true);
5282 editor->first_idle();
5285 /* in 1 second, hide the splash screen
5287 * Consider hiding it *now*. If a user opens opens a dialog
5288 * during that one second while the splash is still visible,
5289 * the dialog will push-back the splash.
5290 * Closing the dialog later will pop it back.
5292 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5294 Keyboard::set_can_save_keybindings (true);
5299 ARDOUR_UI::store_clock_modes ()
5301 XMLNode* node = new XMLNode(X_("ClockModes"));
5303 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5304 XMLNode* child = new XMLNode (X_("Clock"));
5306 child->set_property (X_("name"), (*x)->name());
5307 child->set_property (X_("mode"), (*x)->mode());
5308 child->set_property (X_("on"), (*x)->on());
5310 node->add_child_nocopy (*child);
5313 _session->add_extra_xml (*node);
5314 _session->set_dirty ();
5318 ARDOUR_UI::setup_profile ()
5320 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5321 Profile->set_small_screen ();
5324 if (g_getenv ("TRX")) {
5325 Profile->set_trx ();
5328 if (g_getenv ("MIXBUS")) {
5329 Profile->set_mixbus ();
5334 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5336 MissingFileDialog dialog (s, str, type);
5341 int result = dialog.run ();
5348 return 1; // quit entire session load
5351 result = dialog.get_action ();
5357 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5359 AmbiguousFileDialog dialog (file, hits);
5366 return dialog.get_which ();
5369 /** Allocate our thread-local buffers */
5371 ARDOUR_UI::get_process_buffers ()
5373 _process_thread->get_buffers ();
5376 /** Drop our thread-local buffers */
5378 ARDOUR_UI::drop_process_buffers ()
5380 _process_thread->drop_buffers ();
5384 ARDOUR_UI::feedback_detected ()
5386 _feedback_exists = true;
5390 ARDOUR_UI::successful_graph_sort ()
5392 _feedback_exists = false;
5396 ARDOUR_UI::midi_panic ()
5399 _session->midi_panic();
5404 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5406 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5407 const char* end_big = "</span>";
5408 const char* start_mono = "<tt>";
5409 const char* end_mono = "</tt>";
5411 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5412 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5413 "From now on, use the backup copy with older versions of %3"),
5414 xml_path, backup_path, PROGRAM_NAME,
5416 start_mono, end_mono), true);
5422 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5424 using namespace Menu_Helpers;
5426 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5427 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5428 i->set_active (editor_meter->meter_type () == type);
5432 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5434 using namespace Gtk::Menu_Helpers;
5436 Gtk::Menu* m = manage (new Menu);
5437 MenuList& items = m->items ();
5439 RadioMenuItem::Group group;
5441 _suspend_editor_meter_callbacks = true;
5442 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5443 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5444 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5445 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5446 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5447 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5448 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5449 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5450 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5451 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5452 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5454 m->popup (ev->button, ev->time);
5455 _suspend_editor_meter_callbacks = false;
5459 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5461 if (ev->button == 3 && editor_meter) {
5462 popup_editor_meter_menu (ev);
5469 ARDOUR_UI::reset_peak_display ()
5471 if (!_session || !_session->master_out() || !editor_meter) return;
5472 editor_meter->clear_meters();
5473 editor_meter_max_peak = -INFINITY;
5474 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5478 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5480 if (!_session || !_session->master_out()) return;
5481 if (group == _session->master_out()->route_group()) {
5482 reset_peak_display ();
5487 ARDOUR_UI::reset_route_peak_display (Route* route)
5489 if (!_session || !_session->master_out()) return;
5490 if (_session->master_out().get() == route) {
5491 reset_peak_display ();
5496 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5498 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5499 audio_midi_setup->set_position (WIN_POS_CENTER);
5501 if (desired_sample_rate != 0) {
5502 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5503 audio_midi_setup->try_autostart ();
5504 if (ARDOUR::AudioEngine::instance()->running()) {
5511 int response = audio_midi_setup->run();
5513 case Gtk::RESPONSE_DELETE_EVENT:
5514 // after latency callibration engine may run,
5515 // Running() signal was emitted, but dialog will not
5516 // have emitted a response. The user needs to close
5517 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5518 if (!AudioEngine::instance()->running()) {
5523 if (!AudioEngine::instance()->running()) {
5526 audio_midi_setup->hide ();
5534 ARDOUR_UI::transport_numpad_timeout ()
5536 _numpad_locate_happening = false;
5537 if (_numpad_timeout_connection.connected() )
5538 _numpad_timeout_connection.disconnect();
5543 ARDOUR_UI::transport_numpad_decimal ()
5545 _numpad_timeout_connection.disconnect();
5547 if (_numpad_locate_happening) {
5548 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5549 _numpad_locate_happening = false;
5551 _pending_locate_num = 0;
5552 _numpad_locate_happening = true;
5553 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5558 ARDOUR_UI::transport_numpad_event (int num)
5560 if ( _numpad_locate_happening ) {
5561 _pending_locate_num = _pending_locate_num*10 + num;
5564 case 0: toggle_roll(false, false); break;
5565 case 1: transport_rewind(1); break;
5566 case 2: transport_forward(1); break;
5567 case 3: transport_record(true); break;
5568 case 4: toggle_session_auto_loop(); break;
5569 case 5: transport_record(false); toggle_session_auto_loop(); break;
5570 case 6: toggle_punch(); break;
5571 case 7: toggle_click(); break;
5572 case 8: toggle_auto_return(); break;
5573 case 9: toggle_follow_edits(); break;
5579 ARDOUR_UI::set_flat_buttons ()
5581 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5585 ARDOUR_UI::audioengine_became_silent ()
5587 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5589 Gtk::MESSAGE_WARNING,
5593 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5595 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5596 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5597 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5598 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5599 Gtk::HBox pay_button_box;
5600 Gtk::HBox subscribe_button_box;
5602 pay_button_box.pack_start (pay_button, true, false);
5603 subscribe_button_box.pack_start (subscribe_button, true, false);
5605 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 */
5607 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5608 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5610 msg.get_vbox()->pack_start (pay_label);
5611 msg.get_vbox()->pack_start (pay_button_box);
5612 msg.get_vbox()->pack_start (subscribe_label);
5613 msg.get_vbox()->pack_start (subscribe_button_box);
5615 msg.get_vbox()->show_all ();
5617 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5618 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5619 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5624 case Gtk::RESPONSE_YES:
5625 AudioEngine::instance()->reset_silence_countdown ();
5628 case Gtk::RESPONSE_NO:
5630 save_state_canfail ("");
5634 case Gtk::RESPONSE_CANCEL:
5636 /* don't reset, save session and exit */
5642 ARDOUR_UI::hide_application ()
5644 Application::instance ()-> hide ();
5648 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5650 /* icons, titles, WM stuff */
5652 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5654 if (window_icons.empty()) {
5655 Glib::RefPtr<Gdk::Pixbuf> icon;
5656 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5657 window_icons.push_back (icon);
5659 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5660 window_icons.push_back (icon);
5662 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5663 window_icons.push_back (icon);
5665 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5666 window_icons.push_back (icon);
5670 if (!window_icons.empty()) {
5671 window.set_default_icon_list (window_icons);
5674 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5676 if (!name.empty()) {
5680 window.set_title (title.get_string());
5681 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5683 window.set_flags (CAN_FOCUS);
5684 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5686 /* This is a hack to ensure that GTK-accelerators continue to
5687 * work. Once we switch over to entirely native bindings, this will be
5688 * unnecessary and should be removed
5690 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5692 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5693 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5694 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5695 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5699 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5701 Gtkmm2ext::Bindings* bindings = 0;
5702 Gtk::Window* window = 0;
5704 /* until we get ardour bindings working, we are not handling key
5708 if (ev->type != GDK_KEY_PRESS) {
5712 if (event_window == &_main_window) {
5714 window = event_window;
5716 /* find current tab contents */
5718 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5720 /* see if it uses the ardour binding system */
5723 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5726 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5730 window = event_window;
5732 /* see if window uses ardour binding system */
5734 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5737 /* An empty binding set is treated as if it doesn't exist */
5739 if (bindings && bindings->empty()) {
5743 return key_press_focus_accelerator_handler (*window, ev, bindings);
5746 static Gtkmm2ext::Bindings*
5747 get_bindings_from_widget_heirarchy (GtkWidget** w)
5752 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5755 *w = gtk_widget_get_parent (*w);
5758 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5762 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5764 GtkWindow* win = window.gobj();
5765 GtkWidget* focus = gtk_window_get_focus (win);
5766 GtkWidget* binding_widget = focus;
5767 bool special_handling_of_unmodified_accelerators = false;
5768 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5772 /* some widget has keyboard focus */
5774 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5776 /* A particular kind of focusable widget currently has keyboard
5777 * focus. All unmodified key events should go to that widget
5778 * first and not be used as an accelerator by default
5781 special_handling_of_unmodified_accelerators = true;
5785 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5786 if (focus_bindings) {
5787 bindings = focus_bindings;
5788 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5793 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",
5796 Gtkmm2ext::show_gdk_event_state (ev->state),
5797 special_handling_of_unmodified_accelerators,
5798 Keyboard::some_magic_widget_has_focus(),
5800 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5801 ((ev->state & mask) ? "yes" : "no"),
5802 window.get_title()));
5804 /* This exists to allow us to override the way GTK handles
5805 key events. The normal sequence is:
5807 a) event is delivered to a GtkWindow
5808 b) accelerators/mnemonics are activated
5809 c) if (b) didn't handle the event, propagate to
5810 the focus widget and/or focus chain
5812 The problem with this is that if the accelerators include
5813 keys without modifiers, such as the space bar or the
5814 letter "e", then pressing the key while typing into
5815 a text entry widget results in the accelerator being
5816 activated, instead of the desired letter appearing
5819 There is no good way of fixing this, but this
5820 represents a compromise. The idea is that
5821 key events involving modifiers (not Shift)
5822 get routed into the activation pathway first, then
5823 get propagated to the focus widget if necessary.
5825 If the key event doesn't involve modifiers,
5826 we deliver to the focus widget first, thus allowing
5827 it to get "normal text" without interference
5830 Of course, this can also be problematic: if there
5831 is a widget with focus, then it will swallow
5832 all "normal text" accelerators.
5836 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5838 /* no special handling or there are modifiers in effect: accelerate first */
5840 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5841 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5842 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5844 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5845 KeyboardKey k (ev->state, ev->keyval);
5849 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5851 if (bindings->activate (k, Bindings::Press)) {
5852 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5856 if (binding_widget) {
5857 binding_widget = gtk_widget_get_parent (binding_widget);
5858 if (binding_widget) {
5859 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5868 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5870 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5871 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5875 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5877 if (gtk_window_propagate_key_event (win, ev)) {
5878 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5884 /* no modifiers, propagate first */
5886 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5888 if (gtk_window_propagate_key_event (win, ev)) {
5889 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5893 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5894 KeyboardKey k (ev->state, ev->keyval);
5898 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5901 if (bindings->activate (k, Bindings::Press)) {
5902 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5906 if (binding_widget) {
5907 binding_widget = gtk_widget_get_parent (binding_widget);
5908 if (binding_widget) {
5909 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5918 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
5920 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5921 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5926 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5931 ARDOUR_UI::cancel_solo ()
5934 _session->cancel_all_solo ();
5939 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5941 /* this resets focus to the first focusable parent of the given widget,
5942 * or, if there is no focusable parent, cancels focus in the toplevel
5943 * window that the given widget is packed into (if there is one).
5950 Gtk::Widget* top = w->get_toplevel();
5952 if (!top || !top->is_toplevel()) {
5956 w = w->get_parent ();
5960 if (w->is_toplevel()) {
5961 /* Setting the focus widget to a Gtk::Window causes all
5962 * subsequent calls to ::has_focus() on the nominal
5963 * focus widget in that window to return
5964 * false. Workaround: never set focus to the toplevel
5970 if (w->get_can_focus ()) {
5971 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5972 win->set_focus (*w);
5975 w = w->get_parent ();
5978 if (top == &_main_window) {
5982 /* no focusable parent found, cancel focus in top level window.
5983 C++ API cannot be used for this. Thanks, references.
5986 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
5991 ARDOUR_UI::monitor_dim_all ()
5993 boost::shared_ptr<Route> mon = _session->monitor_out ();
5997 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5999 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
6000 _monitor->set_dim_all (tact->get_active());
6004 ARDOUR_UI::monitor_cut_all ()
6006 boost::shared_ptr<Route> mon = _session->monitor_out ();
6010 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6012 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
6013 _monitor->set_cut_all (tact->get_active());
6017 ARDOUR_UI::monitor_mono ()
6019 boost::shared_ptr<Route> mon = _session->monitor_out ();
6023 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6025 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
6026 _monitor->set_mono (tact->get_active());