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"
83 #include "ardour/ardour.h"
84 #include "ardour/audio_backend.h"
85 #include "ardour/audio_track.h"
86 #include "ardour/audioengine.h"
87 #include "ardour/audiofilesource.h"
88 #include "ardour/automation_watch.h"
89 #include "ardour/disk_reader.h"
90 #include "ardour/disk_writer.h"
91 #include "ardour/filename_extensions.h"
92 #include "ardour/filesystem_paths.h"
93 #include "ardour/ltc_file_reader.h"
94 #include "ardour/midi_track.h"
95 #include "ardour/port.h"
96 #include "ardour/plugin_manager.h"
97 #include "ardour/process_thread.h"
98 #include "ardour/profile.h"
99 #include "ardour/recent_sessions.h"
100 #include "ardour/record_enable_control.h"
101 #include "ardour/revision.h"
102 #include "ardour/session_directory.h"
103 #include "ardour/session_route.h"
104 #include "ardour/session_state_utils.h"
105 #include "ardour/session_utils.h"
106 #include "ardour/source_factory.h"
107 #include "ardour/slave.h"
108 #include "ardour/system_exec.h"
109 #include "ardour/track.h"
110 #include "ardour/vca_manager.h"
111 #include "ardour/utils.h"
113 #include "LuaBridge/LuaBridge.h"
115 #ifdef WINDOWS_VST_SUPPORT
118 #ifdef AUDIOUNIT_SUPPORT
119 #include "ardour/audio_unit.h"
122 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
127 #include "temporal/time.h"
129 typedef uint64_t microseconds_t;
133 #include "enums_convert.h"
135 #include "add_route_dialog.h"
136 #include "ambiguous_file_dialog.h"
137 #include "ardour_ui.h"
138 #include "audio_clock.h"
139 #include "audio_region_view.h"
140 #include "big_clock_window.h"
141 #include "big_transport_window.h"
142 #include "bundle_manager.h"
143 #include "duplicate_routes_dialog.h"
145 #include "engine_dialog.h"
146 #include "export_video_dialog.h"
147 #include "export_video_infobox.h"
148 #include "gain_meter.h"
149 #include "global_port_matrix.h"
150 #include "gui_object.h"
151 #include "gui_thread.h"
152 #include "idleometer.h"
153 #include "keyboard.h"
154 #include "keyeditor.h"
155 #include "location_ui.h"
156 #include "lua_script_manager.h"
157 #include "luawindow.h"
158 #include "main_clock.h"
159 #include "missing_file_dialog.h"
160 #include "missing_plugin_dialog.h"
161 #include "mixer_ui.h"
162 #include "meterbridge.h"
163 #include "meter_patterns.h"
164 #include "mouse_cursors.h"
167 #include "pingback.h"
168 #include "processor_box.h"
169 #include "public_editor.h"
170 #include "rc_option_editor.h"
171 #include "route_time_axis.h"
172 #include "route_params_ui.h"
173 #include "save_as_dialog.h"
174 #include "save_template_dialog.h"
175 #include "script_selector.h"
176 #include "session_archive_dialog.h"
177 #include "session_dialog.h"
178 #include "session_metadata_dialog.h"
179 #include "session_option_editor.h"
180 #include "speaker_dialog.h"
183 #include "template_dialog.h"
184 #include "time_axis_view_item.h"
185 #include "time_info_box.h"
188 #include "utils_videotl.h"
189 #include "video_server_dialog.h"
190 #include "add_video_dialog.h"
191 #include "transcode_video_dialog.h"
193 #include "pbd/i18n.h"
195 using namespace ARDOUR;
196 using namespace ARDOUR_UI_UTILS;
198 using namespace Gtkmm2ext;
199 using namespace ArdourWidgets;
202 using namespace Editing;
204 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
206 sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
207 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
210 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
212 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
213 "Would you like these files to be copied and used for %1 %2.x?\n\n"
214 "(This will require you to restart %1.)"),
215 PROGRAM_NAME, PROGRAM_VERSION, version),
216 false, /* no markup */
219 true /* modal, though it hardly matters since it is the only window */
222 msg.set_default_response (Gtk::RESPONSE_YES);
225 return (msg.run() == Gtk::RESPONSE_YES);
229 libxml_generic_error_func (void* /* parsing_context*/,
237 vsnprintf (buf, sizeof (buf), msg, ap);
238 error << buf << endmsg;
243 libxml_structured_error_func (void* /* parsing_context*/,
251 replace_all (msg, "\n", "");
254 if (err->file && err->line) {
255 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
258 error << ':' << err->int2;
263 error << X_("XML error: ") << msg << endmsg;
269 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
270 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
271 , session_loaded (false)
272 , session_load_in_progress (false)
273 , gui_object_state (new GUIObjectState)
274 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
275 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
276 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
278 , global_actions (X_("global"))
279 , ignore_dual_punch (false)
280 , main_window_visibility (0)
285 , _mixer_on_top (false)
286 , _initial_verbose_plugin_scan (false)
287 , first_time_engine_run (true)
288 , secondary_clock_spacer (0)
289 , auto_input_button (ArdourButton::led_default_elements)
291 , auto_return_button (ArdourButton::led_default_elements)
292 , follow_edits_button (ArdourButton::led_default_elements)
293 , auditioning_alert_button (_("Audition"))
294 , solo_alert_button (_("Solo"))
295 , feedback_alert_button (_("Feedback"))
296 , error_alert_button ( ArdourButton::just_led_default_elements )
297 , editor_meter_peak_display()
299 , _suspend_editor_meter_callbacks (false)
300 , _numpad_locate_happening (false)
301 , _session_is_new (false)
302 , last_key_press_time (0)
306 , rc_option_editor (0)
307 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
308 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
309 , about (X_("about"), _("About"))
310 , location_ui (X_("locations"), S_("Ranges|Locations"))
311 , route_params (X_("inspector"), _("Tracks and Busses"))
312 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
313 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
314 , lua_script_window (X_("script-manager"), _("Script Manager"))
315 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
316 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
317 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
318 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
319 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
320 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
321 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
322 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
323 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
324 , video_server_process (0)
326 , have_configure_timeout (false)
327 , last_configure_time (0)
329 , have_disk_speed_dialog_displayed (false)
330 , _status_bar_visibility (X_("status-bar"))
331 , _feedback_exists (false)
332 , _log_not_acknowledged (LogLevelNone)
333 , duplicate_routes_dialog (0)
334 , editor_visibility_button (S_("Window|Editor"))
335 , mixer_visibility_button (S_("Window|Mixer"))
336 , prefs_visibility_button (S_("Window|Preferences"))
338 Gtkmm2ext::init (localedir);
340 UIConfiguration::instance().post_gui_init ();
342 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
344 /* "touch" the been-here-before path now that config has been migrated */
345 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
347 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
349 /* configuration was modified, exit immediately */
354 if (string (VERSIONSTRING).find (".pre") != string::npos) {
355 /* check this is not being run from ./ardev etc. */
356 if (!running_from_source_tree ()) {
357 pre_release_dialog ();
361 if (theArdourUI == 0) {
365 /* track main window visibility */
367 main_window_visibility = new VisibilityTracker (_main_window);
369 /* stop libxml from spewing to stdout/stderr */
371 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
372 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
374 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
375 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
376 UIConfiguration::instance().map_parameters (pc);
378 transport_ctrl.setup (this);
380 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
381 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
383 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
385 /* handle dialog requests */
387 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
389 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
391 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
393 /* handle Audio/MIDI setup when session requires it */
395 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
397 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
399 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
401 /* handle sr mismatch with a dialog - cross-thread from engine */
402 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
404 /* handle requests to quit (coming from JACK session) */
406 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
408 /* tell the user about feedback */
410 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
411 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
413 /* handle requests to deal with missing files */
415 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
417 /* and ambiguous files */
419 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
421 /* also plugin scan messages */
422 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
423 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
425 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
427 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
430 /* lets get this party started */
432 setup_gtk_ardour_enums ();
435 SessionEvent::create_per_thread_pool ("GUI", 4096);
437 /* we like keyboards */
439 keyboard = new ArdourKeyboard(*this);
441 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
443 keyboard->set_state (*node, Stateful::loading_state_version);
446 UIConfiguration::instance().reset_dpi ();
448 TimeAxisViewItem::set_constant_heights ();
450 /* Set this up so that our window proxies can register actions */
452 ActionManager::init ();
454 /* The following must happen after ARDOUR::init() so that Config is set up */
456 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
459 key_editor.set_state (*ui_xml, 0);
460 session_option_editor.set_state (*ui_xml, 0);
461 speaker_config_window.set_state (*ui_xml, 0);
462 about.set_state (*ui_xml, 0);
463 add_route_dialog.set_state (*ui_xml, 0);
464 add_video_dialog.set_state (*ui_xml, 0);
465 route_params.set_state (*ui_xml, 0);
466 bundle_manager.set_state (*ui_xml, 0);
467 location_ui.set_state (*ui_xml, 0);
468 big_clock_window.set_state (*ui_xml, 0);
469 big_transport_window.set_state (*ui_xml, 0);
470 audio_port_matrix.set_state (*ui_xml, 0);
471 midi_port_matrix.set_state (*ui_xml, 0);
472 export_video_dialog.set_state (*ui_xml, 0);
473 lua_script_window.set_state (*ui_xml, 0);
474 idleometer.set_state (*ui_xml, 0);
477 /* Separate windows */
479 WM::Manager::instance().register_window (&key_editor);
480 WM::Manager::instance().register_window (&session_option_editor);
481 WM::Manager::instance().register_window (&speaker_config_window);
482 WM::Manager::instance().register_window (&about);
483 WM::Manager::instance().register_window (&add_route_dialog);
484 WM::Manager::instance().register_window (&add_video_dialog);
485 WM::Manager::instance().register_window (&route_params);
486 WM::Manager::instance().register_window (&audio_midi_setup);
487 WM::Manager::instance().register_window (&export_video_dialog);
488 WM::Manager::instance().register_window (&lua_script_window);
489 WM::Manager::instance().register_window (&bundle_manager);
490 WM::Manager::instance().register_window (&location_ui);
491 WM::Manager::instance().register_window (&big_clock_window);
492 WM::Manager::instance().register_window (&big_transport_window);
493 WM::Manager::instance().register_window (&audio_port_matrix);
494 WM::Manager::instance().register_window (&midi_port_matrix);
495 WM::Manager::instance().register_window (&idleometer);
497 /* do not retain position for add route dialog */
498 add_route_dialog.set_state_mask (WindowProxy::Size);
500 /* Trigger setting up the color scheme and loading the GTK RC file */
502 UIConfiguration::instance().load_rc_file (false);
504 _process_thread = new ProcessThread ();
505 _process_thread->init ();
507 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
513 ARDOUR_UI::pre_release_dialog ()
515 ArdourDialog d (_("Pre-Release Warning"), true, false);
516 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
518 Label* label = manage (new Label);
519 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
520 There are still several issues and bugs to be worked on,\n\
521 as well as general workflow improvements, before this can be considered\n\
522 release software. So, a few guidelines:\n\
524 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
525 though it may be so, depending on your workflow.\n\
526 2) Please wait for a helpful writeup of new features.\n\
527 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
528 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
529 making sure to note the product version number as 6.0-pre.\n\
530 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
531 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
532 can get there directly from within the program via the Help->Chat menu option.\n\
534 Full information on all the above can be found on the support page at\n\
536 http://ardour.org/support\n\
537 "), PROGRAM_NAME, VERSIONSTRING));
539 d.get_vbox()->set_border_width (12);
540 d.get_vbox()->pack_start (*label, false, false, 12);
541 d.get_vbox()->show_all ();
546 GlobalPortMatrixWindow*
547 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
552 return new GlobalPortMatrixWindow (_session, type);
556 ARDOUR_UI::attach_to_engine ()
558 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
559 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
563 ARDOUR_UI::engine_stopped ()
565 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
566 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
567 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
568 update_sample_rate (0);
573 ARDOUR_UI::engine_running ()
575 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
576 if (first_time_engine_run) {
578 first_time_engine_run = false;
582 _session->reset_xrun_count ();
584 update_disk_space ();
586 update_xrun_count ();
587 update_sample_rate (AudioEngine::instance()->sample_rate());
588 update_timecode_format ();
589 update_peak_thread_work ();
590 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
591 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
595 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
597 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
598 /* we can't rely on the original string continuing to exist when we are called
599 again in the GUI thread, so make a copy and note that we need to
602 char *copy = strdup (reason);
603 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
607 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
608 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
610 update_sample_rate (0);
614 /* if the reason is a non-empty string, it means that the backend was shutdown
615 rather than just Ardour.
618 if (strlen (reason)) {
619 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
621 msgstr = string_compose (_("\
622 The audio backend has either been shutdown or it\n\
623 disconnected %1 because %1\n\
624 was not fast enough. Try to restart\n\
625 the audio backend and save the session."), PROGRAM_NAME);
628 MessageDialog msg (_main_window, msgstr);
629 pop_back_splash (msg);
633 free (const_cast<char*> (reason));
638 ARDOUR_UI::post_engine ()
640 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
642 #ifdef AUDIOUNIT_SUPPORT
644 if (AUPluginInfo::au_get_crashlog(au_msg)) {
645 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
646 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
647 info << au_msg << endmsg;
651 ARDOUR::init_post_engine ();
653 /* connect to important signals */
655 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
656 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
657 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
658 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
659 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
661 if (setup_windows ()) {
662 throw failed_constructor ();
665 transport_ctrl.map_actions ();
667 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
668 XMLNode* n = Config->extra_xml (X_("UI"));
670 _status_bar_visibility.set_state (*n);
673 check_memory_locking();
675 /* this is the first point at which all the possible actions are
676 * available, because some of the available actions are dependent on
677 * aspects of the engine/backend.
680 if (ARDOUR_COMMAND_LINE::show_key_actions) {
682 Bindings::save_all_bindings_as_html (sstr);
684 if (sstr.str().empty()) {
691 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
693 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
699 #ifdef PLATFORM_WINDOWS
705 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
706 #ifndef PLATFORM_WINDOWS
709 g_unlink (file_name);
711 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
717 #ifndef PLATFORM_WINDOWS
721 PBD::open_uri (string_compose ("file:///%1", file_name));
723 halt_connection.disconnect ();
724 AudioEngine::instance()->stop ();
729 if (ARDOUR_COMMAND_LINE::show_actions) {
732 vector<string> paths;
733 vector<string> labels;
734 vector<string> tooltips;
736 vector<Glib::RefPtr<Gtk::Action> > actions;
737 string ver_in = revision;
738 string ver = ver_in.substr(0, ver_in.find("-"));
741 output << "\n<h2>Menu actions</h2>" << endl;
742 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
743 output << " surfaces or scripts.\n</p>\n" << endl;
744 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
745 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
746 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
747 output << "<table class=\"dl\">\n <thead>" << endl;
748 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
749 output << " </thead>\n <tbody>" << endl;
751 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
753 vector<string>::iterator p;
754 vector<string>::iterator l;
756 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
757 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (10, string::npos);
758 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
760 output << " </tbody>\n </table>" << endl;
762 // output this mess to a browser for easiest X-platform use
763 // it is not pretty HTML, but it works and it's main purpose
764 // is to create raw html to fit in Ardour's manual with no editing
769 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
771 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
777 #ifdef PLATFORM_WINDOWS
783 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
784 #ifndef PLATFORM_WINDOWS
787 g_unlink (file_name);
789 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
795 #ifndef PLATFORM_WINDOWS
799 PBD::open_uri (string_compose ("file:///%1", file_name));
801 halt_connection.disconnect ();
802 AudioEngine::instance()->stop ();
806 /* this being a GUI and all, we want peakfiles */
808 AudioFileSource::set_build_peakfiles (true);
809 AudioFileSource::set_build_missing_peakfiles (true);
811 /* set default clock modes */
813 primary_clock->set_mode (AudioClock::Timecode);
814 secondary_clock->set_mode (AudioClock::BBT);
816 /* start the time-of-day-clock */
819 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
820 update_wall_clock ();
821 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
826 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
827 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
828 Config->map_parameters (pc);
830 UIConfiguration::instance().map_parameters (pc);
834 ARDOUR_UI::~ARDOUR_UI ()
836 UIConfiguration::instance().save_state();
840 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
841 // don't bother at 'real' exit. the OS cleans up for us.
842 delete big_clock; big_clock = 0;
843 delete primary_clock; primary_clock = 0;
844 delete secondary_clock; secondary_clock = 0;
845 delete _process_thread; _process_thread = 0;
846 delete time_info_box; time_info_box = 0;
847 delete meterbridge; meterbridge = 0;
848 delete luawindow; luawindow = 0;
849 delete editor; editor = 0;
850 delete mixer; mixer = 0;
851 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
853 delete gui_object_state; gui_object_state = 0;
854 delete main_window_visibility;
855 FastMeter::flush_pattern_cache ();
856 ArdourFader::flush_pattern_cache ();
860 /* Small trick to flush main-thread event pool.
861 * Other thread-pools are destroyed at pthread_exit(),
862 * but tmain thread termination is too late to trigger Pool::~Pool()
864 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.
865 delete ev->event_pool();
870 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
872 if (Splash::instance()) {
873 Splash::instance()->pop_back_for (win);
878 ARDOUR_UI::configure_timeout ()
880 if (last_configure_time == 0) {
881 /* no configure events yet */
885 /* force a gap of 0.5 seconds since the last configure event
888 if (get_microseconds() - last_configure_time < 500000) {
891 have_configure_timeout = false;
892 save_ardour_state ();
898 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
900 if (have_configure_timeout) {
901 last_configure_time = get_microseconds();
903 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
904 have_configure_timeout = true;
911 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
915 if (node.get_property ("roll", str)){
916 roll_controllable->set_id (str);
918 if (node.get_property ("stop", str)) {
919 stop_controllable->set_id (str);
921 if (node.get_property ("goto-start", str)) {
922 goto_start_controllable->set_id (str);
924 if (node.get_property ("goto-end", str)) {
925 goto_end_controllable->set_id (str);
927 if (node.get_property ("auto-loop", str)) {
928 auto_loop_controllable->set_id (str);
930 if (node.get_property ("play-selection", str)) {
931 play_selection_controllable->set_id (str);
933 if (node.get_property ("rec", str)) {
934 rec_controllable->set_id (str);
936 if (node.get_property ("shuttle", str)) {
937 shuttle_box.controllable()->set_id (str);
942 ARDOUR_UI::get_transport_controllable_state ()
944 XMLNode* node = new XMLNode(X_("TransportControllables"));
946 node->set_property (X_("roll"), roll_controllable->id());
947 node->set_property (X_("stop"), stop_controllable->id());
948 node->set_property (X_("goto-start"), goto_start_controllable->id());
949 node->set_property (X_("goto-end"), goto_end_controllable->id());
950 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
951 node->set_property (X_("play-selection"), play_selection_controllable->id());
952 node->set_property (X_("rec"), rec_controllable->id());
953 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
959 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
962 _session->save_state (snapshot_name);
967 ARDOUR_UI::autosave_session ()
969 if (g_main_depth() > 1) {
970 /* inside a recursive main loop,
971 give up because we may not be able to
977 if (!Config->get_periodic_safety_backups()) {
982 _session->maybe_write_autosave();
989 ARDOUR_UI::session_dirty_changed ()
996 ARDOUR_UI::update_autosave ()
998 if (_session && _session->dirty()) {
999 if (_autosave_connection.connected()) {
1000 _autosave_connection.disconnect();
1003 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1004 Config->get_periodic_safety_backup_interval() * 1000);
1007 if (_autosave_connection.connected()) {
1008 _autosave_connection.disconnect();
1014 ARDOUR_UI::check_announcements ()
1017 string _annc_filename;
1020 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1021 #elif defined PLATFORM_WINDOWS
1022 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1024 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1026 _annc_filename.append (VERSIONSTRING);
1028 _announce_string = "";
1030 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1031 FILE* fin = g_fopen (path.c_str(), "rb");
1033 while (!feof (fin)) {
1036 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1039 _announce_string.append (tmp, len);
1044 pingback (VERSIONSTRING, path);
1049 _hide_splash (gpointer arg)
1051 ((ARDOUR_UI*)arg)->hide_splash();
1056 ARDOUR_UI::starting ()
1058 Application* app = Application::instance ();
1059 const char *nsm_url;
1060 bool brand_new_user = ArdourStartup::required ();
1062 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1063 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1065 if (ARDOUR_COMMAND_LINE::check_announcements) {
1066 check_announcements ();
1071 /* we need to create this early because it may need to set the
1072 * audio backend end up.
1076 audio_midi_setup.get (true);
1078 std::cerr << "audio-midi engine setup failed."<< std::endl;
1082 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1083 nsm = new NSM_Client;
1084 if (!nsm->init (nsm_url)) {
1085 /* the ardour executable may have different names:
1087 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1088 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1089 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1091 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1093 const char *process_name = g_getenv ("ARDOUR_SELF");
1094 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1097 // wait for announce reply from nsm server
1098 for ( i = 0; i < 5000; ++i) {
1102 if (nsm->is_active()) {
1107 error << _("NSM server did not announce itself") << endmsg;
1110 // wait for open command from nsm server
1111 for ( i = 0; i < 5000; ++i) {
1113 Glib::usleep (1000);
1114 if (nsm->client_id ()) {
1120 error << _("NSM: no client ID provided") << endmsg;
1124 if (_session && nsm) {
1125 _session->set_nsm_state( nsm->is_active() );
1127 error << _("NSM: no session created") << endmsg;
1131 // nsm requires these actions disabled
1132 vector<string> action_names;
1133 action_names.push_back("SaveAs");
1134 action_names.push_back("Rename");
1135 action_names.push_back("New");
1136 action_names.push_back("Open");
1137 action_names.push_back("Recent");
1138 action_names.push_back("Close");
1140 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1141 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1143 act->set_sensitive (false);
1150 error << _("NSM: initialization failed") << endmsg;
1156 if (brand_new_user) {
1157 _initial_verbose_plugin_scan = true;
1162 _initial_verbose_plugin_scan = false;
1163 switch (s.response ()) {
1164 case Gtk::RESPONSE_OK:
1171 // TODO: maybe IFF brand_new_user
1172 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1173 std::string dspd (Config->get_default_session_parent_dir());
1174 Searchpath ds (ARDOUR::ardour_data_search_path());
1175 ds.add_subdirectory_to_paths ("sessions");
1176 vector<string> demos;
1177 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1179 ARDOUR::RecentSessions rs;
1180 ARDOUR::read_recent_sessions (rs);
1182 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1183 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1184 std::string name = basename_nosuffix (basename_nosuffix (*i));
1185 std::string path = Glib::build_filename (dspd, name);
1186 /* skip if session-dir already exists */
1187 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1190 /* skip sessions that are already in 'recent'.
1191 * eg. a new user changed <session-default-dir> shorly after installation
1193 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1194 if ((*r).first == name) {
1199 PBD::FileArchive ar (*i);
1200 if (0 == ar.inflate (dspd)) {
1201 store_recent_sessions (name, path);
1202 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1208 #ifdef NO_PLUGIN_STATE
1210 ARDOUR::RecentSessions rs;
1211 ARDOUR::read_recent_sessions (rs);
1213 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1215 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1217 /* already used Ardour, have sessions ... warn about plugin state */
1219 ArdourDialog d (_("Free/Demo Version Warning"), true);
1221 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1222 CheckButton c (_("Don't warn me about this again"));
1224 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"),
1225 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1226 _("It will not restore OR save any plugin settings"),
1227 _("If you load an existing session with plugin settings\n"
1228 "they will not be used and will be lost."),
1229 _("To get full access to updates without this limitation\n"
1230 "consider becoming a subscriber for a low cost every month.")));
1231 l.set_justify (JUSTIFY_CENTER);
1233 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1235 d.get_vbox()->pack_start (l, true, true);
1236 d.get_vbox()->pack_start (b, false, false, 12);
1237 d.get_vbox()->pack_start (c, false, false, 12);
1239 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1240 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1244 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1246 if (d.run () != RESPONSE_OK) {
1252 /* go get a session */
1254 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1256 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1257 std::cerr << "Cannot get session parameters."<< std::endl;
1264 WM::Manager::instance().show_visible ();
1266 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1267 * editor window, and we may want stuff to be hidden.
1269 _status_bar_visibility.update ();
1271 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1273 /* all other dialogs are created conditionally */
1279 ARDOUR_UI::check_memory_locking ()
1281 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1282 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1286 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1288 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1290 struct rlimit limits;
1292 long pages, page_size;
1294 size_t pages_len=sizeof(pages);
1295 if ((page_size = getpagesize()) < 0 ||
1296 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1298 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1303 ram = (int64_t) pages * (int64_t) page_size;
1306 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1310 if (limits.rlim_cur != RLIM_INFINITY) {
1312 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1316 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1317 "This might cause %1 to run out of memory before your system "
1318 "runs out of memory. \n\n"
1319 "You can view the memory limit with 'ulimit -l', "
1320 "and it is normally controlled by %2"),
1323 X_("/etc/login.conf")
1325 X_(" /etc/security/limits.conf")
1329 msg.set_default_response (RESPONSE_OK);
1331 VBox* vbox = msg.get_vbox();
1333 CheckButton cb (_("Do not show this window again"));
1334 hbox.pack_start (cb, true, false);
1335 vbox->pack_start (hbox);
1340 pop_back_splash (msg);
1344 if (cb.get_active()) {
1345 XMLNode node (X_("no-memory-warning"));
1346 Config->add_instant_xml (node);
1351 #endif // !__APPLE__
1356 ARDOUR_UI::queue_finish ()
1358 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1362 ARDOUR_UI::idle_finish ()
1365 return false; /* do not call again */
1372 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1374 if (_session->dirty()) {
1375 vector<string> actions;
1376 actions.push_back (_("Don't quit"));
1377 actions.push_back (_("Just quit"));
1378 actions.push_back (_("Save and quit"));
1379 switch (ask_about_saving_session(actions)) {
1384 /* use the default name */
1385 if (save_state_canfail ("")) {
1386 /* failed - don't quit */
1387 MessageDialog msg (_main_window,
1388 string_compose (_("\
1389 %1 was unable to save your session.\n\n\
1390 If you still wish to quit, please use the\n\n\
1391 \"Just quit\" option."), PROGRAM_NAME));
1392 pop_back_splash(msg);
1402 second_connection.disconnect ();
1403 point_one_second_connection.disconnect ();
1404 point_zero_something_second_connection.disconnect();
1405 fps_connection.disconnect();
1408 delete ARDOUR_UI::instance()->video_timeline;
1409 ARDOUR_UI::instance()->video_timeline = NULL;
1410 stop_video_server();
1412 /* Save state before deleting the session, as that causes some
1413 windows to be destroyed before their visible state can be
1416 save_ardour_state ();
1418 if (key_editor.get (false)) {
1419 key_editor->disconnect ();
1422 close_all_dialogs ();
1425 _session->set_clean ();
1426 _session->remove_pending_capture_state ();
1431 halt_connection.disconnect ();
1432 AudioEngine::instance()->stop ();
1433 #ifdef WINDOWS_VST_SUPPORT
1434 fst_stop_threading();
1440 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1442 ArdourDialog window (_("Unsaved Session"));
1443 Gtk::HBox dhbox; // the hbox for the image and text
1444 Gtk::Label prompt_label;
1445 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1449 assert (actions.size() >= 3);
1451 window.add_button (actions[0], RESPONSE_REJECT);
1452 window.add_button (actions[1], RESPONSE_APPLY);
1453 window.add_button (actions[2], RESPONSE_ACCEPT);
1455 window.set_default_response (RESPONSE_ACCEPT);
1457 Gtk::Button noquit_button (msg);
1458 noquit_button.set_name ("EditorGTKButton");
1462 if (_session->snap_name() == _session->name()) {
1463 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?"),
1464 _session->snap_name());
1466 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?"),
1467 _session->snap_name());
1470 prompt_label.set_text (prompt);
1471 prompt_label.set_name (X_("PrompterLabel"));
1472 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1474 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1475 dhbox.set_homogeneous (false);
1476 dhbox.pack_start (*dimage, false, false, 5);
1477 dhbox.pack_start (prompt_label, true, false, 5);
1478 window.get_vbox()->pack_start (dhbox);
1480 window.set_name (_("Prompter"));
1481 window.set_modal (true);
1482 window.set_resizable (false);
1485 prompt_label.show();
1490 ResponseType r = (ResponseType) window.run();
1495 case RESPONSE_ACCEPT: // save and get out of here
1497 case RESPONSE_APPLY: // get out of here
1508 ARDOUR_UI::every_second ()
1511 update_xrun_count ();
1512 update_buffer_load ();
1513 update_disk_space ();
1514 update_timecode_format ();
1515 update_peak_thread_work ();
1517 if (nsm && nsm->is_active ()) {
1520 if (!_was_dirty && _session->dirty ()) {
1524 else if (_was_dirty && !_session->dirty ()){
1532 ARDOUR_UI::every_point_one_seconds ()
1534 if (editor) editor->build_region_boundary_cache();
1538 ARDOUR_UI::every_point_zero_something_seconds ()
1540 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1542 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1543 float mpeak = editor_meter->update_meters();
1544 if (mpeak > editor_meter_max_peak) {
1545 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1546 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1553 ARDOUR_UI::set_fps_timeout_connection ()
1555 unsigned int interval = 40;
1556 if (!_session) return;
1557 if (_session->timecode_frames_per_second() != 0) {
1558 /* ideally we'll use a select() to sleep and not accumulate
1559 * idle time to provide a regular periodic signal.
1560 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1561 * However, that'll require a dedicated thread and cross-thread
1562 * signals to the GUI Thread..
1564 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1565 * _session->sample_rate() / _session->nominal_sample_rate()
1566 / _session->timecode_frames_per_second()
1568 #ifdef PLATFORM_WINDOWS
1569 // the smallest windows scheduler time-slice is ~15ms.
1570 // periodic GUI timeouts shorter than that will cause
1571 // WaitForSingleObject to spinlock (100% of one CPU Core)
1572 // and gtk never enters idle mode.
1573 // also changing timeBeginPeriod(1) does not affect that in
1574 // any beneficial way, so we just limit the max rate for now.
1575 interval = std::max(30u, interval); // at most ~33Hz.
1577 interval = std::max(8u, interval); // at most 120Hz.
1580 fps_connection.disconnect();
1581 Timers::set_fps_interval (interval);
1585 ARDOUR_UI::update_sample_rate (samplecnt_t)
1589 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1591 if (!AudioEngine::instance()->connected()) {
1593 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1597 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1600 /* no sample rate available */
1601 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1604 if (fmod (rate, 1000.0) != 0.0) {
1605 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1606 (float) rate / 1000.0f,
1607 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1609 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1611 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1615 sample_rate_label.set_markup (buf);
1619 ARDOUR_UI::update_format ()
1622 format_label.set_text ("");
1627 s << _("File:") << X_(" <span foreground=\"green\">");
1629 switch (_session->config.get_native_file_header_format ()) {
1661 switch (_session->config.get_native_file_data_format ()) {
1675 format_label.set_markup (s.str ());
1679 ARDOUR_UI::update_xrun_count ()
1683 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1684 should also be changed.
1688 const unsigned int x = _session->get_xrun_count ();
1689 dsp_load_indicator.set_xrun_count (x);
1691 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1693 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1696 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1697 dsp_load_indicator.set_xrun_count (UINT_MAX);
1699 xrun_label.set_markup (buf);
1700 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1704 ARDOUR_UI::update_cpu_load ()
1708 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1709 should also be changed.
1712 double const c = AudioEngine::instance()->get_dsp_load ();
1713 dsp_load_indicator.set_dsp_load (c);
1714 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1715 cpu_load_label.set_markup (buf);
1719 ARDOUR_UI::update_peak_thread_work ()
1722 const int c = SourceFactory::peak_work_queue_length ();
1724 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1725 peak_thread_work_label.set_markup (buf);
1727 peak_thread_work_label.set_markup (X_(""));
1732 ARDOUR_UI::update_buffer_load ()
1736 uint32_t const playback = _session ? _session->playback_load () : 100;
1737 uint32_t const capture = _session ? _session->capture_load () : 100;
1739 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1740 should also be changed.
1746 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1747 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1748 playback <= 5 ? X_("red") : X_("green"),
1750 capture <= 5 ? X_("red") : X_("green"),
1754 buffer_load_label.set_markup (buf);
1756 buffer_load_label.set_text ("");
1761 ARDOUR_UI::count_recenabled_streams (Route& route)
1763 Track* track = dynamic_cast<Track*>(&route);
1764 if (track && track->rec_enable_control()->get_value()) {
1765 rec_enabled_streams += track->n_inputs().n_total();
1770 ARDOUR_UI::update_disk_space()
1772 if (_session == 0) {
1773 disk_space_indicator.set_available_disk_sec (-1);
1777 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1779 samplecnt_t fr = _session->sample_rate();
1782 /* skip update - no SR available */
1783 disk_space_indicator.set_available_disk_sec (-1);
1788 /* Available space is unknown */
1789 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1790 disk_space_indicator.set_available_disk_sec (-1);
1791 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1792 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1793 disk_space_indicator.set_available_disk_sec (max_samplecnt);
1795 rec_enabled_streams = 0;
1796 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1798 samplecnt_t samples = opt_samples.get_value_or (0);
1800 if (rec_enabled_streams) {
1801 samples /= rec_enabled_streams;
1808 disk_space_indicator.set_available_disk_sec (samples / (float)fr);
1810 hrs = samples / (fr * 3600);
1813 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1815 samples -= hrs * fr * 3600;
1816 mins = samples / (fr * 60);
1817 samples -= mins * fr * 60;
1818 secs = samples / fr;
1820 bool const low = (hrs == 0 && mins <= 30);
1824 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1825 low ? X_("red") : X_("green"),
1831 disk_space_label.set_markup (buf);
1835 ARDOUR_UI::update_timecode_format ()
1841 TimecodeSlave* tcslave;
1842 SyncSource sync_src = Config->get_sync_source();
1844 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1845 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1850 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1851 matching ? X_("green") : X_("red"),
1852 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1854 snprintf (buf, sizeof (buf), "TC: n/a");
1857 timecode_format_label.set_markup (buf);
1861 ARDOUR_UI::update_wall_clock ()
1865 static int last_min = -1;
1868 tm_now = localtime (&now);
1869 if (last_min != tm_now->tm_min) {
1871 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1872 wall_clock_label.set_text (buf);
1873 last_min = tm_now->tm_min;
1880 ARDOUR_UI::open_recent_session ()
1882 bool can_return = (_session != 0);
1884 SessionDialog recent_session_dialog;
1888 ResponseType r = (ResponseType) recent_session_dialog.run ();
1891 case RESPONSE_ACCEPT:
1895 recent_session_dialog.hide();
1902 recent_session_dialog.hide();
1906 std::string path = recent_session_dialog.session_folder();
1907 std::string state = recent_session_dialog.session_name (should_be_new);
1909 if (should_be_new == true) {
1913 _session_is_new = false;
1915 if (load_session (path, state) == 0) {
1924 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1926 if (!AudioEngine::instance()->connected()) {
1927 MessageDialog msg (parent, string_compose (
1928 _("%1 is not connected to any audio backend.\n"
1929 "You cannot open or close sessions in this condition"),
1931 pop_back_splash (msg);
1939 ARDOUR_UI::open_session ()
1941 if (!check_audioengine (_main_window)) {
1945 /* ardour sessions are folders */
1946 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1947 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1948 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1949 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1952 string session_parent_dir = Glib::path_get_dirname(_session->path());
1953 open_session_selector.set_current_folder(session_parent_dir);
1955 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1958 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1960 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1961 string default_session_folder = Config->get_default_session_parent_dir();
1962 open_session_selector.add_shortcut_folder (default_session_folder);
1964 catch (Glib::Error const& e) {
1965 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1968 FileFilter session_filter;
1969 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1970 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1971 open_session_selector.add_filter (session_filter);
1973 FileFilter archive_filter;
1974 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1975 archive_filter.set_name (_("Session Archives"));
1977 open_session_selector.add_filter (archive_filter);
1979 open_session_selector.set_filter (session_filter);
1981 int response = open_session_selector.run();
1982 open_session_selector.hide ();
1984 if (response == Gtk::RESPONSE_CANCEL) {
1988 string session_path = open_session_selector.get_filename();
1992 if (session_path.length() > 0) {
1993 int rv = ARDOUR::inflate_session (session_path,
1994 Config->get_default_session_parent_dir(), path, name);
1996 _session_is_new = false;
1997 load_session (path, name);
2000 MessageDialog msg (_main_window,
2001 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2004 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2005 _session_is_new = isnew;
2006 load_session (path, name);
2012 ARDOUR_UI::session_add_mixed_track (
2013 const ChanCount& input,
2014 const ChanCount& output,
2015 RouteGroup* route_group,
2017 const string& name_template,
2019 PluginInfoPtr instrument,
2020 Plugin::PresetRecord* pset,
2021 ARDOUR::PresentationInfo::order_t order)
2025 if (Profile->get_mixbus ()) {
2030 list<boost::shared_ptr<MidiTrack> > tracks;
2031 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2033 if (tracks.size() != how_many) {
2034 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2039 display_insufficient_ports_message ();
2045 ARDOUR_UI::session_add_midi_bus (
2046 RouteGroup* route_group,
2048 const string& name_template,
2050 PluginInfoPtr instrument,
2051 Plugin::PresetRecord* pset,
2052 ARDOUR::PresentationInfo::order_t order)
2054 if (_session == 0) {
2055 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2059 if (Profile->get_mixbus ()) {
2065 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2066 if (routes.size() != how_many) {
2067 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2072 display_insufficient_ports_message ();
2078 ARDOUR_UI::session_add_midi_route (
2080 RouteGroup* route_group,
2082 const string& name_template,
2084 PluginInfoPtr instrument,
2085 Plugin::PresetRecord* pset,
2086 ARDOUR::PresentationInfo::order_t order)
2088 ChanCount one_midi_channel;
2089 one_midi_channel.set (DataType::MIDI, 1);
2092 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2094 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2099 ARDOUR_UI::session_add_audio_route (
2101 int32_t input_channels,
2102 int32_t output_channels,
2103 ARDOUR::TrackMode mode,
2104 RouteGroup* route_group,
2106 string const & name_template,
2108 ARDOUR::PresentationInfo::order_t order)
2110 list<boost::shared_ptr<AudioTrack> > tracks;
2117 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2119 if (tracks.size() != how_many) {
2120 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2126 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2128 if (routes.size() != how_many) {
2129 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2136 display_insufficient_ports_message ();
2141 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2142 (*i)->set_strict_io (true);
2144 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2145 (*i)->set_strict_io (true);
2151 ARDOUR_UI::display_insufficient_ports_message ()
2153 MessageDialog msg (_main_window,
2154 string_compose (_("There are insufficient ports available\n\
2155 to create a new track or bus.\n\
2156 You should save %1, exit and\n\
2157 restart with more ports."), PROGRAM_NAME));
2158 pop_back_splash (msg);
2163 ARDOUR_UI::transport_goto_start ()
2166 _session->goto_start();
2168 /* force displayed area in editor to start no matter
2169 what "follow playhead" setting is.
2173 editor->center_screen (_session->current_start_sample ());
2179 ARDOUR_UI::transport_goto_zero ()
2182 _session->request_locate (0);
2184 /* force displayed area in editor to start no matter
2185 what "follow playhead" setting is.
2189 editor->reset_x_origin (0);
2195 ARDOUR_UI::transport_goto_wallclock ()
2197 if (_session && editor) {
2201 samplepos_t samples;
2204 localtime_r (&now, &tmnow);
2206 samplecnt_t sample_rate = _session->sample_rate();
2208 if (sample_rate == 0) {
2209 /* no frame rate available */
2213 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2214 samples += tmnow.tm_min * (60 * sample_rate);
2215 samples += tmnow.tm_sec * sample_rate;
2217 _session->request_locate (samples, _session->transport_rolling ());
2219 /* force displayed area in editor to start no matter
2220 what "follow playhead" setting is.
2224 editor->center_screen (samples);
2230 ARDOUR_UI::transport_goto_end ()
2233 samplepos_t const sample = _session->current_end_sample();
2234 _session->request_locate (sample);
2236 /* force displayed area in editor to start no matter
2237 what "follow playhead" setting is.
2241 editor->center_screen (sample);
2247 ARDOUR_UI::transport_stop ()
2253 if (_session->is_auditioning()) {
2254 _session->cancel_audition ();
2258 _session->request_stop (false, true);
2261 /** Check if any tracks are record enabled. If none are, record enable all of them.
2262 * @return true if track record-enabled status was changed, false otherwise.
2265 ARDOUR_UI::trx_record_enable_all_tracks ()
2271 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2272 bool none_record_enabled = true;
2274 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2275 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2278 if (t->rec_enable_control()->get_value()) {
2279 none_record_enabled = false;
2284 if (none_record_enabled) {
2285 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2288 return none_record_enabled;
2292 ARDOUR_UI::transport_record (bool roll)
2295 switch (_session->record_status()) {
2296 case Session::Disabled:
2297 if (_session->ntracks() == 0) {
2298 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."));
2302 if (Profile->get_trx()) {
2303 roll = trx_record_enable_all_tracks ();
2305 _session->maybe_enable_record ();
2310 case Session::Recording:
2312 _session->request_stop();
2314 _session->disable_record (false, true);
2318 case Session::Enabled:
2319 _session->disable_record (false, true);
2325 ARDOUR_UI::transport_roll ()
2331 if (_session->is_auditioning()) {
2336 if (_session->config.get_external_sync()) {
2337 switch (Config->get_sync_source()) {
2341 /* transport controlled by the master */
2347 bool rolling = _session->transport_rolling();
2349 if (_session->get_play_loop()) {
2351 /* If loop playback is not a mode, then we should cancel
2352 it when this action is requested. If it is a mode
2353 we just leave it in place.
2356 if (!Config->get_loop_is_mode()) {
2357 /* XXX it is not possible to just leave seamless loop and keep
2358 playing at present (nov 4th 2009)
2360 if (!Config->get_seamless_loop()) {
2361 /* stop loop playback and stop rolling */
2362 _session->request_play_loop (false, true);
2363 } else if (rolling) {
2364 /* stop loop playback but keep rolling */
2365 _session->request_play_loop (false, false);
2369 } else if (_session->get_play_range () ) {
2370 /* stop playing a range if we currently are */
2371 _session->request_play_range (0, true);
2375 _session->request_transport_speed (1.0f);
2380 ARDOUR_UI::get_smart_mode() const
2382 return ( editor->get_smart_mode() );
2387 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2393 if (_session->is_auditioning()) {
2394 _session->cancel_audition ();
2398 if (_session->config.get_external_sync()) {
2399 switch (Config->get_sync_source()) {
2403 /* transport controlled by the master */
2408 bool rolling = _session->transport_rolling();
2409 bool affect_transport = true;
2411 if (rolling && roll_out_of_bounded_mode) {
2412 /* drop out of loop/range playback but leave transport rolling */
2413 if (_session->get_play_loop()) {
2414 if (_session->actively_recording()) {
2416 /* just stop using the loop, then actually stop
2419 _session->request_play_loop (false, affect_transport);
2422 if (Config->get_seamless_loop()) {
2423 /* the disk buffers contain copies of the loop - we can't
2424 just keep playing, so stop the transport. the user
2425 can restart as they wish.
2427 affect_transport = true;
2429 /* disk buffers are normal, so we can keep playing */
2430 affect_transport = false;
2432 _session->request_play_loop (false, affect_transport);
2434 } else if (_session->get_play_range ()) {
2435 affect_transport = false;
2436 _session->request_play_range (0, true);
2440 if (affect_transport) {
2442 _session->request_stop (with_abort, true);
2444 } else if (!with_abort) { /* with_abort == true means the
2445 * command was intended to stop
2446 * transport, not start.
2449 /* the only external sync condition we can be in here
2450 * would be Engine (JACK) sync, in which case we still
2454 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
2455 _session->request_play_range (&editor->get_selection().time, true);
2456 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2458 _session->request_transport_speed (1.0f);
2464 ARDOUR_UI::toggle_session_auto_loop ()
2470 Location * looploc = _session->locations()->auto_loop_location();
2476 if (_session->get_play_loop()) {
2478 /* looping enabled, our job is to disable it */
2480 _session->request_play_loop (false);
2484 /* looping not enabled, our job is to enable it.
2486 loop-is-NOT-mode: this action always starts the transport rolling.
2487 loop-IS-mode: this action simply sets the loop play mechanism, but
2488 does not start transport.
2490 if (Config->get_loop_is_mode()) {
2491 _session->request_play_loop (true, false);
2493 _session->request_play_loop (true, true);
2497 //show the loop markers
2498 looploc->set_hidden (false, this);
2502 ARDOUR_UI::transport_play_selection ()
2508 editor->play_selection ();
2512 ARDOUR_UI::transport_play_preroll ()
2517 editor->play_with_preroll ();
2521 ARDOUR_UI::transport_rec_preroll ()
2526 editor->rec_with_preroll ();
2530 ARDOUR_UI::transport_rec_count_in ()
2535 editor->rec_with_count_in ();
2539 ARDOUR_UI::transport_rewind (int option)
2541 float current_transport_speed;
2544 current_transport_speed = _session->transport_speed();
2546 if (current_transport_speed >= 0.0f) {
2549 _session->request_transport_speed (-1.0f);
2552 _session->request_transport_speed (-4.0f);
2555 _session->request_transport_speed (-0.5f);
2560 _session->request_transport_speed (current_transport_speed * 1.5f);
2566 ARDOUR_UI::transport_forward (int option)
2572 float current_transport_speed = _session->transport_speed();
2574 if (current_transport_speed <= 0.0f) {
2577 _session->request_transport_speed (1.0f);
2580 _session->request_transport_speed (4.0f);
2583 _session->request_transport_speed (0.5f);
2588 _session->request_transport_speed (current_transport_speed * 1.5f);
2593 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2599 boost::shared_ptr<Route> r;
2601 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2603 boost::shared_ptr<Track> t;
2605 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2606 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2612 ARDOUR_UI::map_transport_state ()
2615 layered_button.set_sensitive (false);
2619 shuttle_box.map_transport_state ();
2621 float sp = _session->transport_speed();
2624 layered_button.set_sensitive (!_session->actively_recording ());
2626 layered_button.set_sensitive (true);
2627 update_disk_space ();
2632 ARDOUR_UI::blink_handler (bool blink_on)
2634 sync_blink (blink_on);
2636 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2639 error_blink (blink_on);
2640 solo_blink (blink_on);
2641 audition_blink (blink_on);
2642 feedback_blink (blink_on);
2644 dsp_load_indicator.blink(blink_on);
2645 disk_space_indicator.blink(blink_on);
2649 ARDOUR_UI::update_clocks ()
2651 if (!_session) return;
2653 if (editor && !editor->dragging_playhead()) {
2654 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2659 ARDOUR_UI::start_clocking ()
2661 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2662 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2664 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2669 ARDOUR_UI::stop_clocking ()
2671 clock_signal_connection.disconnect ();
2675 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2679 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2681 label->set_text (buf);
2682 bar->set_fraction (fraction);
2684 /* process events, redraws, etc. */
2686 while (gtk_events_pending()) {
2687 gtk_main_iteration ();
2690 return true; /* continue with save-as */
2694 ARDOUR_UI::save_session_as ()
2700 if (_session->dirty()) {
2701 vector<string> actions;
2702 actions.push_back (_("Abort save-as"));
2703 actions.push_back (_("Don't save now, just save-as"));
2704 actions.push_back (_("Save it first"));
2705 switch (ask_about_saving_session(actions)) {
2710 if (save_state_canfail ("")) {
2711 MessageDialog msg (_main_window,
2712 string_compose (_("\
2713 %1 was unable to save your session.\n\n\
2714 If you still wish to proceeed, please use the\n\n\
2715 \"Don't save now\" option."), PROGRAM_NAME));
2716 pop_back_splash(msg);
2722 _session->remove_pending_capture_state ();
2727 if (!save_as_dialog) {
2728 save_as_dialog = new SaveAsDialog;
2731 save_as_dialog->set_name (_session->name());
2733 int response = save_as_dialog->run ();
2735 save_as_dialog->hide ();
2738 case Gtk::RESPONSE_OK:
2747 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2748 sa.new_name = save_as_dialog->new_name ();
2749 sa.switch_to = save_as_dialog->switch_to();
2750 sa.copy_media = save_as_dialog->copy_media();
2751 sa.copy_external = save_as_dialog->copy_external();
2752 sa.include_media = save_as_dialog->include_media ();
2754 /* Only bother with a progress dialog if we're going to copy
2755 media into the save-as target. Without that choice, this
2756 will be very fast because we're only talking about a few kB's to
2757 perhaps a couple of MB's of data.
2760 ArdourDialog progress_dialog (_("Save As"), true);
2763 if (sa.include_media && sa.copy_media) {
2765 Gtk::Label* label = manage (new Gtk::Label());
2766 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2768 progress_dialog.get_vbox()->pack_start (*label);
2769 progress_dialog.get_vbox()->pack_start (*progress_bar);
2771 progress_bar->show ();
2773 /* this signal will be emitted from within this, the calling thread,
2774 * after every file is copied. It provides information on percentage
2775 * complete (in terms of total data to copy), the number of files
2776 * copied so far, and the total number to copy.
2779 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2781 progress_dialog.show_all ();
2782 progress_dialog.present ();
2785 if (_session->save_as (sa)) {
2787 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2791 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2792 * the trick is this: if the new session was copy with media included,
2793 * then Session::save_as() will have already done a neat trick to avoid
2794 * us having to unload and load the new state. But if the media was not
2795 * included, then this is required (it avoids us having to otherwise
2796 * drop all references to media (sources).
2799 if (!sa.include_media && sa.switch_to) {
2800 unload_session (false);
2801 load_session (sa.final_session_folder_name, sa.new_name);
2806 ARDOUR_UI::archive_session ()
2814 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2816 SessionArchiveDialog sad;
2817 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2818 int response = sad.run ();
2820 if (response != Gtk::RESPONSE_OK) {
2825 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2826 MessageDialog msg (_("Session Archiving failed."));
2832 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2836 struct tm local_time;
2839 localtime_r (&n, &local_time);
2840 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2841 if (switch_to_it && _session->dirty ()) {
2842 save_state_canfail ("");
2845 save_state (timebuf, switch_to_it);
2850 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2854 prompter.get_result (snapname);
2856 bool do_save = (snapname.length() != 0);
2859 char illegal = Session::session_name_is_legal(snapname);
2861 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2862 "snapshot names may not contain a '%1' character"), illegal));
2868 vector<std::string> p;
2869 get_state_files_in_directory (_session->session_directory().root_path(), p);
2870 vector<string> n = get_file_names_no_extension (p);
2872 if (find (n.begin(), n.end(), snapname) != n.end()) {
2874 do_save = overwrite_file_dialog (prompter,
2875 _("Confirm Snapshot Overwrite"),
2876 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2880 save_state (snapname, switch_to_it);
2890 /** Ask the user for the name of a new snapshot and then take it.
2894 ARDOUR_UI::snapshot_session (bool switch_to_it)
2896 if (switch_to_it && _session->dirty()) {
2897 vector<string> actions;
2898 actions.push_back (_("Abort saving snapshot"));
2899 actions.push_back (_("Don't save now, just snapshot"));
2900 actions.push_back (_("Save it first"));
2901 switch (ask_about_saving_session(actions)) {
2906 if (save_state_canfail ("")) {
2907 MessageDialog msg (_main_window,
2908 string_compose (_("\
2909 %1 was unable to save your session.\n\n\
2910 If you still wish to proceeed, please use the\n\n\
2911 \"Don't save now\" option."), PROGRAM_NAME));
2912 pop_back_splash(msg);
2918 _session->remove_pending_capture_state ();
2923 Prompter prompter (true);
2924 prompter.set_name ("Prompter");
2925 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2927 prompter.set_title (_("Snapshot and switch"));
2928 prompter.set_prompt (_("New session name"));
2930 prompter.set_title (_("Take Snapshot"));
2931 prompter.set_prompt (_("Name of new snapshot"));
2935 prompter.set_initial_text (_session->snap_name());
2937 Glib::DateTime tm (g_date_time_new_now_local ());
2938 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2941 bool finished = false;
2943 switch (prompter.run()) {
2944 case RESPONSE_ACCEPT:
2946 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2957 /** Ask the user for a new session name and then rename the session to it.
2961 ARDOUR_UI::rename_session ()
2967 Prompter prompter (true);
2970 prompter.set_name ("Prompter");
2971 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2972 prompter.set_title (_("Rename Session"));
2973 prompter.set_prompt (_("New session name"));
2976 switch (prompter.run()) {
2977 case RESPONSE_ACCEPT:
2979 prompter.get_result (name);
2981 bool do_rename = (name.length() != 0);
2984 char illegal = Session::session_name_is_legal (name);
2987 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2988 "session names may not contain a '%1' character"), illegal));
2993 switch (_session->rename (name)) {
2995 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2996 msg.set_position (WIN_POS_MOUSE);
3004 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3005 msg.set_position (WIN_POS_MOUSE);
3021 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3023 if (!_session || _session->deletion_in_progress()) {
3027 XMLNode* node = new XMLNode (X_("UI"));
3029 WM::Manager::instance().add_state (*node);
3031 node->add_child_nocopy (gui_object_state->get_state());
3033 _session->add_extra_xml (*node);
3035 if (export_video_dialog) {
3036 _session->add_extra_xml (export_video_dialog->get_state());
3039 save_state_canfail (name, switch_to_it);
3043 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3048 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3053 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3058 ARDOUR_UI::primary_clock_value_changed ()
3061 _session->request_locate (primary_clock->current_time ());
3066 ARDOUR_UI::big_clock_value_changed ()
3069 _session->request_locate (big_clock->current_time ());
3074 ARDOUR_UI::secondary_clock_value_changed ()
3077 _session->request_locate (secondary_clock->current_time ());
3081 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3083 if (response == RESPONSE_ACCEPT) {
3084 const string name = d->get_template_name ();
3085 const string desc = d->get_description ();
3087 int failed = _session->save_template (name, desc);
3089 if (failed == -2) { /* file already exists. */
3090 bool overwrite = overwrite_file_dialog (*d,
3091 _("Confirm Template Overwrite"),
3092 _("A template already exists with that name. Do you want to overwrite it?"));
3095 _session->save_template (name, desc, true);
3107 ARDOUR_UI::save_template ()
3109 if (!check_audioengine (_main_window)) {
3113 const std::string desc = SessionMetadata::Metadata()->description ();
3114 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3115 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3119 void ARDOUR_UI::manage_templates ()
3126 ARDOUR_UI::edit_metadata ()
3128 SessionMetadataEditor dialog;
3129 dialog.set_session (_session);
3130 dialog.grab_focus ();
3135 ARDOUR_UI::import_metadata ()
3137 SessionMetadataImporter dialog;
3138 dialog.set_session (_session);
3143 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3145 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3147 MessageDialog msg (str,
3149 Gtk::MESSAGE_WARNING,
3150 Gtk::BUTTONS_YES_NO,
3154 msg.set_name (X_("OpenExistingDialog"));
3155 msg.set_title (_("Open Existing Session"));
3156 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3157 msg.set_position (Gtk::WIN_POS_CENTER);
3158 pop_back_splash (msg);
3160 switch (msg.run()) {
3169 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3171 BusProfile bus_profile;
3174 bus_profile.master_out_channels = 2;
3176 /* get settings from advanced section of NSD */
3177 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3180 // NULL profile: no master, no monitor
3181 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3189 ARDOUR_UI::load_from_application_api (const std::string& path)
3191 /* OS X El Capitan (and probably later) now somehow passes the command
3192 line arguments to an app via the openFile delegate protocol. Ardour
3193 already does its own command line processing, and having both
3194 pathways active causes crashes. So, if the command line was already
3195 set, do nothing here.
3198 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3202 ARDOUR_COMMAND_LINE::session_name = path;
3204 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3206 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3208 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3209 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3210 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3211 * -> SessionDialog is not displayed
3214 if (_session_dialog) {
3215 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3216 std::string session_path = path;
3217 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3218 session_path = Glib::path_get_dirname (session_path);
3220 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3221 _session_dialog->set_provided_session (session_name, session_path);
3222 _session_dialog->response (RESPONSE_NONE);
3223 _session_dialog->hide();
3228 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3229 /* /path/to/foo => /path/to/foo, foo */
3230 rv = load_session (path, basename_nosuffix (path));
3232 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3233 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3236 // if load_session fails -> pop up SessionDialog.
3238 ARDOUR_COMMAND_LINE::session_name = "";
3240 if (get_session_parameters (true, false)) {
3246 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3248 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3250 string session_name;
3251 string session_path;
3252 string template_name;
3254 bool likely_new = false;
3255 bool cancel_not_quit;
3257 /* deal with any existing DIRTY session now, rather than later. don't
3258 * treat a non-dirty session this way, so that it stays visible
3259 * as we bring up the new session dialog.
3262 if (_session && ARDOUR_UI::instance()->video_timeline) {
3263 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3266 /* if there is already a session, relabel the button
3267 on the SessionDialog so that we don't Quit directly
3269 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3271 if (_session && _session->dirty()) {
3272 if (unload_session (false)) {
3273 /* unload cancelled by user */
3276 ARDOUR_COMMAND_LINE::session_name = "";
3279 if (!load_template.empty()) {
3280 should_be_new = true;
3281 template_name = load_template;
3284 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3285 session_path = ARDOUR_COMMAND_LINE::session_name;
3287 if (!session_path.empty()) {
3288 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3289 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3290 /* session/snapshot file, change path to be dir */
3291 session_path = Glib::path_get_dirname (session_path);
3296 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3298 _session_dialog = &session_dialog;
3301 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3303 /* if they named a specific statefile, use it, otherwise they are
3304 just giving a session folder, and we want to use it as is
3305 to find the session.
3308 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3310 if (suffix != string::npos) {
3311 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3312 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3313 session_name = Glib::path_get_basename (session_name);
3315 session_path = ARDOUR_COMMAND_LINE::session_name;
3316 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3321 session_dialog.clear_given ();
3324 if (should_be_new || session_name.empty()) {
3325 /* need the dialog to get info from user */
3327 cerr << "run dialog\n";
3329 switch (session_dialog.run()) {
3330 case RESPONSE_ACCEPT:
3333 /* this is used for async * app->ShouldLoad(). */
3334 continue; // while loop
3337 if (quit_on_cancel) {
3338 ARDOUR_UI::finish ();
3339 Gtkmm2ext::Application::instance()->cleanup();
3341 pthread_cancel_all ();
3342 return -1; // caller is responsible to call exit()
3348 session_dialog.hide ();
3351 /* if we run the startup dialog again, offer more than just "new session" */
3353 should_be_new = false;
3355 session_name = session_dialog.session_name (likely_new);
3356 session_path = session_dialog.session_folder ();
3363 int rv = ARDOUR::inflate_session (session_name,
3364 Config->get_default_session_parent_dir(), session_path, session_name);
3366 MessageDialog msg (session_dialog,
3367 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3372 session_dialog.set_provided_session (session_name, session_path);
3376 // XXX check archive, inflate
3377 string::size_type suffix = session_name.find (statefile_suffix);
3379 if (suffix != string::npos) {
3380 session_name = session_name.substr (0, suffix);
3383 /* this shouldn't happen, but we catch it just in case it does */
3385 if (session_name.empty()) {
3389 if (session_dialog.use_session_template()) {
3390 template_name = session_dialog.session_template_name();
3391 _session_is_new = true;
3394 if (session_name[0] == G_DIR_SEPARATOR ||
3395 #ifdef PLATFORM_WINDOWS
3396 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3398 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3399 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3404 /* absolute path or cwd-relative path specified for session name: infer session folder
3405 from what was given.
3408 session_path = Glib::path_get_dirname (session_name);
3409 session_name = Glib::path_get_basename (session_name);
3413 session_path = session_dialog.session_folder();
3415 char illegal = Session::session_name_is_legal (session_name);
3418 MessageDialog msg (session_dialog,
3419 string_compose (_("To ensure compatibility with various systems\n"
3420 "session names may not contain a '%1' character"),
3423 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3428 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3431 if (likely_new && !nsm) {
3433 std::string existing = Glib::build_filename (session_path, session_name);
3435 if (!ask_about_loading_existing_session (existing)) {
3436 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3441 _session_is_new = false;
3446 pop_back_splash (session_dialog);
3447 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3449 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3453 char illegal = Session::session_name_is_legal(session_name);
3456 pop_back_splash (session_dialog);
3457 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3458 "session names may not contain a '%1' character"), illegal));
3460 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3464 _session_is_new = true;
3467 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3469 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3470 meta_session_setup (template_name.substr (11));
3472 } else if (likely_new && template_name.empty()) {
3474 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3478 ret = load_session (session_path, session_name, template_name);
3481 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3485 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3486 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3490 /* clear this to avoid endless attempts to load the
3494 ARDOUR_COMMAND_LINE::session_name = "";
3498 _session_dialog = NULL;
3504 ARDOUR_UI::close_session()
3506 if (!check_audioengine (_main_window)) {
3510 if (unload_session (true)) {
3514 ARDOUR_COMMAND_LINE::session_name = "";
3516 if (get_session_parameters (true, false)) {
3521 /** @param snap_name Snapshot name (without .ardour suffix).
3522 * @return -2 if the load failed because we are not connected to the AudioEngine.
3525 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3527 /* load_session calls flush_pending() which allows
3528 * GUI interaction and potentially loading another session
3529 * (that was easy via snapshot sidebar).
3530 * Recursing into load_session() from load_session() and recusive
3531 * event loops causes all kind of crashes.
3533 assert (!session_load_in_progress);
3534 if (session_load_in_progress) {
3537 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3539 Session *new_session;
3544 unload_status = unload_session ();
3546 if (unload_status < 0) {
3548 } else if (unload_status > 0) {
3554 session_loaded = false;
3556 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3559 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3562 /* this one is special */
3564 catch (AudioEngine::PortRegistrationFailure const& err) {
3566 MessageDialog msg (err.what(),
3569 Gtk::BUTTONS_CLOSE);
3571 msg.set_title (_("Port Registration Error"));
3572 msg.set_secondary_text (_("Click the Close button to try again."));
3573 msg.set_position (Gtk::WIN_POS_CENTER);
3574 pop_back_splash (msg);
3577 int response = msg.run ();
3582 case RESPONSE_CANCEL:
3589 catch (SessionException const& e) {
3590 MessageDialog msg (string_compose(
3591 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3592 path, snap_name, e.what()),
3597 msg.set_title (_("Loading Error"));
3598 msg.set_position (Gtk::WIN_POS_CENTER);
3599 pop_back_splash (msg);
3611 MessageDialog msg (string_compose(
3612 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3618 msg.set_title (_("Loading Error"));
3619 msg.set_position (Gtk::WIN_POS_CENTER);
3620 pop_back_splash (msg);
3632 list<string> const u = new_session->unknown_processors ();
3634 MissingPluginDialog d (_session, u);
3639 if (!new_session->writable()) {
3640 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3645 msg.set_title (_("Read-only Session"));
3646 msg.set_position (Gtk::WIN_POS_CENTER);
3647 pop_back_splash (msg);
3654 /* Now the session been created, add the transport controls */
3655 new_session->add_controllable(roll_controllable);
3656 new_session->add_controllable(stop_controllable);
3657 new_session->add_controllable(goto_start_controllable);
3658 new_session->add_controllable(goto_end_controllable);
3659 new_session->add_controllable(auto_loop_controllable);
3660 new_session->add_controllable(play_selection_controllable);
3661 new_session->add_controllable(rec_controllable);
3663 set_session (new_session);
3665 session_loaded = true;
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 session_loaded = false;
3711 x = unload_session ();
3719 _session_is_new = true;
3722 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3725 catch (SessionException const& e) {
3726 cerr << "Here are the errors associated with this failed session:\n";
3728 cerr << "---------\n";
3729 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3730 msg.set_title (_("Loading Error"));
3731 msg.set_position (Gtk::WIN_POS_CENTER);
3732 pop_back_splash (msg);
3737 cerr << "Here are the errors associated with this failed session:\n";
3739 cerr << "---------\n";
3740 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3741 msg.set_title (_("Loading Error"));
3742 msg.set_position (Gtk::WIN_POS_CENTER);
3743 pop_back_splash (msg);
3748 /* Give the new session the default GUI state, if such things exist */
3751 n = Config->instant_xml (X_("Editor"));
3753 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3754 new_session->add_instant_xml (*n, false);
3756 n = Config->instant_xml (X_("Mixer"));
3758 new_session->add_instant_xml (*n, false);
3761 n = Config->instant_xml (X_("Preferences"));
3763 new_session->add_instant_xml (*n, false);
3766 /* Put the playhead at 0 and scroll fully left */
3767 n = new_session->instant_xml (X_("Editor"));
3769 n->set_property (X_("playhead"), X_("0"));
3770 n->set_property (X_("left-frame"), X_("0"));
3773 set_session (new_session);
3775 session_loaded = true;
3777 new_session->save_state(new_session->name());
3783 static void _lua_print (std::string s) {
3785 std::cout << "LuaInstance: " << s << "\n";
3787 PBD::info << "LuaInstance: " << s << endmsg;
3790 std::map<std::string, std::string>
3791 ARDOUR_UI::route_setup_info (const std::string& script_path)
3793 std::map<std::string, std::string> rv;
3795 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3800 lua.Print.connect (&_lua_print);
3803 lua_State* L = lua.getState();
3804 LuaInstance::register_classes (L);
3805 LuaBindings::set_session (L, _session);
3806 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3807 lua_setglobal (L, "Editor");
3809 lua.do_command ("function ardour () end");
3810 lua.do_file (script_path);
3813 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3814 if (!fn.isFunction ()) {
3817 luabridge::LuaRef rs = fn ();
3818 if (!rs.isTable ()) {
3821 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3822 if (!i.key().isString()) {
3825 std::string key = i.key().tostring();
3826 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3827 rv[key] = i.value().tostring();
3830 } catch (luabridge::LuaException const& e) {
3831 cerr << "LuaException:" << e.what () << endl;
3837 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3839 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3842 assert (add_route_dialog);
3845 if ((count = add_route_dialog->count()) <= 0) {
3850 lua.Print.connect (&_lua_print);
3853 lua_State* L = lua.getState();
3854 LuaInstance::register_classes (L);
3855 LuaBindings::set_session (L, _session);
3856 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3857 lua_setglobal (L, "Editor");
3859 lua.do_command ("function ardour () end");
3860 lua.do_file (script_path);
3862 luabridge::LuaRef args (luabridge::newTable (L));
3864 args["name"] = add_route_dialog->name_template ();
3865 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3866 args["group"] = add_route_dialog->route_group ();
3867 args["strict_io"] = add_route_dialog->use_strict_io ();
3868 args["instrument"] = add_route_dialog->requested_instrument ();
3869 args["track_mode"] = add_route_dialog->mode ();
3870 args["channels"] = add_route_dialog->channel_count ();
3871 args["how_many"] = count;
3874 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3875 if (fn.isFunction()) {
3878 } catch (luabridge::LuaException const& e) {
3879 cerr << "LuaException:" << e.what () << endl;
3881 display_insufficient_ports_message ();
3886 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3888 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3893 lua.Print.connect (&_lua_print);
3896 lua_State* L = lua.getState();
3897 LuaInstance::register_classes (L);
3898 LuaBindings::set_session (L, _session);
3899 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3900 lua_setglobal (L, "Editor");
3902 lua.do_command ("function ardour () end");
3903 lua.do_file (script_path);
3906 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3907 if (fn.isFunction()) {
3910 } catch (luabridge::LuaException const& e) {
3911 cerr << "LuaException:" << e.what () << endl;
3913 display_insufficient_ports_message ();
3918 ARDOUR_UI::launch_chat ()
3920 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3922 dialog.set_title (_("About the Chat"));
3923 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."));
3925 switch (dialog.run()) {
3928 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3929 #elif defined PLATFORM_WINDOWS
3930 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3932 open_uri("http://webchat.freenode.net/?channels=ardour");
3941 ARDOUR_UI::launch_manual ()
3943 PBD::open_uri (Config->get_tutorial_manual_url());
3947 ARDOUR_UI::launch_reference ()
3949 PBD::open_uri (Config->get_reference_manual_url());
3953 ARDOUR_UI::launch_tracker ()
3955 PBD::open_uri ("http://tracker.ardour.org");
3959 ARDOUR_UI::launch_subscribe ()
3961 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3965 ARDOUR_UI::launch_cheat_sheet ()
3968 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3970 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3975 ARDOUR_UI::launch_website ()
3977 PBD::open_uri ("http://ardour.org");
3981 ARDOUR_UI::launch_website_dev ()
3983 PBD::open_uri ("http://ardour.org/development.html");
3987 ARDOUR_UI::launch_forums ()
3989 PBD::open_uri ("https://community.ardour.org/forums");
3993 ARDOUR_UI::launch_howto_report ()
3995 PBD::open_uri ("http://ardour.org/reporting_bugs");
3999 ARDOUR_UI::loading_message (const std::string& msg)
4001 if (ARDOUR_COMMAND_LINE::no_splash) {
4009 splash->message (msg);
4013 ARDOUR_UI::show_splash ()
4017 splash = new Splash;
4027 ARDOUR_UI::hide_splash ()
4034 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4038 removed = rep.paths.size();
4041 MessageDialog msgd (_main_window,
4042 _("No files were ready for clean-up"),
4046 msgd.set_title (_("Clean-up"));
4047 msgd.set_secondary_text (_("If this seems surprising, \n\
4048 check for any existing snapshots.\n\
4049 These may still include regions that\n\
4050 require some unused files to continue to exist."));
4056 ArdourDialog results (_("Clean-up"), true, false);
4058 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4059 CleanupResultsModelColumns() {
4063 Gtk::TreeModelColumn<std::string> visible_name;
4064 Gtk::TreeModelColumn<std::string> fullpath;
4068 CleanupResultsModelColumns results_columns;
4069 Glib::RefPtr<Gtk::ListStore> results_model;
4070 Gtk::TreeView results_display;
4072 results_model = ListStore::create (results_columns);
4073 results_display.set_model (results_model);
4074 results_display.append_column (list_title, results_columns.visible_name);
4076 results_display.set_name ("CleanupResultsList");
4077 results_display.set_headers_visible (true);
4078 results_display.set_headers_clickable (false);
4079 results_display.set_reorderable (false);
4081 Gtk::ScrolledWindow list_scroller;
4084 Gtk::HBox dhbox; // the hbox for the image and text
4085 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4086 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4088 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4090 const string dead_directory = _session->session_directory().dead_path();
4093 %1 - number of files removed
4094 %2 - location of "dead"
4095 %3 - size of files affected
4096 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4099 const char* bprefix;
4100 double space_adjusted = 0;
4102 if (rep.space < 1000) {
4104 space_adjusted = rep.space;
4105 } else if (rep.space < 1000000) {
4106 bprefix = _("kilo");
4107 space_adjusted = floorf((float)rep.space / 1000.0);
4108 } else if (rep.space < 1000000 * 1000) {
4109 bprefix = _("mega");
4110 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4112 bprefix = _("giga");
4113 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4117 txt.set_markup (string_compose (P_("\
4118 The following file was deleted from %2,\n\
4119 releasing %3 %4bytes of disk space", "\
4120 The following %1 files were deleted from %2,\n\
4121 releasing %3 %4bytes of disk space", removed),
4122 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4124 txt.set_markup (string_compose (P_("\
4125 The following file was not in use and \n\
4126 has been moved to: %2\n\n\
4127 After a restart of %5\n\n\
4128 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4129 will release an additional %3 %4bytes of disk space.\n", "\
4130 The following %1 files were not in use and \n\
4131 have been moved to: %2\n\n\
4132 After a restart of %5\n\n\
4133 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4134 will release an additional %3 %4bytes of disk space.\n", removed),
4135 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4138 dhbox.pack_start (*dimage, true, false, 5);
4139 dhbox.pack_start (txt, true, false, 5);
4141 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4142 TreeModel::Row row = *(results_model->append());
4143 row[results_columns.visible_name] = *i;
4144 row[results_columns.fullpath] = *i;
4147 list_scroller.add (results_display);
4148 list_scroller.set_size_request (-1, 150);
4149 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4151 dvbox.pack_start (dhbox, true, false, 5);
4152 dvbox.pack_start (list_scroller, true, false, 5);
4153 ddhbox.pack_start (dvbox, true, false, 5);
4155 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4156 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4157 results.set_default_response (RESPONSE_CLOSE);
4158 results.set_position (Gtk::WIN_POS_MOUSE);
4160 results_display.show();
4161 list_scroller.show();
4168 //results.get_vbox()->show();
4169 results.set_resizable (false);
4176 ARDOUR_UI::cleanup ()
4178 if (_session == 0) {
4179 /* shouldn't happen: menu item is insensitive */
4184 MessageDialog checker (_("Are you sure you want to clean-up?"),
4186 Gtk::MESSAGE_QUESTION,
4189 checker.set_title (_("Clean-up"));
4191 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4192 ALL undo/redo information will be lost if you clean-up.\n\
4193 Clean-up will move all unused files to a \"dead\" location."));
4195 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4196 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4197 checker.set_default_response (RESPONSE_CANCEL);
4199 checker.set_name (_("CleanupDialog"));
4200 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4201 checker.set_position (Gtk::WIN_POS_MOUSE);
4203 switch (checker.run()) {
4204 case RESPONSE_ACCEPT:
4210 ARDOUR::CleanupReport rep;
4212 editor->prepare_for_cleanup ();
4214 /* do not allow flush until a session is reloaded */
4216 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4218 act->set_sensitive (false);
4221 if (_session->cleanup_sources (rep)) {
4222 editor->finish_cleanup ();
4226 editor->finish_cleanup ();
4229 display_cleanup_results (rep, _("Cleaned Files"), false);
4233 ARDOUR_UI::flush_trash ()
4235 if (_session == 0) {
4236 /* shouldn't happen: menu item is insensitive */
4240 ARDOUR::CleanupReport rep;
4242 if (_session->cleanup_trash_sources (rep)) {
4246 display_cleanup_results (rep, _("deleted file"), true);
4250 ARDOUR_UI::cleanup_peakfiles ()
4252 if (_session == 0) {
4253 /* shouldn't happen: menu item is insensitive */
4257 if (! _session->can_cleanup_peakfiles ()) {
4261 // get all region-views in this session
4263 TrackViewList empty;
4265 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4266 std::list<RegionView*> views = rs.by_layer();
4268 // remove displayed audio-region-views waveforms
4269 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4270 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4271 if (!arv) { continue ; }
4272 arv->delete_waves();
4275 // cleanup peak files:
4276 // - stop pending peakfile threads
4277 // - close peakfiles if any
4278 // - remove peak dir in session
4279 // - setup peakfiles (background thread)
4280 _session->cleanup_peakfiles ();
4282 // re-add waves to ARV
4283 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4284 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4285 if (!arv) { continue ; }
4286 arv->create_waves();
4290 PresentationInfo::order_t
4291 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4293 if (editor->get_selection().tracks.empty()) {
4294 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4297 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4300 we want the new routes to have their order keys set starting from
4301 the highest order key in the selection + 1 (if available).
4304 if (place == RouteDialogs::AfterSelection) {
4305 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4307 order_hint = rtav->route()->presentation_info().order();
4310 } else if (place == RouteDialogs::BeforeSelection) {
4311 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4313 order_hint = rtav->route()->presentation_info().order();
4315 } else if (place == RouteDialogs::First) {
4318 /* leave order_hint at max_order */
4325 ARDOUR_UI::start_duplicate_routes ()
4327 if (!duplicate_routes_dialog) {
4328 duplicate_routes_dialog = new DuplicateRouteDialog;
4331 if (duplicate_routes_dialog->restart (_session)) {
4335 duplicate_routes_dialog->present ();
4339 ARDOUR_UI::add_route ()
4341 if (!add_route_dialog.get (false)) {
4342 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4349 if (add_route_dialog->is_visible()) {
4350 /* we're already doing this */
4354 add_route_dialog->set_position (WIN_POS_MOUSE);
4355 add_route_dialog->present();
4359 ARDOUR_UI::add_route_dialog_response (int r)
4362 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4369 case AddRouteDialog::Add:
4370 add_route_dialog->reset_name_edited ();
4372 case AddRouteDialog::AddAndClose:
4373 add_route_dialog->ArdourDialog::on_response (r);
4376 add_route_dialog->ArdourDialog::on_response (r);
4380 std::string template_path = add_route_dialog->get_template_path();
4381 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4382 meta_route_setup (template_path.substr (11));
4386 if ((count = add_route_dialog->count()) <= 0) {
4390 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4391 const string name_template = add_route_dialog->name_template ();
4392 DisplaySuspender ds;
4394 if (!template_path.empty ()) {
4395 if (add_route_dialog->name_template_is_default ()) {
4396 _session->new_route_from_template (count, order, template_path, string ());
4398 _session->new_route_from_template (count, order, template_path, name_template);
4403 ChanCount input_chan= add_route_dialog->channels ();
4404 ChanCount output_chan;
4405 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4406 RouteGroup* route_group = add_route_dialog->route_group ();
4407 AutoConnectOption oac = Config->get_output_auto_connect();
4408 bool strict_io = add_route_dialog->use_strict_io ();
4410 if (oac & AutoConnectMaster) {
4411 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4412 output_chan.set (DataType::MIDI, 0);
4414 output_chan = input_chan;
4417 /* XXX do something with name template */
4419 Session::ProcessorChangeBlocker pcb (_session);
4421 switch (add_route_dialog->type_wanted()) {
4422 case AddRouteDialog::AudioTrack:
4423 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);
4425 case AddRouteDialog::MidiTrack:
4426 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4428 case AddRouteDialog::MixedTrack:
4429 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4431 case AddRouteDialog::AudioBus:
4432 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4434 case AddRouteDialog::MidiBus:
4435 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4437 case AddRouteDialog::VCAMaster:
4438 _session->vca_manager().create_vca (count, name_template);
4444 ARDOUR_UI::stop_video_server (bool ask_confirm)
4446 if (!video_server_process && ask_confirm) {
4447 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4449 if (video_server_process) {
4451 ArdourDialog confirm (_("Stop Video-Server"), true);
4452 Label m (_("Do you really want to stop the Video Server?"));
4453 confirm.get_vbox()->pack_start (m, true, true);
4454 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4455 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4456 confirm.show_all ();
4457 if (confirm.run() == RESPONSE_CANCEL) {
4461 delete video_server_process;
4462 video_server_process =0;
4467 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4469 ARDOUR_UI::start_video_server( float_window, true);
4473 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4479 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4480 if (video_server_process) {
4481 popup_error(_("The Video Server is already started."));
4483 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4489 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4491 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4493 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4495 video_server_dialog->set_transient_for (*float_window);
4498 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4499 video_server_dialog->hide();
4501 ResponseType r = (ResponseType) video_server_dialog->run ();
4502 video_server_dialog->hide();
4503 if (r != RESPONSE_ACCEPT) { return false; }
4504 if (video_server_dialog->show_again()) {
4505 Config->set_show_video_server_dialog(false);
4509 std::string icsd_exec = video_server_dialog->get_exec_path();
4510 std::string icsd_docroot = video_server_dialog->get_docroot();
4511 #ifndef PLATFORM_WINDOWS
4512 if (icsd_docroot.empty()) {
4513 icsd_docroot = VideoUtils::video_get_docroot (Config);
4518 #ifdef PLATFORM_WINDOWS
4519 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4520 /* OK, allow all drive letters */
4523 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4524 warning << _("Specified docroot is not an existing directory.") << endmsg;
4527 #ifndef PLATFORM_WINDOWS
4528 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4529 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4530 warning << _("Given Video Server is not an executable file.") << endmsg;
4534 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4535 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4536 warning << _("Given Video Server is not an executable file.") << endmsg;
4542 argp=(char**) calloc(9,sizeof(char*));
4543 argp[0] = strdup(icsd_exec.c_str());
4544 argp[1] = strdup("-P");
4545 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4546 argp[3] = strdup("-p");
4547 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4548 argp[5] = strdup("-C");
4549 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4550 argp[7] = strdup(icsd_docroot.c_str());
4552 stop_video_server();
4554 #ifdef PLATFORM_WINDOWS
4555 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4556 /* OK, allow all drive letters */
4559 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4560 Config->set_video_advanced_setup(false);
4562 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4563 Config->set_video_server_url(url_str);
4564 Config->set_video_server_docroot(icsd_docroot);
4565 Config->set_video_advanced_setup(true);
4568 if (video_server_process) {
4569 delete video_server_process;
4572 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4573 if (video_server_process->start()) {
4574 warning << _("Cannot launch the video-server") << endmsg;
4577 int timeout = 120; // 6 sec
4578 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4579 Glib::usleep (50000);
4581 if (--timeout <= 0 || !video_server_process->is_running()) break;
4584 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4586 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4587 delete video_server_process;
4588 video_server_process = 0;
4596 ARDOUR_UI::add_video (Gtk::Window* float_window)
4602 if (!start_video_server(float_window, false)) {
4603 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4608 add_video_dialog->set_transient_for (*float_window);
4611 if (add_video_dialog->is_visible()) {
4612 /* we're already doing this */
4616 ResponseType r = (ResponseType) add_video_dialog->run ();
4617 add_video_dialog->hide();
4618 if (r != RESPONSE_ACCEPT) { return; }
4620 bool local_file, orig_local_file;
4621 std::string path = add_video_dialog->file_name(local_file);
4623 std::string orig_path = path;
4624 orig_local_file = local_file;
4626 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4628 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4629 warning << string_compose(_("could not open %1"), path) << endmsg;
4632 if (!local_file && path.length() == 0) {
4633 warning << _("no video-file selected") << endmsg;
4637 std::string audio_from_video;
4638 bool detect_ltc = false;
4640 switch (add_video_dialog->import_option()) {
4641 case VTL_IMPORT_TRANSCODE:
4643 TranscodeVideoDialog *transcode_video_dialog;
4644 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4645 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4646 transcode_video_dialog->hide();
4647 if (r != RESPONSE_ACCEPT) {
4648 delete transcode_video_dialog;
4652 audio_from_video = transcode_video_dialog->get_audiofile();
4654 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4657 else if (!audio_from_video.empty()) {
4658 editor->embed_audio_from_video(
4660 video_timeline->get_offset(),
4661 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4664 switch (transcode_video_dialog->import_option()) {
4665 case VTL_IMPORT_TRANSCODED:
4666 path = transcode_video_dialog->get_filename();
4669 case VTL_IMPORT_REFERENCE:
4672 delete transcode_video_dialog;
4675 delete transcode_video_dialog;
4679 case VTL_IMPORT_NONE:
4683 /* strip _session->session_directory().video_path() from video file if possible */
4684 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4685 path=path.substr(_session->session_directory().video_path().size());
4686 if (path.at(0) == G_DIR_SEPARATOR) {
4687 path=path.substr(1);
4691 video_timeline->set_update_session_fps(auto_set_session_fps);
4693 if (video_timeline->video_file_info(path, local_file)) {
4694 XMLNode* node = new XMLNode(X_("Videotimeline"));
4695 node->set_property (X_("Filename"), path);
4696 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4697 node->set_property (X_("LocalFile"), local_file);
4698 if (orig_local_file) {
4699 node->set_property (X_("OriginalVideoFile"), orig_path);
4701 node->remove_property (X_("OriginalVideoFile"));
4703 _session->add_extra_xml (*node);
4704 _session->set_dirty ();
4706 if (!audio_from_video.empty() && detect_ltc) {
4707 std::vector<LTCFileReader::LTCMap> ltc_seq;
4710 /* TODO ask user about TV standard (LTC alignment if any) */
4711 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4712 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4714 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4716 /* TODO seek near end of file, and read LTC until end.
4717 * if it fails to find any LTC samples, scan complete file
4719 * calculate drift of LTC compared to video-duration,
4720 * ask user for reference (timecode from start/mid/end)
4723 // LTCFileReader will have written error messages
4726 ::g_unlink(audio_from_video.c_str());
4728 if (ltc_seq.size() == 0) {
4729 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4731 /* the very first TC in the file is somteimes not aligned properly */
4732 int i = ltc_seq.size() -1;
4733 ARDOUR::sampleoffset_t video_start_offset =
4734 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4735 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4736 video_timeline->set_offset(video_start_offset);
4740 _session->maybe_update_session_range(
4741 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4742 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4745 if (add_video_dialog->launch_xjadeo() && local_file) {
4746 editor->set_xjadeo_sensitive(true);
4747 editor->toggle_xjadeo_proc(1);
4749 editor->toggle_xjadeo_proc(0);
4751 editor->toggle_ruler_video(true);
4756 ARDOUR_UI::remove_video ()
4758 video_timeline->close_session();
4759 editor->toggle_ruler_video(false);
4762 video_timeline->set_offset_locked(false);
4763 video_timeline->set_offset(0);
4765 /* delete session state */
4766 XMLNode* node = new XMLNode(X_("Videotimeline"));
4767 _session->add_extra_xml(*node);
4768 node = new XMLNode(X_("Videomonitor"));
4769 _session->add_extra_xml(*node);
4770 node = new XMLNode(X_("Videoexport"));
4771 _session->add_extra_xml(*node);
4772 stop_video_server();
4776 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4778 if (localcacheonly) {
4779 video_timeline->vmon_update();
4781 video_timeline->flush_cache();
4783 editor->queue_visual_videotimeline_update();
4787 ARDOUR_UI::export_video (bool range)
4789 if (ARDOUR::Config->get_show_video_export_info()) {
4790 ExportVideoInfobox infobox (_session);
4791 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4792 if (infobox.show_again()) {
4793 ARDOUR::Config->set_show_video_export_info(false);
4796 case GTK_RESPONSE_YES:
4797 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4803 export_video_dialog->set_session (_session);
4804 export_video_dialog->apply_state(editor->get_selection().time, range);
4805 export_video_dialog->run ();
4806 export_video_dialog->hide ();
4810 ARDOUR_UI::preferences_settings () const
4815 node = _session->instant_xml(X_("Preferences"));
4817 node = Config->instant_xml(X_("Preferences"));
4821 node = new XMLNode (X_("Preferences"));
4828 ARDOUR_UI::mixer_settings () const
4833 node = _session->instant_xml(X_("Mixer"));
4835 node = Config->instant_xml(X_("Mixer"));
4839 node = new XMLNode (X_("Mixer"));
4846 ARDOUR_UI::main_window_settings () const
4851 node = _session->instant_xml(X_("Main"));
4853 node = Config->instant_xml(X_("Main"));
4857 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4858 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4863 node = new XMLNode (X_("Main"));
4870 ARDOUR_UI::editor_settings () const
4875 node = _session->instant_xml(X_("Editor"));
4877 node = Config->instant_xml(X_("Editor"));
4881 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4882 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4887 node = new XMLNode (X_("Editor"));
4894 ARDOUR_UI::keyboard_settings () const
4898 node = Config->extra_xml(X_("Keyboard"));
4901 node = new XMLNode (X_("Keyboard"));
4908 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4911 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4912 _session->locations()->add (location);
4917 ARDOUR_UI::halt_on_xrun_message ()
4919 cerr << "HALT on xrun\n";
4920 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4925 ARDOUR_UI::xrun_handler (samplepos_t where)
4931 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4933 if (_session && _session->actively_recording()) {
4934 dsp_load_indicator.set_xrun_while_recording();
4937 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4938 create_xrun_marker(where);
4941 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4942 halt_on_xrun_message ();
4947 ARDOUR_UI::disk_overrun_handler ()
4949 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4951 if (!have_disk_speed_dialog_displayed) {
4952 have_disk_speed_dialog_displayed = true;
4953 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4954 The disk system on your computer\n\
4955 was not able to keep up with %1.\n\
4957 Specifically, it failed to write data to disk\n\
4958 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4959 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4965 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4966 static MessageDialog *scan_dlg = NULL;
4967 static ProgressBar *scan_pbar = NULL;
4968 static HBox *scan_tbox = NULL;
4969 static Gtk::Button *scan_timeout_button;
4972 ARDOUR_UI::cancel_plugin_scan ()
4974 PluginManager::instance().cancel_plugin_scan();
4978 ARDOUR_UI::cancel_plugin_timeout ()
4980 PluginManager::instance().cancel_plugin_timeout();
4981 scan_timeout_button->set_sensitive (false);
4985 ARDOUR_UI::plugin_scan_timeout (int timeout)
4987 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4991 scan_pbar->set_sensitive (false);
4992 scan_timeout_button->set_sensitive (true);
4993 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4996 scan_pbar->set_sensitive (false);
4997 scan_timeout_button->set_sensitive (false);
5003 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5005 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5009 const bool cancelled = PluginManager::instance().cancelled();
5010 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5011 if (cancelled && scan_dlg->is_mapped()) {
5016 if (cancelled || !can_cancel) {
5021 static Gtk::Button *cancel_button;
5023 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5024 VBox* vbox = scan_dlg->get_vbox();
5025 vbox->set_size_request(400,-1);
5026 scan_dlg->set_title (_("Scanning for plugins"));
5028 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5029 cancel_button->set_name ("EditorGTKButton");
5030 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5031 cancel_button->show();
5033 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5035 scan_tbox = manage( new HBox() );
5037 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5038 scan_timeout_button->set_name ("EditorGTKButton");
5039 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5040 scan_timeout_button->show();
5042 scan_pbar = manage(new ProgressBar());
5043 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5044 scan_pbar->set_text(_("Scan Timeout"));
5047 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5048 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5050 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5053 assert(scan_dlg && scan_tbox && cancel_button);
5055 if (type == X_("closeme")) {
5059 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5062 if (!can_cancel || !cancelled) {
5063 scan_timeout_button->set_sensitive(false);
5065 cancel_button->set_sensitive(can_cancel && !cancelled);
5071 ARDOUR_UI::gui_idle_handler ()
5074 /* due to idle calls, gtk_events_pending() may always return true */
5075 while (gtk_events_pending() && --timeout) {
5076 gtk_main_iteration ();
5081 ARDOUR_UI::disk_underrun_handler ()
5083 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5085 if (!have_disk_speed_dialog_displayed) {
5086 have_disk_speed_dialog_displayed = true;
5087 MessageDialog* msg = new MessageDialog (
5088 _main_window, string_compose (_("The disk system on your computer\n\
5089 was not able to keep up with %1.\n\
5091 Specifically, it failed to read data from disk\n\
5092 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5093 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5099 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5101 have_disk_speed_dialog_displayed = false;
5106 ARDOUR_UI::session_dialog (std::string msg)
5108 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5112 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5119 ARDOUR_UI::pending_state_dialog ()
5121 HBox* hbox = manage (new HBox());
5122 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5123 ArdourDialog dialog (_("Crash Recovery"), true);
5124 Label message (string_compose (_("\
5125 This session appears to have been in the\n\
5126 middle of recording when %1 or\n\
5127 the computer was shutdown.\n\
5129 %1 can recover any captured audio for\n\
5130 you, or it can ignore it. Please decide\n\
5131 what you would like to do.\n"), PROGRAM_NAME));
5132 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5133 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5134 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5135 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5136 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5137 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5138 dialog.set_default_response (RESPONSE_ACCEPT);
5139 dialog.set_position (WIN_POS_CENTER);
5144 switch (dialog.run ()) {
5145 case RESPONSE_ACCEPT:
5153 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5155 HBox* hbox = new HBox();
5156 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5157 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5158 Label message (string_compose (_("\
5159 This session was created with a sample rate of %1 Hz, but\n\
5160 %2 is currently running at %3 Hz. If you load this session,\n\
5161 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5163 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5164 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5165 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5166 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5167 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5168 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5169 dialog.set_default_response (RESPONSE_ACCEPT);
5170 dialog.set_position (WIN_POS_CENTER);
5175 switch (dialog.run()) {
5176 case RESPONSE_ACCEPT:
5186 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5188 MessageDialog msg (string_compose (_("\
5189 This session was created with a sample rate of %1 Hz, but\n\
5190 %2 is currently running at %3 Hz.\n\
5191 Audio will be recorded and played at the wrong sample rate.\n\
5192 Re-Configure the Audio Engine in\n\
5193 Menu > Window > Audio/Midi Setup"),
5194 desired, PROGRAM_NAME, actual),
5196 Gtk::MESSAGE_WARNING);
5201 ARDOUR_UI::use_config ()
5203 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5205 set_transport_controllable_state (*node);
5210 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5212 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5214 primary_clock->set (pos);
5216 case DeltaEditPoint:
5217 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5219 case DeltaOriginMarker:
5221 Location* loc = _session->locations()->clock_origin_location ();
5222 primary_clock->set (pos, false, loc ? loc->start() : 0);
5227 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5229 secondary_clock->set (pos);
5231 case DeltaEditPoint:
5232 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5234 case DeltaOriginMarker:
5236 Location* loc = _session->locations()->clock_origin_location ();
5237 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5242 if (big_clock_window) {
5243 big_clock->set (pos);
5245 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5250 ARDOUR_UI::record_state_changed ()
5252 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5255 /* why bother - the clock isn't visible */
5259 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5261 if (big_clock_window) {
5262 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5263 big_clock->set_active (true);
5265 big_clock->set_active (false);
5272 ARDOUR_UI::first_idle ()
5275 _session->allow_auto_play (true);
5279 editor->first_idle();
5282 /* in 1 second, hide the splash screen
5284 * Consider hiding it *now*. If a user opens opens a dialog
5285 * during that one second while the splash is still visible,
5286 * the dialog will push-back the splash.
5287 * Closing the dialog later will pop it back.
5289 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5291 Keyboard::set_can_save_keybindings (true);
5296 ARDOUR_UI::store_clock_modes ()
5298 XMLNode* node = new XMLNode(X_("ClockModes"));
5300 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5301 XMLNode* child = new XMLNode (X_("Clock"));
5303 child->set_property (X_("name"), (*x)->name());
5304 child->set_property (X_("mode"), (*x)->mode());
5305 child->set_property (X_("on"), (*x)->on());
5307 node->add_child_nocopy (*child);
5310 _session->add_extra_xml (*node);
5311 _session->set_dirty ();
5315 ARDOUR_UI::setup_profile ()
5317 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5318 Profile->set_small_screen ();
5321 if (g_getenv ("TRX")) {
5322 Profile->set_trx ();
5325 if (g_getenv ("MIXBUS")) {
5326 Profile->set_mixbus ();
5331 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5333 MissingFileDialog dialog (s, str, type);
5338 int result = dialog.run ();
5345 return 1; // quit entire session load
5348 result = dialog.get_action ();
5354 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5356 AmbiguousFileDialog dialog (file, hits);
5363 return dialog.get_which ();
5366 /** Allocate our thread-local buffers */
5368 ARDOUR_UI::get_process_buffers ()
5370 _process_thread->get_buffers ();
5373 /** Drop our thread-local buffers */
5375 ARDOUR_UI::drop_process_buffers ()
5377 _process_thread->drop_buffers ();
5381 ARDOUR_UI::feedback_detected ()
5383 _feedback_exists = true;
5387 ARDOUR_UI::successful_graph_sort ()
5389 _feedback_exists = false;
5393 ARDOUR_UI::midi_panic ()
5396 _session->midi_panic();
5401 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5403 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5404 const char* end_big = "</span>";
5405 const char* start_mono = "<tt>";
5406 const char* end_mono = "</tt>";
5408 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5409 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5410 "From now on, use the backup copy with older versions of %3"),
5411 xml_path, backup_path, PROGRAM_NAME,
5413 start_mono, end_mono), true);
5419 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5421 using namespace Menu_Helpers;
5423 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5424 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5425 i->set_active (editor_meter->meter_type () == type);
5429 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5431 using namespace Gtk::Menu_Helpers;
5433 Gtk::Menu* m = manage (new Menu);
5434 MenuList& items = m->items ();
5436 RadioMenuItem::Group group;
5438 _suspend_editor_meter_callbacks = true;
5439 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5440 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5441 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5442 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5443 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5444 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5445 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5446 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5447 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5448 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5449 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5451 m->popup (ev->button, ev->time);
5452 _suspend_editor_meter_callbacks = false;
5456 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5458 if (ev->button == 3 && editor_meter) {
5459 popup_editor_meter_menu (ev);
5466 ARDOUR_UI::reset_peak_display ()
5468 if (!_session || !_session->master_out() || !editor_meter) return;
5469 editor_meter->clear_meters();
5470 editor_meter_max_peak = -INFINITY;
5471 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5475 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5477 if (!_session || !_session->master_out()) return;
5478 if (group == _session->master_out()->route_group()) {
5479 reset_peak_display ();
5484 ARDOUR_UI::reset_route_peak_display (Route* route)
5486 if (!_session || !_session->master_out()) return;
5487 if (_session->master_out().get() == route) {
5488 reset_peak_display ();
5493 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5495 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5496 audio_midi_setup->set_position (WIN_POS_CENTER);
5498 if (desired_sample_rate != 0) {
5499 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5500 audio_midi_setup->try_autostart ();
5501 if (ARDOUR::AudioEngine::instance()->running()) {
5508 int response = audio_midi_setup->run();
5510 case Gtk::RESPONSE_DELETE_EVENT:
5511 // after latency callibration engine may run,
5512 // Running() signal was emitted, but dialog will not
5513 // have emitted a response. The user needs to close
5514 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5515 if (!AudioEngine::instance()->running()) {
5520 if (!AudioEngine::instance()->running()) {
5523 audio_midi_setup->hide ();
5531 ARDOUR_UI::transport_numpad_timeout ()
5533 _numpad_locate_happening = false;
5534 if (_numpad_timeout_connection.connected() )
5535 _numpad_timeout_connection.disconnect();
5540 ARDOUR_UI::transport_numpad_decimal ()
5542 _numpad_timeout_connection.disconnect();
5544 if (_numpad_locate_happening) {
5545 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5546 _numpad_locate_happening = false;
5548 _pending_locate_num = 0;
5549 _numpad_locate_happening = true;
5550 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5555 ARDOUR_UI::transport_numpad_event (int num)
5557 if ( _numpad_locate_happening ) {
5558 _pending_locate_num = _pending_locate_num*10 + num;
5561 case 0: toggle_roll(false, false); break;
5562 case 1: transport_rewind(1); break;
5563 case 2: transport_forward(1); break;
5564 case 3: transport_record(true); break;
5565 case 4: toggle_session_auto_loop(); break;
5566 case 5: transport_record(false); toggle_session_auto_loop(); break;
5567 case 6: toggle_punch(); break;
5568 case 7: toggle_click(); break;
5569 case 8: toggle_auto_return(); break;
5570 case 9: toggle_follow_edits(); break;
5576 ARDOUR_UI::set_flat_buttons ()
5578 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5582 ARDOUR_UI::audioengine_became_silent ()
5584 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5586 Gtk::MESSAGE_WARNING,
5590 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5592 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5593 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5594 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5595 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5596 Gtk::HBox pay_button_box;
5597 Gtk::HBox subscribe_button_box;
5599 pay_button_box.pack_start (pay_button, true, false);
5600 subscribe_button_box.pack_start (subscribe_button, true, false);
5602 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 */
5604 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5605 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5607 msg.get_vbox()->pack_start (pay_label);
5608 msg.get_vbox()->pack_start (pay_button_box);
5609 msg.get_vbox()->pack_start (subscribe_label);
5610 msg.get_vbox()->pack_start (subscribe_button_box);
5612 msg.get_vbox()->show_all ();
5614 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5615 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5616 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5621 case Gtk::RESPONSE_YES:
5622 AudioEngine::instance()->reset_silence_countdown ();
5625 case Gtk::RESPONSE_NO:
5627 save_state_canfail ("");
5631 case Gtk::RESPONSE_CANCEL:
5633 /* don't reset, save session and exit */
5639 ARDOUR_UI::hide_application ()
5641 Application::instance ()-> hide ();
5645 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5647 /* icons, titles, WM stuff */
5649 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5651 if (window_icons.empty()) {
5652 Glib::RefPtr<Gdk::Pixbuf> icon;
5653 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5654 window_icons.push_back (icon);
5656 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5657 window_icons.push_back (icon);
5659 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5660 window_icons.push_back (icon);
5662 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5663 window_icons.push_back (icon);
5667 if (!window_icons.empty()) {
5668 window.set_default_icon_list (window_icons);
5671 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5673 if (!name.empty()) {
5677 window.set_title (title.get_string());
5678 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5680 window.set_flags (CAN_FOCUS);
5681 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5683 /* This is a hack to ensure that GTK-accelerators continue to
5684 * work. Once we switch over to entirely native bindings, this will be
5685 * unnecessary and should be removed
5687 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5689 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5690 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5691 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5692 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5696 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5698 Gtkmm2ext::Bindings* bindings = 0;
5699 Gtk::Window* window = 0;
5701 /* until we get ardour bindings working, we are not handling key
5705 if (ev->type != GDK_KEY_PRESS) {
5709 if (event_window == &_main_window) {
5711 window = event_window;
5713 /* find current tab contents */
5715 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5717 /* see if it uses the ardour binding system */
5720 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5723 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5727 window = event_window;
5729 /* see if window uses ardour binding system */
5731 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5734 /* An empty binding set is treated as if it doesn't exist */
5736 if (bindings && bindings->empty()) {
5740 return key_press_focus_accelerator_handler (*window, ev, bindings);
5743 static Gtkmm2ext::Bindings*
5744 get_bindings_from_widget_heirarchy (GtkWidget** w)
5749 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5752 *w = gtk_widget_get_parent (*w);
5755 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5759 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5761 GtkWindow* win = window.gobj();
5762 GtkWidget* focus = gtk_window_get_focus (win);
5763 GtkWidget* binding_widget = focus;
5764 bool special_handling_of_unmodified_accelerators = false;
5765 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5769 /* some widget has keyboard focus */
5771 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5773 /* A particular kind of focusable widget currently has keyboard
5774 * focus. All unmodified key events should go to that widget
5775 * first and not be used as an accelerator by default
5778 special_handling_of_unmodified_accelerators = true;
5782 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5783 if (focus_bindings) {
5784 bindings = focus_bindings;
5785 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5790 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",
5793 Gtkmm2ext::show_gdk_event_state (ev->state),
5794 special_handling_of_unmodified_accelerators,
5795 Keyboard::some_magic_widget_has_focus(),
5797 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5798 ((ev->state & mask) ? "yes" : "no"),
5799 window.get_title()));
5801 /* This exists to allow us to override the way GTK handles
5802 key events. The normal sequence is:
5804 a) event is delivered to a GtkWindow
5805 b) accelerators/mnemonics are activated
5806 c) if (b) didn't handle the event, propagate to
5807 the focus widget and/or focus chain
5809 The problem with this is that if the accelerators include
5810 keys without modifiers, such as the space bar or the
5811 letter "e", then pressing the key while typing into
5812 a text entry widget results in the accelerator being
5813 activated, instead of the desired letter appearing
5816 There is no good way of fixing this, but this
5817 represents a compromise. The idea is that
5818 key events involving modifiers (not Shift)
5819 get routed into the activation pathway first, then
5820 get propagated to the focus widget if necessary.
5822 If the key event doesn't involve modifiers,
5823 we deliver to the focus widget first, thus allowing
5824 it to get "normal text" without interference
5827 Of course, this can also be problematic: if there
5828 is a widget with focus, then it will swallow
5829 all "normal text" accelerators.
5833 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5835 /* no special handling or there are modifiers in effect: accelerate first */
5837 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5838 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5839 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5841 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5842 KeyboardKey k (ev->state, ev->keyval);
5846 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5848 if (bindings->activate (k, Bindings::Press)) {
5849 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5853 if (binding_widget) {
5854 binding_widget = gtk_widget_get_parent (binding_widget);
5855 if (binding_widget) {
5856 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5865 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5867 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5868 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5872 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5874 if (gtk_window_propagate_key_event (win, ev)) {
5875 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5881 /* no modifiers, propagate first */
5883 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5885 if (gtk_window_propagate_key_event (win, ev)) {
5886 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5890 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5891 KeyboardKey k (ev->state, ev->keyval);
5895 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5898 if (bindings->activate (k, Bindings::Press)) {
5899 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5903 if (binding_widget) {
5904 binding_widget = gtk_widget_get_parent (binding_widget);
5905 if (binding_widget) {
5906 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5915 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5917 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5918 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5923 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5928 ARDOUR_UI::load_bindings ()
5930 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5931 error << _("Global keybindings are missing") << endmsg;
5936 ARDOUR_UI::cancel_solo ()
5939 _session->cancel_all_solo ();
5944 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5946 /* this resets focus to the first focusable parent of the given widget,
5947 * or, if there is no focusable parent, cancels focus in the toplevel
5948 * window that the given widget is packed into (if there is one).
5955 Gtk::Widget* top = w->get_toplevel();
5957 if (!top || !top->is_toplevel()) {
5961 w = w->get_parent ();
5965 if (w->is_toplevel()) {
5966 /* Setting the focus widget to a Gtk::Window causes all
5967 * subsequent calls to ::has_focus() on the nominal
5968 * focus widget in that window to return
5969 * false. Workaround: never set focus to the toplevel
5975 if (w->get_can_focus ()) {
5976 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5977 win->set_focus (*w);
5980 w = w->get_parent ();
5983 if (top == &_main_window) {
5987 /* no focusable parent found, cancel focus in top level window.
5988 C++ API cannot be used for this. Thanks, references.
5991 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);