2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/accelmap.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/uimanager.h>
55 #include "pbd/error.h"
56 #include "pbd/basename.h"
57 #include "pbd/compose.h"
58 #include "pbd/convert.h"
59 #include "pbd/failed_constructor.h"
60 #include "pbd/file_archive.h"
61 #include "pbd/enumwriter.h"
62 #include "pbd/memento_command.h"
63 #include "pbd/openuri.h"
64 #include "pbd/stl_delete.h"
65 #include "pbd/types_convert.h"
66 #include "pbd/unwind.h"
67 #include "pbd/file_utils.h"
68 #include "pbd/localtime_r.h"
69 #include "pbd/pthread_utils.h"
70 #include "pbd/replace_all.h"
71 #include "pbd/scoped_file_descriptor.h"
72 #include "pbd/xml++.h"
74 #include "gtkmm2ext/application.h"
75 #include "gtkmm2ext/bindings.h"
76 #include "gtkmm2ext/gtk_ui.h"
77 #include "gtkmm2ext/utils.h"
78 #include "gtkmm2ext/window_title.h"
80 #include "widgets/fastmeter.h"
81 #include "widgets/prompter.h"
82 #include "widgets/tooltips.h"
84 #include "ardour/ardour.h"
85 #include "ardour/audio_backend.h"
86 #include "ardour/audio_track.h"
87 #include "ardour/audioengine.h"
88 #include "ardour/audiofilesource.h"
89 #include "ardour/automation_watch.h"
90 #include "ardour/disk_reader.h"
91 #include "ardour/disk_writer.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/filesystem_paths.h"
94 #include "ardour/ltc_file_reader.h"
95 #include "ardour/midi_track.h"
96 #include "ardour/port.h"
97 #include "ardour/plugin_manager.h"
98 #include "ardour/process_thread.h"
99 #include "ardour/profile.h"
100 #include "ardour/recent_sessions.h"
101 #include "ardour/record_enable_control.h"
102 #include "ardour/revision.h"
103 #include "ardour/session_directory.h"
104 #include "ardour/session_route.h"
105 #include "ardour/session_state_utils.h"
106 #include "ardour/session_utils.h"
107 #include "ardour/source_factory.h"
108 #include "ardour/transport_master.h"
109 #include "ardour/transport_master_manager.h"
110 #include "ardour/system_exec.h"
111 #include "ardour/track.h"
112 #include "ardour/vca_manager.h"
113 #include "ardour/utils.h"
115 #include "LuaBridge/LuaBridge.h"
117 #ifdef WINDOWS_VST_SUPPORT
120 #ifdef AUDIOUNIT_SUPPORT
121 #include "ardour/audio_unit.h"
124 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
129 #include "temporal/time.h"
131 typedef uint64_t microseconds_t;
135 #include "enums_convert.h"
137 #include "add_route_dialog.h"
138 #include "ambiguous_file_dialog.h"
139 #include "ardour_ui.h"
140 #include "audio_clock.h"
141 #include "audio_region_view.h"
142 #include "big_clock_window.h"
143 #include "big_transport_window.h"
144 #include "bundle_manager.h"
145 #include "duplicate_routes_dialog.h"
147 #include "engine_dialog.h"
148 #include "export_video_dialog.h"
149 #include "export_video_infobox.h"
150 #include "gain_meter.h"
151 #include "global_port_matrix.h"
152 #include "gui_object.h"
153 #include "gui_thread.h"
154 #include "idleometer.h"
155 #include "keyboard.h"
156 #include "keyeditor.h"
157 #include "location_ui.h"
158 #include "lua_script_manager.h"
159 #include "luawindow.h"
160 #include "main_clock.h"
161 #include "missing_file_dialog.h"
162 #include "missing_plugin_dialog.h"
163 #include "mixer_ui.h"
164 #include "meterbridge.h"
165 #include "meter_patterns.h"
166 #include "mouse_cursors.h"
169 #include "pingback.h"
170 #include "processor_box.h"
171 #include "public_editor.h"
172 #include "rc_option_editor.h"
173 #include "route_time_axis.h"
174 #include "route_params_ui.h"
175 #include "save_as_dialog.h"
176 #include "save_template_dialog.h"
177 #include "script_selector.h"
178 #include "session_archive_dialog.h"
179 #include "session_dialog.h"
180 #include "session_metadata_dialog.h"
181 #include "session_option_editor.h"
182 #include "speaker_dialog.h"
185 #include "template_dialog.h"
186 #include "time_axis_view_item.h"
187 #include "time_info_box.h"
189 #include "transport_masters_dialog.h"
191 #include "utils_videotl.h"
192 #include "video_server_dialog.h"
193 #include "add_video_dialog.h"
194 #include "transcode_video_dialog.h"
196 #include "pbd/i18n.h"
198 using namespace ARDOUR;
199 using namespace ARDOUR_UI_UTILS;
201 using namespace Gtkmm2ext;
202 using namespace ArdourWidgets;
205 using namespace Editing;
207 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
209 sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
210 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
213 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
215 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
216 "Would you like these files to be copied and used for %1 %2.x?\n\n"
217 "(This will require you to restart %1.)"),
218 PROGRAM_NAME, PROGRAM_VERSION, version),
219 false, /* no markup */
222 true /* modal, though it hardly matters since it is the only window */
225 msg.set_default_response (Gtk::RESPONSE_YES);
228 return (msg.run() == Gtk::RESPONSE_YES);
232 libxml_generic_error_func (void* /* parsing_context*/,
240 vsnprintf (buf, sizeof (buf), msg, ap);
241 error << buf << endmsg;
246 libxml_structured_error_func (void* /* parsing_context*/,
254 replace_all (msg, "\n", "");
257 if (err->file && err->line) {
258 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
261 error << ':' << err->int2;
266 error << X_("XML error: ") << msg << endmsg;
272 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
273 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
274 , session_loaded (false)
275 , session_load_in_progress (false)
276 , gui_object_state (new GUIObjectState)
277 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
278 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
279 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
281 , global_actions (X_("global"))
282 , ignore_dual_punch (false)
283 , main_window_visibility (0)
288 , _mixer_on_top (false)
289 , _initial_verbose_plugin_scan (false)
290 , first_time_engine_run (true)
291 , secondary_clock_spacer (0)
292 , auto_input_button (ArdourButton::led_default_elements)
294 , auto_return_button (ArdourButton::led_default_elements)
295 , follow_edits_button (ArdourButton::led_default_elements)
296 , auditioning_alert_button (_("Audition"))
297 , solo_alert_button (_("Solo"))
298 , feedback_alert_button (_("Feedback"))
299 , error_alert_button ( ArdourButton::just_led_default_elements )
300 , editor_meter_peak_display()
302 , _suspend_editor_meter_callbacks (false)
303 , _numpad_locate_happening (false)
304 , _session_is_new (false)
305 , last_key_press_time (0)
309 , rc_option_editor (0)
310 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
311 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
312 , about (X_("about"), _("About"))
313 , location_ui (X_("locations"), S_("Ranges|Locations"))
314 , route_params (X_("inspector"), _("Tracks and Busses"))
315 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
316 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
317 , lua_script_window (X_("script-manager"), _("Script Manager"))
318 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
319 , transport_masters_window (X_("transport-masters"), _("Transport Masters"))
320 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
321 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
322 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
323 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
324 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
325 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
326 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
327 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
328 , video_server_process (0)
330 , have_configure_timeout (false)
331 , last_configure_time (0)
333 , have_disk_speed_dialog_displayed (false)
334 , _status_bar_visibility (X_("status-bar"))
335 , _feedback_exists (false)
336 , _log_not_acknowledged (LogLevelNone)
337 , duplicate_routes_dialog (0)
338 , editor_visibility_button (S_("Window|Editor"))
339 , mixer_visibility_button (S_("Window|Mixer"))
340 , prefs_visibility_button (S_("Window|Preferences"))
342 Gtkmm2ext::init (localedir);
344 UIConfiguration::instance().post_gui_init ();
346 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
348 /* "touch" the been-here-before path now that config has been migrated */
349 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
351 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
353 /* configuration was modified, exit immediately */
358 if (string (VERSIONSTRING).find (".pre") != string::npos) {
359 /* check this is not being run from ./ardev etc. */
360 if (!running_from_source_tree ()) {
361 pre_release_dialog ();
365 if (theArdourUI == 0) {
369 /* track main window visibility */
371 main_window_visibility = new VisibilityTracker (_main_window);
373 /* stop libxml from spewing to stdout/stderr */
375 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
376 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
378 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
379 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
380 UIConfiguration::instance().map_parameters (pc);
382 transport_ctrl.setup (this);
384 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
385 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
387 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
389 /* handle dialog requests */
391 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
393 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
395 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
397 /* handle Audio/MIDI setup when session requires it */
399 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
401 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
403 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
405 /* handle sr mismatch with a dialog - cross-thread from engine */
406 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
408 /* handle requests to quit (coming from JACK session) */
410 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
412 /* tell the user about feedback */
414 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
415 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
417 /* handle requests to deal with missing files */
419 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
421 /* and ambiguous files */
423 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
425 /* also plugin scan messages */
426 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
427 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
429 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
431 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
434 /* lets get this party started */
436 setup_gtk_ardour_enums ();
439 SessionEvent::create_per_thread_pool ("GUI", 4096);
441 /* we like keyboards */
443 keyboard = new ArdourKeyboard(*this);
445 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
447 keyboard->set_state (*node, Stateful::loading_state_version);
450 UIConfiguration::instance().reset_dpi ();
452 TimeAxisViewItem::set_constant_heights ();
454 /* Set this up so that our window proxies can register actions */
456 ActionManager::init ();
458 /* The following must happen after ARDOUR::init() so that Config is set up */
460 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
463 std::cerr << "\n\n\nHAVE UI XML, set dialogs\n\n\n";
464 key_editor.set_state (*ui_xml, 0);
465 session_option_editor.set_state (*ui_xml, 0);
466 speaker_config_window.set_state (*ui_xml, 0);
467 about.set_state (*ui_xml, 0);
468 add_route_dialog.set_state (*ui_xml, 0);
469 add_video_dialog.set_state (*ui_xml, 0);
470 route_params.set_state (*ui_xml, 0);
471 bundle_manager.set_state (*ui_xml, 0);
472 location_ui.set_state (*ui_xml, 0);
473 big_clock_window.set_state (*ui_xml, 0);
474 big_transport_window.set_state (*ui_xml, 0);
475 audio_port_matrix.set_state (*ui_xml, 0);
476 midi_port_matrix.set_state (*ui_xml, 0);
477 export_video_dialog.set_state (*ui_xml, 0);
478 lua_script_window.set_state (*ui_xml, 0);
479 idleometer.set_state (*ui_xml, 0);
480 transport_masters_window.set_state (*ui_xml, 0);
483 /* Separate windows */
485 WM::Manager::instance().register_window (&key_editor);
486 WM::Manager::instance().register_window (&session_option_editor);
487 WM::Manager::instance().register_window (&speaker_config_window);
488 WM::Manager::instance().register_window (&about);
489 WM::Manager::instance().register_window (&add_route_dialog);
490 WM::Manager::instance().register_window (&add_video_dialog);
491 WM::Manager::instance().register_window (&route_params);
492 WM::Manager::instance().register_window (&audio_midi_setup);
493 WM::Manager::instance().register_window (&export_video_dialog);
494 WM::Manager::instance().register_window (&lua_script_window);
495 WM::Manager::instance().register_window (&bundle_manager);
496 WM::Manager::instance().register_window (&location_ui);
497 WM::Manager::instance().register_window (&big_clock_window);
498 WM::Manager::instance().register_window (&big_transport_window);
499 WM::Manager::instance().register_window (&audio_port_matrix);
500 WM::Manager::instance().register_window (&midi_port_matrix);
501 WM::Manager::instance().register_window (&idleometer);
502 WM::Manager::instance().register_window (&transport_masters_window);
504 /* do not retain position for add route dialog */
505 add_route_dialog.set_state_mask (WindowProxy::Size);
507 /* Trigger setting up the color scheme and loading the GTK RC file */
509 UIConfiguration::instance().load_rc_file (false);
511 _process_thread = new ProcessThread ();
512 _process_thread->init ();
514 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
520 ARDOUR_UI::pre_release_dialog ()
522 ArdourDialog d (_("Pre-Release Warning"), true, false);
523 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
525 Label* label = manage (new Label);
526 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
527 There are still several issues and bugs to be worked on,\n\
528 as well as general workflow improvements, before this can be considered\n\
529 release software. So, a few guidelines:\n\
531 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
532 though it may be so, depending on your workflow.\n\
533 2) Please wait for a helpful writeup of new features.\n\
534 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
535 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
536 making sure to note the product version number as 6.0-pre.\n\
537 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
538 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
539 can get there directly from within the program via the Help->Chat menu option.\n\
541 Full information on all the above can be found on the support page at\n\
543 http://ardour.org/support\n\
544 "), PROGRAM_NAME, VERSIONSTRING));
546 d.get_vbox()->set_border_width (12);
547 d.get_vbox()->pack_start (*label, false, false, 12);
548 d.get_vbox()->show_all ();
553 GlobalPortMatrixWindow*
554 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
559 return new GlobalPortMatrixWindow (_session, type);
563 ARDOUR_UI::attach_to_engine ()
565 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
566 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
570 ARDOUR_UI::engine_stopped ()
572 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
573 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
574 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
575 update_sample_rate (0);
580 ARDOUR_UI::engine_running ()
582 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
583 if (first_time_engine_run) {
585 first_time_engine_run = false;
589 _session->reset_xrun_count ();
591 update_disk_space ();
593 update_sample_rate (AudioEngine::instance()->sample_rate());
594 update_timecode_format ();
595 update_peak_thread_work ();
596 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
597 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
601 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
603 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
604 /* we can't rely on the original string continuing to exist when we are called
605 again in the GUI thread, so make a copy and note that we need to
608 char *copy = strdup (reason);
609 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
613 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
614 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
616 update_sample_rate (0);
620 /* if the reason is a non-empty string, it means that the backend was shutdown
621 rather than just Ardour.
624 if (strlen (reason)) {
625 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
627 msgstr = string_compose (_("\
628 The audio backend has either been shutdown or it\n\
629 disconnected %1 because %1\n\
630 was not fast enough. Try to restart\n\
631 the audio backend and save the session."), PROGRAM_NAME);
634 MessageDialog msg (_main_window, msgstr);
635 pop_back_splash (msg);
639 free (const_cast<char*> (reason));
644 ARDOUR_UI::post_engine ()
646 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
648 #ifdef AUDIOUNIT_SUPPORT
650 if (AUPluginInfo::au_get_crashlog(au_msg)) {
651 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
652 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
653 info << au_msg << endmsg;
657 ARDOUR::init_post_engine ();
659 /* connect to important signals */
661 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
662 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
663 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
664 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
665 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
667 if (setup_windows ()) {
668 throw failed_constructor ();
671 transport_ctrl.map_actions ();
673 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
674 XMLNode* n = Config->extra_xml (X_("UI"));
676 _status_bar_visibility.set_state (*n);
679 check_memory_locking();
681 /* this is the first point at which all the possible actions are
682 * available, because some of the available actions are dependent on
683 * aspects of the engine/backend.
686 if (ARDOUR_COMMAND_LINE::show_key_actions) {
688 Bindings::save_all_bindings_as_html (sstr);
690 if (sstr.str().empty()) {
697 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
699 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
705 #ifdef PLATFORM_WINDOWS
711 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
712 #ifndef PLATFORM_WINDOWS
715 g_unlink (file_name);
717 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
723 #ifndef PLATFORM_WINDOWS
727 PBD::open_uri (string_compose ("file:///%1", file_name));
729 halt_connection.disconnect ();
730 AudioEngine::instance()->stop ();
735 if (ARDOUR_COMMAND_LINE::show_actions) {
738 vector<string> paths;
739 vector<string> labels;
740 vector<string> tooltips;
742 vector<Glib::RefPtr<Gtk::Action> > actions;
743 string ver_in = revision;
744 string ver = ver_in.substr(0, ver_in.find("-"));
747 output << "\n<h2>Menu actions</h2>" << endl;
748 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
749 output << " surfaces or scripts.\n</p>\n" << endl;
750 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
751 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
752 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
753 output << "<table class=\"dl\">\n <thead>" << endl;
754 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
755 output << " </thead>\n <tbody>" << endl;
757 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
759 vector<string>::iterator p;
760 vector<string>::iterator l;
762 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
763 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (10, string::npos);
764 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
766 output << " </tbody>\n </table>" << endl;
768 // output this mess to a browser for easiest X-platform use
769 // it is not pretty HTML, but it works and it's main purpose
770 // is to create raw html to fit in Ardour's manual with no editing
775 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
777 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
783 #ifdef PLATFORM_WINDOWS
789 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
790 #ifndef PLATFORM_WINDOWS
793 g_unlink (file_name);
795 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
801 #ifndef PLATFORM_WINDOWS
805 PBD::open_uri (string_compose ("file:///%1", file_name));
807 halt_connection.disconnect ();
808 AudioEngine::instance()->stop ();
812 /* this being a GUI and all, we want peakfiles */
814 AudioFileSource::set_build_peakfiles (true);
815 AudioFileSource::set_build_missing_peakfiles (true);
817 /* set default clock modes */
819 primary_clock->set_mode (AudioClock::Timecode);
820 secondary_clock->set_mode (AudioClock::BBT);
822 /* start the time-of-day-clock */
825 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
826 update_wall_clock ();
827 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
832 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
833 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
834 Config->map_parameters (pc);
836 UIConfiguration::instance().map_parameters (pc);
840 ARDOUR_UI::~ARDOUR_UI ()
842 UIConfiguration::instance().save_state();
846 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
847 // don't bother at 'real' exit. the OS cleans up for us.
848 delete big_clock; big_clock = 0;
849 delete primary_clock; primary_clock = 0;
850 delete secondary_clock; secondary_clock = 0;
851 delete _process_thread; _process_thread = 0;
852 delete time_info_box; time_info_box = 0;
853 delete meterbridge; meterbridge = 0;
854 delete luawindow; luawindow = 0;
855 delete editor; editor = 0;
856 delete mixer; mixer = 0;
857 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
859 delete gui_object_state; gui_object_state = 0;
860 delete main_window_visibility;
861 FastMeter::flush_pattern_cache ();
862 ArdourFader::flush_pattern_cache ();
866 /* Small trick to flush main-thread event pool.
867 * Other thread-pools are destroyed at pthread_exit(),
868 * but tmain thread termination is too late to trigger Pool::~Pool()
870 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.
871 delete ev->event_pool();
876 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
878 if (Splash::instance()) {
879 Splash::instance()->pop_back_for (win);
884 ARDOUR_UI::configure_timeout ()
886 if (last_configure_time == 0) {
887 /* no configure events yet */
891 /* force a gap of 0.5 seconds since the last configure event
894 if (get_microseconds() - last_configure_time < 500000) {
897 have_configure_timeout = false;
898 save_ardour_state ();
904 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
906 if (have_configure_timeout) {
907 last_configure_time = get_microseconds();
909 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
910 have_configure_timeout = true;
917 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
921 if (node.get_property ("roll", str)){
922 roll_controllable->set_id (str);
924 if (node.get_property ("stop", str)) {
925 stop_controllable->set_id (str);
927 if (node.get_property ("goto-start", str)) {
928 goto_start_controllable->set_id (str);
930 if (node.get_property ("goto-end", str)) {
931 goto_end_controllable->set_id (str);
933 if (node.get_property ("auto-loop", str)) {
934 auto_loop_controllable->set_id (str);
936 if (node.get_property ("play-selection", str)) {
937 play_selection_controllable->set_id (str);
939 if (node.get_property ("rec", str)) {
940 rec_controllable->set_id (str);
942 if (node.get_property ("shuttle", str)) {
943 shuttle_box.controllable()->set_id (str);
948 ARDOUR_UI::get_transport_controllable_state ()
950 XMLNode* node = new XMLNode(X_("TransportControllables"));
952 node->set_property (X_("roll"), roll_controllable->id());
953 node->set_property (X_("stop"), stop_controllable->id());
954 node->set_property (X_("goto-start"), goto_start_controllable->id());
955 node->set_property (X_("goto-end"), goto_end_controllable->id());
956 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
957 node->set_property (X_("play-selection"), play_selection_controllable->id());
958 node->set_property (X_("rec"), rec_controllable->id());
959 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
965 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
968 _session->save_state (snapshot_name);
973 ARDOUR_UI::autosave_session ()
975 if (g_main_depth() > 1) {
976 /* inside a recursive main loop,
977 give up because we may not be able to
983 if (!Config->get_periodic_safety_backups()) {
988 _session->maybe_write_autosave();
995 ARDOUR_UI::session_dirty_changed ()
1002 ARDOUR_UI::update_autosave ()
1004 if (_session && _session->dirty()) {
1005 if (_autosave_connection.connected()) {
1006 _autosave_connection.disconnect();
1009 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1010 Config->get_periodic_safety_backup_interval() * 1000);
1013 if (_autosave_connection.connected()) {
1014 _autosave_connection.disconnect();
1020 ARDOUR_UI::check_announcements ()
1023 string _annc_filename;
1026 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1027 #elif defined PLATFORM_WINDOWS
1028 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1030 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1032 _annc_filename.append (VERSIONSTRING);
1034 _announce_string = "";
1036 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1037 FILE* fin = g_fopen (path.c_str(), "rb");
1039 while (!feof (fin)) {
1042 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1045 _announce_string.append (tmp, len);
1050 pingback (VERSIONSTRING, path);
1055 _hide_splash (gpointer arg)
1057 ((ARDOUR_UI*)arg)->hide_splash();
1062 ARDOUR_UI::starting ()
1064 Application* app = Application::instance ();
1065 const char *nsm_url;
1066 bool brand_new_user = ArdourStartup::required ();
1068 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1069 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1071 if (ARDOUR_COMMAND_LINE::check_announcements) {
1072 check_announcements ();
1077 /* we need to create this early because it may need to set the
1078 * audio backend end up.
1082 audio_midi_setup.get (true);
1084 std::cerr << "audio-midi engine setup failed."<< std::endl;
1088 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1089 nsm = new NSM_Client;
1090 if (!nsm->init (nsm_url)) {
1091 /* the ardour executable may have different names:
1093 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1094 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1095 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1097 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1099 const char *process_name = g_getenv ("ARDOUR_SELF");
1100 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1103 // wait for announce reply from nsm server
1104 for ( i = 0; i < 5000; ++i) {
1108 if (nsm->is_active()) {
1113 error << _("NSM server did not announce itself") << endmsg;
1116 // wait for open command from nsm server
1117 for ( i = 0; i < 5000; ++i) {
1119 Glib::usleep (1000);
1120 if (nsm->client_id ()) {
1126 error << _("NSM: no client ID provided") << endmsg;
1130 if (_session && nsm) {
1131 _session->set_nsm_state( nsm->is_active() );
1133 error << _("NSM: no session created") << endmsg;
1137 // nsm requires these actions disabled
1138 vector<string> action_names;
1139 action_names.push_back("SaveAs");
1140 action_names.push_back("Rename");
1141 action_names.push_back("New");
1142 action_names.push_back("Open");
1143 action_names.push_back("Recent");
1144 action_names.push_back("Close");
1146 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1147 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1149 act->set_sensitive (false);
1156 error << _("NSM: initialization failed") << endmsg;
1162 if (brand_new_user) {
1163 _initial_verbose_plugin_scan = true;
1168 _initial_verbose_plugin_scan = false;
1169 switch (s.response ()) {
1170 case Gtk::RESPONSE_OK:
1177 // TODO: maybe IFF brand_new_user
1178 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1179 std::string dspd (Config->get_default_session_parent_dir());
1180 Searchpath ds (ARDOUR::ardour_data_search_path());
1181 ds.add_subdirectory_to_paths ("sessions");
1182 vector<string> demos;
1183 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1185 ARDOUR::RecentSessions rs;
1186 ARDOUR::read_recent_sessions (rs);
1188 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1189 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1190 std::string name = basename_nosuffix (basename_nosuffix (*i));
1191 std::string path = Glib::build_filename (dspd, name);
1192 /* skip if session-dir already exists */
1193 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1196 /* skip sessions that are already in 'recent'.
1197 * eg. a new user changed <session-default-dir> shorly after installation
1199 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1200 if ((*r).first == name) {
1205 PBD::FileArchive ar (*i);
1206 if (0 == ar.inflate (dspd)) {
1207 store_recent_sessions (name, path);
1208 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1214 #ifdef NO_PLUGIN_STATE
1216 ARDOUR::RecentSessions rs;
1217 ARDOUR::read_recent_sessions (rs);
1219 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1221 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1223 /* already used Ardour, have sessions ... warn about plugin state */
1225 ArdourDialog d (_("Free/Demo Version Warning"), true);
1227 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1228 CheckButton c (_("Don't warn me about this again"));
1230 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"),
1231 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1232 _("It will not restore OR save any plugin settings"),
1233 _("If you load an existing session with plugin settings\n"
1234 "they will not be used and will be lost."),
1235 _("To get full access to updates without this limitation\n"
1236 "consider becoming a subscriber for a low cost every month.")));
1237 l.set_justify (JUSTIFY_CENTER);
1239 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1241 d.get_vbox()->pack_start (l, true, true);
1242 d.get_vbox()->pack_start (b, false, false, 12);
1243 d.get_vbox()->pack_start (c, false, false, 12);
1245 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1246 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1250 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1252 if (d.run () != RESPONSE_OK) {
1258 /* go get a session */
1260 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1262 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1263 std::cerr << "Cannot get session parameters."<< std::endl;
1270 WM::Manager::instance().show_visible ();
1272 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1273 * editor window, and we may want stuff to be hidden.
1275 _status_bar_visibility.update ();
1277 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1279 /* all other dialogs are created conditionally */
1285 ARDOUR_UI::check_memory_locking ()
1287 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1288 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1292 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1294 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1296 struct rlimit limits;
1298 long pages, page_size;
1300 size_t pages_len=sizeof(pages);
1301 if ((page_size = getpagesize()) < 0 ||
1302 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1304 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1309 ram = (int64_t) pages * (int64_t) page_size;
1312 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1316 if (limits.rlim_cur != RLIM_INFINITY) {
1318 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1322 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1323 "This might cause %1 to run out of memory before your system "
1324 "runs out of memory. \n\n"
1325 "You can view the memory limit with 'ulimit -l', "
1326 "and it is normally controlled by %2"),
1329 X_("/etc/login.conf")
1331 X_(" /etc/security/limits.conf")
1335 msg.set_default_response (RESPONSE_OK);
1337 VBox* vbox = msg.get_vbox();
1339 CheckButton cb (_("Do not show this window again"));
1340 hbox.pack_start (cb, true, false);
1341 vbox->pack_start (hbox);
1346 pop_back_splash (msg);
1350 if (cb.get_active()) {
1351 XMLNode node (X_("no-memory-warning"));
1352 Config->add_instant_xml (node);
1357 #endif // !__APPLE__
1362 ARDOUR_UI::queue_finish ()
1364 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1368 ARDOUR_UI::idle_finish ()
1371 return false; /* do not call again */
1378 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1380 if (_session->dirty()) {
1381 vector<string> actions;
1382 actions.push_back (_("Don't quit"));
1383 actions.push_back (_("Just quit"));
1384 actions.push_back (_("Save and quit"));
1385 switch (ask_about_saving_session(actions)) {
1390 /* use the default name */
1391 if (save_state_canfail ("")) {
1392 /* failed - don't quit */
1393 MessageDialog msg (_main_window,
1394 string_compose (_("\
1395 %1 was unable to save your session.\n\n\
1396 If you still wish to quit, please use the\n\n\
1397 \"Just quit\" option."), PROGRAM_NAME));
1398 pop_back_splash(msg);
1408 second_connection.disconnect ();
1409 point_one_second_connection.disconnect ();
1410 point_zero_something_second_connection.disconnect();
1411 fps_connection.disconnect();
1414 delete ARDOUR_UI::instance()->video_timeline;
1415 ARDOUR_UI::instance()->video_timeline = NULL;
1416 stop_video_server();
1418 /* Save state before deleting the session, as that causes some
1419 windows to be destroyed before their visible state can be
1422 save_ardour_state ();
1424 if (key_editor.get (false)) {
1425 key_editor->disconnect ();
1428 close_all_dialogs ();
1431 _session->set_clean ();
1432 _session->remove_pending_capture_state ();
1437 halt_connection.disconnect ();
1438 AudioEngine::instance()->stop ();
1439 #ifdef WINDOWS_VST_SUPPORT
1440 fst_stop_threading();
1446 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1448 ArdourDialog window (_("Unsaved Session"));
1449 Gtk::HBox dhbox; // the hbox for the image and text
1450 Gtk::Label prompt_label;
1451 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1455 assert (actions.size() >= 3);
1457 window.add_button (actions[0], RESPONSE_REJECT);
1458 window.add_button (actions[1], RESPONSE_APPLY);
1459 window.add_button (actions[2], RESPONSE_ACCEPT);
1461 window.set_default_response (RESPONSE_ACCEPT);
1463 Gtk::Button noquit_button (msg);
1464 noquit_button.set_name ("EditorGTKButton");
1468 if (_session->snap_name() == _session->name()) {
1469 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?"),
1470 _session->snap_name());
1472 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?"),
1473 _session->snap_name());
1476 prompt_label.set_text (prompt);
1477 prompt_label.set_name (X_("PrompterLabel"));
1478 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1480 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1481 dhbox.set_homogeneous (false);
1482 dhbox.pack_start (*dimage, false, false, 5);
1483 dhbox.pack_start (prompt_label, true, false, 5);
1484 window.get_vbox()->pack_start (dhbox);
1486 window.set_name (_("Prompter"));
1487 window.set_modal (true);
1488 window.set_resizable (false);
1491 prompt_label.show();
1496 ResponseType r = (ResponseType) window.run();
1501 case RESPONSE_ACCEPT: // save and get out of here
1503 case RESPONSE_APPLY: // get out of here
1514 ARDOUR_UI::every_second ()
1517 update_disk_space ();
1518 update_timecode_format ();
1519 update_peak_thread_work ();
1521 if (nsm && nsm->is_active ()) {
1524 if (!_was_dirty && _session->dirty ()) {
1528 else if (_was_dirty && !_session->dirty ()){
1536 ARDOUR_UI::every_point_one_seconds ()
1538 if (editor) editor->build_region_boundary_cache();
1542 ARDOUR_UI::every_point_zero_something_seconds ()
1544 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1546 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1547 float mpeak = editor_meter->update_meters();
1548 if (mpeak > editor_meter_max_peak) {
1549 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1550 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1557 ARDOUR_UI::set_fps_timeout_connection ()
1559 unsigned int interval = 40;
1560 if (!_session) return;
1561 if (_session->timecode_frames_per_second() != 0) {
1562 /* ideally we'll use a select() to sleep and not accumulate
1563 * idle time to provide a regular periodic signal.
1564 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1565 * However, that'll require a dedicated thread and cross-thread
1566 * signals to the GUI Thread..
1568 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1569 * _session->sample_rate() / _session->nominal_sample_rate()
1570 / _session->timecode_frames_per_second()
1572 #ifdef PLATFORM_WINDOWS
1573 // the smallest windows scheduler time-slice is ~15ms.
1574 // periodic GUI timeouts shorter than that will cause
1575 // WaitForSingleObject to spinlock (100% of one CPU Core)
1576 // and gtk never enters idle mode.
1577 // also changing timeBeginPeriod(1) does not affect that in
1578 // any beneficial way, so we just limit the max rate for now.
1579 interval = std::max(30u, interval); // at most ~33Hz.
1581 interval = std::max(8u, interval); // at most 120Hz.
1584 fps_connection.disconnect();
1585 Timers::set_fps_interval (interval);
1589 ARDOUR_UI::update_sample_rate (samplecnt_t)
1593 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1595 if (!AudioEngine::instance()->connected()) {
1597 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1601 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1604 /* no sample rate available */
1605 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1608 if (fmod (rate, 1000.0) != 0.0) {
1609 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1610 (float) rate / 1000.0f,
1611 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1613 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1615 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1619 sample_rate_label.set_markup (buf);
1623 ARDOUR_UI::update_format ()
1626 format_label.set_text ("");
1631 s << _("File:") << X_(" <span foreground=\"green\">");
1633 switch (_session->config.get_native_file_header_format ()) {
1665 switch (_session->config.get_native_file_data_format ()) {
1679 format_label.set_markup (s.str ());
1683 ARDOUR_UI::update_cpu_load ()
1685 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1686 double const c = AudioEngine::instance()->get_dsp_load ();
1688 const char* const bg = c > 90 ? " background=\"red\"" : "";
1692 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1694 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1696 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1699 dsp_load_label.set_markup (buf);
1702 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1704 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1706 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1709 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1713 ARDOUR_UI::update_peak_thread_work ()
1716 const int c = SourceFactory::peak_work_queue_length ();
1718 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1719 peak_thread_work_label.set_markup (buf);
1721 peak_thread_work_label.set_markup (X_(""));
1726 ARDOUR_UI::count_recenabled_streams (Route& route)
1728 Track* track = dynamic_cast<Track*>(&route);
1729 if (track && track->rec_enable_control()->get_value()) {
1730 rec_enabled_streams += track->n_inputs().n_total();
1735 ARDOUR_UI::format_disk_space_label (float remain_sec)
1737 if (remain_sec < 0) {
1738 disk_space_label.set_text (_("N/A"));
1739 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1745 int sec = floor (remain_sec);
1746 int hrs = sec / 3600;
1747 int mins = (sec / 60) % 60;
1748 int secs = sec % 60;
1749 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1750 ArdourWidgets::set_tooltip (disk_space_label, buf);
1752 if (remain_sec > 86400) {
1753 disk_space_label.set_text (_("Rec: >24h"));
1755 } else if (remain_sec > 32400 /* 9 hours */) {
1756 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1757 } else if (remain_sec > 5940 /* 99 mins */) {
1758 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1760 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1762 disk_space_label.set_text (buf);
1767 ARDOUR_UI::update_disk_space()
1769 if (_session == 0) {
1770 format_disk_space_label (-1);
1774 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1775 samplecnt_t fr = _session->sample_rate();
1778 /* skip update - no SR available */
1779 format_disk_space_label (-1);
1784 /* Available space is unknown */
1785 format_disk_space_label (-1);
1786 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1787 format_disk_space_label (max_samplecnt);
1789 rec_enabled_streams = 0;
1790 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1792 samplecnt_t samples = opt_samples.get_value_or (0);
1794 if (rec_enabled_streams) {
1795 samples /= rec_enabled_streams;
1798 format_disk_space_label (samples / (float)fr);
1804 ARDOUR_UI::update_timecode_format ()
1810 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1811 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1813 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1814 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1819 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1820 matching ? X_("green") : X_("red"),
1821 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1823 snprintf (buf, sizeof (buf), "TC: n/a");
1826 timecode_format_label.set_markup (buf);
1830 ARDOUR_UI::update_wall_clock ()
1834 static int last_min = -1;
1837 tm_now = localtime (&now);
1838 if (last_min != tm_now->tm_min) {
1840 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1841 wall_clock_label.set_text (buf);
1842 last_min = tm_now->tm_min;
1849 ARDOUR_UI::open_recent_session ()
1851 bool can_return = (_session != 0);
1853 SessionDialog recent_session_dialog;
1857 ResponseType r = (ResponseType) recent_session_dialog.run ();
1860 case RESPONSE_ACCEPT:
1864 recent_session_dialog.hide();
1871 recent_session_dialog.hide();
1875 std::string path = recent_session_dialog.session_folder();
1876 std::string state = recent_session_dialog.session_name (should_be_new);
1878 if (should_be_new == true) {
1882 _session_is_new = false;
1884 if (load_session (path, state) == 0) {
1893 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1895 if (!AudioEngine::instance()->connected()) {
1896 MessageDialog msg (parent, string_compose (
1897 _("%1 is not connected to any audio backend.\n"
1898 "You cannot open or close sessions in this condition"),
1900 pop_back_splash (msg);
1908 ARDOUR_UI::open_session ()
1910 if (!check_audioengine (_main_window)) {
1914 /* ardour sessions are folders */
1915 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1916 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1917 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1918 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1921 string session_parent_dir = Glib::path_get_dirname(_session->path());
1922 open_session_selector.set_current_folder(session_parent_dir);
1924 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1927 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1929 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1930 string default_session_folder = Config->get_default_session_parent_dir();
1931 open_session_selector.add_shortcut_folder (default_session_folder);
1933 catch (Glib::Error const& e) {
1934 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1937 FileFilter session_filter;
1938 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1939 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1940 open_session_selector.add_filter (session_filter);
1942 FileFilter archive_filter;
1943 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1944 archive_filter.set_name (_("Session Archives"));
1946 open_session_selector.add_filter (archive_filter);
1948 open_session_selector.set_filter (session_filter);
1950 int response = open_session_selector.run();
1951 open_session_selector.hide ();
1953 if (response == Gtk::RESPONSE_CANCEL) {
1957 string session_path = open_session_selector.get_filename();
1961 if (session_path.length() > 0) {
1962 int rv = ARDOUR::inflate_session (session_path,
1963 Config->get_default_session_parent_dir(), path, name);
1965 _session_is_new = false;
1966 load_session (path, name);
1969 MessageDialog msg (_main_window,
1970 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1973 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1974 _session_is_new = isnew;
1975 load_session (path, name);
1981 ARDOUR_UI::session_add_mixed_track (
1982 const ChanCount& input,
1983 const ChanCount& output,
1984 RouteGroup* route_group,
1986 const string& name_template,
1988 PluginInfoPtr instrument,
1989 Plugin::PresetRecord* pset,
1990 ARDOUR::PresentationInfo::order_t order)
1994 if (Profile->get_mixbus ()) {
1999 list<boost::shared_ptr<MidiTrack> > tracks;
2000 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2002 if (tracks.size() != how_many) {
2003 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2008 display_insufficient_ports_message ();
2014 ARDOUR_UI::session_add_midi_bus (
2015 RouteGroup* route_group,
2017 const string& name_template,
2019 PluginInfoPtr instrument,
2020 Plugin::PresetRecord* pset,
2021 ARDOUR::PresentationInfo::order_t order)
2023 if (_session == 0) {
2024 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2028 if (Profile->get_mixbus ()) {
2034 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2035 if (routes.size() != how_many) {
2036 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2041 display_insufficient_ports_message ();
2047 ARDOUR_UI::session_add_midi_route (
2049 RouteGroup* route_group,
2051 const string& name_template,
2053 PluginInfoPtr instrument,
2054 Plugin::PresetRecord* pset,
2055 ARDOUR::PresentationInfo::order_t order)
2057 ChanCount one_midi_channel;
2058 one_midi_channel.set (DataType::MIDI, 1);
2061 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2063 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2068 ARDOUR_UI::session_add_audio_route (
2070 int32_t input_channels,
2071 int32_t output_channels,
2072 ARDOUR::TrackMode mode,
2073 RouteGroup* route_group,
2075 string const & name_template,
2077 ARDOUR::PresentationInfo::order_t order)
2079 list<boost::shared_ptr<AudioTrack> > tracks;
2086 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2088 if (tracks.size() != how_many) {
2089 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2095 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2097 if (routes.size() != how_many) {
2098 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2105 display_insufficient_ports_message ();
2110 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2111 (*i)->set_strict_io (true);
2113 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2114 (*i)->set_strict_io (true);
2120 ARDOUR_UI::display_insufficient_ports_message ()
2122 MessageDialog msg (_main_window,
2123 string_compose (_("There are insufficient ports available\n\
2124 to create a new track or bus.\n\
2125 You should save %1, exit and\n\
2126 restart with more ports."), PROGRAM_NAME));
2127 pop_back_splash (msg);
2132 ARDOUR_UI::transport_goto_start ()
2135 _session->goto_start();
2137 /* force displayed area in editor to start no matter
2138 what "follow playhead" setting is.
2142 editor->center_screen (_session->current_start_sample ());
2148 ARDOUR_UI::transport_goto_zero ()
2151 _session->request_locate (0);
2153 /* force displayed area in editor to start no matter
2154 what "follow playhead" setting is.
2158 editor->reset_x_origin (0);
2164 ARDOUR_UI::transport_goto_wallclock ()
2166 if (_session && editor) {
2170 samplepos_t samples;
2173 localtime_r (&now, &tmnow);
2175 samplecnt_t sample_rate = _session->sample_rate();
2177 if (sample_rate == 0) {
2178 /* no frame rate available */
2182 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2183 samples += tmnow.tm_min * (60 * sample_rate);
2184 samples += tmnow.tm_sec * sample_rate;
2186 _session->request_locate (samples, _session->transport_rolling ());
2188 /* force displayed area in editor to start no matter
2189 what "follow playhead" setting is.
2193 editor->center_screen (samples);
2199 ARDOUR_UI::transport_goto_end ()
2202 samplepos_t const sample = _session->current_end_sample();
2203 _session->request_locate (sample);
2205 /* force displayed area in editor to start no matter
2206 what "follow playhead" setting is.
2210 editor->center_screen (sample);
2216 ARDOUR_UI::transport_stop ()
2222 if (_session->is_auditioning()) {
2223 _session->cancel_audition ();
2227 _session->request_stop (false, true);
2230 /** Check if any tracks are record enabled. If none are, record enable all of them.
2231 * @return true if track record-enabled status was changed, false otherwise.
2234 ARDOUR_UI::trx_record_enable_all_tracks ()
2240 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2241 bool none_record_enabled = true;
2243 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2244 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2247 if (t->rec_enable_control()->get_value()) {
2248 none_record_enabled = false;
2253 if (none_record_enabled) {
2254 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2257 return none_record_enabled;
2261 ARDOUR_UI::transport_record (bool roll)
2264 switch (_session->record_status()) {
2265 case Session::Disabled:
2266 if (_session->ntracks() == 0) {
2267 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."));
2271 if (Profile->get_trx()) {
2272 roll = trx_record_enable_all_tracks ();
2274 _session->maybe_enable_record ();
2279 case Session::Recording:
2281 _session->request_stop();
2283 _session->disable_record (false, true);
2287 case Session::Enabled:
2288 _session->disable_record (false, true);
2294 ARDOUR_UI::transport_roll ()
2300 if (_session->is_auditioning()) {
2305 if (_session->config.get_external_sync()) {
2306 switch (Config->get_sync_source()) {
2310 /* transport controlled by the master */
2316 bool rolling = _session->transport_rolling();
2318 if (_session->get_play_loop()) {
2320 /* If loop playback is not a mode, then we should cancel
2321 it when this action is requested. If it is a mode
2322 we just leave it in place.
2325 if (!Config->get_loop_is_mode()) {
2326 /* XXX it is not possible to just leave seamless loop and keep
2327 playing at present (nov 4th 2009)
2329 if (!Config->get_seamless_loop()) {
2330 /* stop loop playback and stop rolling */
2331 _session->request_play_loop (false, true);
2332 } else if (rolling) {
2333 /* stop loop playback but keep rolling */
2334 _session->request_play_loop (false, false);
2338 } else if (_session->get_play_range () ) {
2339 /* stop playing a range if we currently are */
2340 _session->request_play_range (0, true);
2344 _session->request_transport_speed (1.0f);
2349 ARDOUR_UI::get_smart_mode() const
2351 return ( editor->get_smart_mode() );
2356 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2362 if (_session->is_auditioning()) {
2363 _session->cancel_audition ();
2367 if (_session->config.get_external_sync()) {
2368 switch (Config->get_sync_source()) {
2372 /* transport controlled by the master */
2377 bool rolling = _session->transport_rolling();
2378 bool affect_transport = true;
2380 if (rolling && roll_out_of_bounded_mode) {
2381 /* drop out of loop/range playback but leave transport rolling */
2382 if (_session->get_play_loop()) {
2383 if (_session->actively_recording()) {
2385 /* just stop using the loop, then actually stop
2388 _session->request_play_loop (false, affect_transport);
2391 if (Config->get_seamless_loop()) {
2392 /* the disk buffers contain copies of the loop - we can't
2393 just keep playing, so stop the transport. the user
2394 can restart as they wish.
2396 affect_transport = true;
2398 /* disk buffers are normal, so we can keep playing */
2399 affect_transport = false;
2401 _session->request_play_loop (false, affect_transport);
2403 } else if (_session->get_play_range ()) {
2404 affect_transport = false;
2405 _session->request_play_range (0, true);
2409 if (affect_transport) {
2411 _session->request_stop (with_abort, true);
2413 } else if (!with_abort) { /* with_abort == true means the
2414 * command was intended to stop
2415 * transport, not start.
2418 /* the only external sync condition we can be in here
2419 * would be Engine (JACK) sync, in which case we still
2423 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
2424 _session->request_play_range (&editor->get_selection().time, true);
2425 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2427 _session->request_transport_speed (1.0f);
2433 ARDOUR_UI::toggle_session_auto_loop ()
2439 Location * looploc = _session->locations()->auto_loop_location();
2445 if (_session->get_play_loop()) {
2447 /* looping enabled, our job is to disable it */
2449 _session->request_play_loop (false);
2453 /* looping not enabled, our job is to enable it.
2455 loop-is-NOT-mode: this action always starts the transport rolling.
2456 loop-IS-mode: this action simply sets the loop play mechanism, but
2457 does not start transport.
2459 if (Config->get_loop_is_mode()) {
2460 _session->request_play_loop (true, false);
2462 _session->request_play_loop (true, true);
2466 //show the loop markers
2467 looploc->set_hidden (false, this);
2471 ARDOUR_UI::transport_play_selection ()
2477 editor->play_selection ();
2481 ARDOUR_UI::transport_play_preroll ()
2486 editor->play_with_preroll ();
2490 ARDOUR_UI::transport_rec_preroll ()
2495 editor->rec_with_preroll ();
2499 ARDOUR_UI::transport_rec_count_in ()
2504 editor->rec_with_count_in ();
2508 ARDOUR_UI::transport_rewind (int option)
2510 float current_transport_speed;
2513 current_transport_speed = _session->transport_speed();
2515 if (current_transport_speed >= 0.0f) {
2518 _session->request_transport_speed (-1.0f);
2521 _session->request_transport_speed (-4.0f);
2524 _session->request_transport_speed (-0.5f);
2529 _session->request_transport_speed (current_transport_speed * 1.5f);
2535 ARDOUR_UI::transport_forward (int option)
2541 float current_transport_speed = _session->transport_speed();
2543 if (current_transport_speed <= 0.0f) {
2546 _session->request_transport_speed (1.0f);
2549 _session->request_transport_speed (4.0f);
2552 _session->request_transport_speed (0.5f);
2557 _session->request_transport_speed (current_transport_speed * 1.5f);
2562 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2568 boost::shared_ptr<Route> r;
2570 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2572 boost::shared_ptr<Track> t;
2574 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2575 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2581 ARDOUR_UI::map_transport_state ()
2584 layered_button.set_sensitive (false);
2588 shuttle_box.map_transport_state ();
2590 float sp = _session->transport_speed();
2593 layered_button.set_sensitive (!_session->actively_recording ());
2595 layered_button.set_sensitive (true);
2596 update_disk_space ();
2601 ARDOUR_UI::blink_handler (bool blink_on)
2603 sync_blink (blink_on);
2605 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2608 error_blink (blink_on);
2609 solo_blink (blink_on);
2610 audition_blink (blink_on);
2611 feedback_blink (blink_on);
2615 ARDOUR_UI::update_clocks ()
2617 if (!_session) return;
2619 if (editor && !editor->dragging_playhead()) {
2620 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2625 ARDOUR_UI::start_clocking ()
2627 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2628 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2630 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2635 ARDOUR_UI::stop_clocking ()
2637 clock_signal_connection.disconnect ();
2641 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2645 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2647 label->set_text (buf);
2648 bar->set_fraction (fraction);
2650 /* process events, redraws, etc. */
2652 while (gtk_events_pending()) {
2653 gtk_main_iteration ();
2656 return true; /* continue with save-as */
2660 ARDOUR_UI::save_session_as ()
2666 if (_session->dirty()) {
2667 vector<string> actions;
2668 actions.push_back (_("Abort save-as"));
2669 actions.push_back (_("Don't save now, just save-as"));
2670 actions.push_back (_("Save it first"));
2671 switch (ask_about_saving_session(actions)) {
2676 if (save_state_canfail ("")) {
2677 MessageDialog msg (_main_window,
2678 string_compose (_("\
2679 %1 was unable to save your session.\n\n\
2680 If you still wish to proceed, please use the\n\n\
2681 \"Don't save now\" option."), PROGRAM_NAME));
2682 pop_back_splash(msg);
2688 _session->remove_pending_capture_state ();
2693 if (!save_as_dialog) {
2694 save_as_dialog = new SaveAsDialog;
2697 save_as_dialog->set_name (_session->name());
2699 int response = save_as_dialog->run ();
2701 save_as_dialog->hide ();
2704 case Gtk::RESPONSE_OK:
2713 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2714 sa.new_name = save_as_dialog->new_name ();
2715 sa.switch_to = save_as_dialog->switch_to();
2716 sa.copy_media = save_as_dialog->copy_media();
2717 sa.copy_external = save_as_dialog->copy_external();
2718 sa.include_media = save_as_dialog->include_media ();
2720 /* Only bother with a progress dialog if we're going to copy
2721 media into the save-as target. Without that choice, this
2722 will be very fast because we're only talking about a few kB's to
2723 perhaps a couple of MB's of data.
2726 ArdourDialog progress_dialog (_("Save As"), true);
2729 if (sa.include_media && sa.copy_media) {
2731 Gtk::Label* label = manage (new Gtk::Label());
2732 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2734 progress_dialog.get_vbox()->pack_start (*label);
2735 progress_dialog.get_vbox()->pack_start (*progress_bar);
2737 progress_bar->show ();
2739 /* this signal will be emitted from within this, the calling thread,
2740 * after every file is copied. It provides information on percentage
2741 * complete (in terms of total data to copy), the number of files
2742 * copied so far, and the total number to copy.
2745 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2747 progress_dialog.show_all ();
2748 progress_dialog.present ();
2751 if (_session->save_as (sa)) {
2753 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2757 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2758 * the trick is this: if the new session was copy with media included,
2759 * then Session::save_as() will have already done a neat trick to avoid
2760 * us having to unload and load the new state. But if the media was not
2761 * included, then this is required (it avoids us having to otherwise
2762 * drop all references to media (sources).
2765 if (!sa.include_media && sa.switch_to) {
2766 unload_session (false);
2767 load_session (sa.final_session_folder_name, sa.new_name);
2772 ARDOUR_UI::archive_session ()
2780 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2782 SessionArchiveDialog sad;
2783 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2784 int response = sad.run ();
2786 if (response != Gtk::RESPONSE_OK) {
2791 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2792 MessageDialog msg (_("Session Archiving failed."));
2798 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2802 struct tm local_time;
2805 localtime_r (&n, &local_time);
2806 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2807 if (switch_to_it && _session->dirty ()) {
2808 save_state_canfail ("");
2811 save_state (timebuf, switch_to_it);
2816 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2820 prompter.get_result (snapname);
2822 bool do_save = (snapname.length() != 0);
2825 char illegal = Session::session_name_is_legal(snapname);
2827 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2828 "snapshot names may not contain a '%1' character"), illegal));
2834 vector<std::string> p;
2835 get_state_files_in_directory (_session->session_directory().root_path(), p);
2836 vector<string> n = get_file_names_no_extension (p);
2838 if (find (n.begin(), n.end(), snapname) != n.end()) {
2840 do_save = overwrite_file_dialog (prompter,
2841 _("Confirm Snapshot Overwrite"),
2842 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2846 save_state (snapname, switch_to_it);
2856 /** Ask the user for the name of a new snapshot and then take it.
2860 ARDOUR_UI::snapshot_session (bool switch_to_it)
2862 if (switch_to_it && _session->dirty()) {
2863 vector<string> actions;
2864 actions.push_back (_("Abort saving snapshot"));
2865 actions.push_back (_("Don't save now, just snapshot"));
2866 actions.push_back (_("Save it first"));
2867 switch (ask_about_saving_session(actions)) {
2872 if (save_state_canfail ("")) {
2873 MessageDialog msg (_main_window,
2874 string_compose (_("\
2875 %1 was unable to save your session.\n\n\
2876 If you still wish to proceed, please use the\n\n\
2877 \"Don't save now\" option."), PROGRAM_NAME));
2878 pop_back_splash(msg);
2884 _session->remove_pending_capture_state ();
2889 Prompter prompter (true);
2890 prompter.set_name ("Prompter");
2891 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2893 prompter.set_title (_("Snapshot and switch"));
2894 prompter.set_prompt (_("New session name"));
2896 prompter.set_title (_("Take Snapshot"));
2897 prompter.set_prompt (_("Name of new snapshot"));
2901 prompter.set_initial_text (_session->snap_name());
2903 Glib::DateTime tm (g_date_time_new_now_local ());
2904 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2907 bool finished = false;
2909 switch (prompter.run()) {
2910 case RESPONSE_ACCEPT:
2912 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2923 /** Ask the user for a new session name and then rename the session to it.
2927 ARDOUR_UI::rename_session ()
2933 Prompter prompter (true);
2936 prompter.set_name ("Prompter");
2937 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2938 prompter.set_title (_("Rename Session"));
2939 prompter.set_prompt (_("New session name"));
2942 switch (prompter.run()) {
2943 case RESPONSE_ACCEPT:
2945 prompter.get_result (name);
2947 bool do_rename = (name.length() != 0);
2950 char illegal = Session::session_name_is_legal (name);
2953 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2954 "session names may not contain a '%1' character"), illegal));
2959 switch (_session->rename (name)) {
2961 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2962 msg.set_position (WIN_POS_MOUSE);
2970 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2971 msg.set_position (WIN_POS_MOUSE);
2987 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2989 if (!_session || _session->deletion_in_progress()) {
2993 XMLNode* node = new XMLNode (X_("UI"));
2995 WM::Manager::instance().add_state (*node);
2997 node->add_child_nocopy (gui_object_state->get_state());
2999 _session->add_extra_xml (*node);
3001 if (export_video_dialog) {
3002 _session->add_extra_xml (export_video_dialog->get_state());
3005 save_state_canfail (name, switch_to_it);
3009 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3014 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3019 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3024 ARDOUR_UI::primary_clock_value_changed ()
3027 _session->request_locate (primary_clock->current_time ());
3032 ARDOUR_UI::big_clock_value_changed ()
3035 _session->request_locate (big_clock->current_time ());
3040 ARDOUR_UI::secondary_clock_value_changed ()
3043 _session->request_locate (secondary_clock->current_time ());
3047 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3049 if (response == RESPONSE_ACCEPT) {
3050 const string name = d->get_template_name ();
3051 const string desc = d->get_description ();
3053 int failed = _session->save_template (name, desc);
3055 if (failed == -2) { /* file already exists. */
3056 bool overwrite = overwrite_file_dialog (*d,
3057 _("Confirm Template Overwrite"),
3058 _("A template already exists with that name. Do you want to overwrite it?"));
3061 _session->save_template (name, desc, true);
3073 ARDOUR_UI::save_template ()
3075 if (!check_audioengine (_main_window)) {
3079 const std::string desc = SessionMetadata::Metadata()->description ();
3080 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3081 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3085 void ARDOUR_UI::manage_templates ()
3092 ARDOUR_UI::edit_metadata ()
3094 SessionMetadataEditor dialog;
3095 dialog.set_session (_session);
3096 dialog.grab_focus ();
3101 ARDOUR_UI::import_metadata ()
3103 SessionMetadataImporter dialog;
3104 dialog.set_session (_session);
3109 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3111 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3113 MessageDialog msg (str,
3115 Gtk::MESSAGE_WARNING,
3116 Gtk::BUTTONS_YES_NO,
3120 msg.set_name (X_("OpenExistingDialog"));
3121 msg.set_title (_("Open Existing Session"));
3122 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3123 msg.set_position (Gtk::WIN_POS_CENTER);
3124 pop_back_splash (msg);
3126 switch (msg.run()) {
3135 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3137 BusProfile bus_profile;
3140 bus_profile.master_out_channels = 2;
3142 /* get settings from advanced section of NSD */
3143 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3146 // NULL profile: no master, no monitor
3147 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3155 ARDOUR_UI::load_from_application_api (const std::string& path)
3157 /* OS X El Capitan (and probably later) now somehow passes the command
3158 line arguments to an app via the openFile delegate protocol. Ardour
3159 already does its own command line processing, and having both
3160 pathways active causes crashes. So, if the command line was already
3161 set, do nothing here.
3164 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3168 ARDOUR_COMMAND_LINE::session_name = path;
3170 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3172 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3174 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3175 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3176 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3177 * -> SessionDialog is not displayed
3180 if (_session_dialog) {
3181 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3182 std::string session_path = path;
3183 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3184 session_path = Glib::path_get_dirname (session_path);
3186 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3187 _session_dialog->set_provided_session (session_name, session_path);
3188 _session_dialog->response (RESPONSE_NONE);
3189 _session_dialog->hide();
3194 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3195 /* /path/to/foo => /path/to/foo, foo */
3196 rv = load_session (path, basename_nosuffix (path));
3198 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3199 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3202 // if load_session fails -> pop up SessionDialog.
3204 ARDOUR_COMMAND_LINE::session_name = "";
3206 if (get_session_parameters (true, false)) {
3212 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3214 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3216 string session_name;
3217 string session_path;
3218 string template_name;
3220 bool likely_new = false;
3221 bool cancel_not_quit;
3223 /* deal with any existing DIRTY session now, rather than later. don't
3224 * treat a non-dirty session this way, so that it stays visible
3225 * as we bring up the new session dialog.
3228 if (_session && ARDOUR_UI::instance()->video_timeline) {
3229 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3232 /* if there is already a session, relabel the button
3233 on the SessionDialog so that we don't Quit directly
3235 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3237 if (_session && _session->dirty()) {
3238 if (unload_session (false)) {
3239 /* unload cancelled by user */
3242 ARDOUR_COMMAND_LINE::session_name = "";
3245 if (!load_template.empty()) {
3246 should_be_new = true;
3247 template_name = load_template;
3250 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3251 session_path = ARDOUR_COMMAND_LINE::session_name;
3253 if (!session_path.empty()) {
3254 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3255 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3256 /* session/snapshot file, change path to be dir */
3257 session_path = Glib::path_get_dirname (session_path);
3262 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3264 _session_dialog = &session_dialog;
3267 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3269 /* if they named a specific statefile, use it, otherwise they are
3270 just giving a session folder, and we want to use it as is
3271 to find the session.
3274 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3276 if (suffix != string::npos) {
3277 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3278 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3279 session_name = Glib::path_get_basename (session_name);
3281 session_path = ARDOUR_COMMAND_LINE::session_name;
3282 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3287 session_dialog.clear_given ();
3290 if (should_be_new || session_name.empty()) {
3291 /* need the dialog to get info from user */
3293 cerr << "run dialog\n";
3295 switch (session_dialog.run()) {
3296 case RESPONSE_ACCEPT:
3299 /* this is used for async * app->ShouldLoad(). */
3300 continue; // while loop
3303 if (quit_on_cancel) {
3304 ARDOUR_UI::finish ();
3305 Gtkmm2ext::Application::instance()->cleanup();
3307 pthread_cancel_all ();
3308 return -1; // caller is responsible to call exit()
3314 session_dialog.hide ();
3317 /* if we run the startup dialog again, offer more than just "new session" */
3319 should_be_new = false;
3321 session_name = session_dialog.session_name (likely_new);
3322 session_path = session_dialog.session_folder ();
3329 int rv = ARDOUR::inflate_session (session_name,
3330 Config->get_default_session_parent_dir(), session_path, session_name);
3332 MessageDialog msg (session_dialog,
3333 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3338 session_dialog.set_provided_session (session_name, session_path);
3342 // XXX check archive, inflate
3343 string::size_type suffix = session_name.find (statefile_suffix);
3345 if (suffix != string::npos) {
3346 session_name = session_name.substr (0, suffix);
3349 /* this shouldn't happen, but we catch it just in case it does */
3351 if (session_name.empty()) {
3355 if (session_dialog.use_session_template()) {
3356 template_name = session_dialog.session_template_name();
3357 _session_is_new = true;
3360 if (session_name[0] == G_DIR_SEPARATOR ||
3361 #ifdef PLATFORM_WINDOWS
3362 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3364 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3365 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3370 /* absolute path or cwd-relative path specified for session name: infer session folder
3371 from what was given.
3374 session_path = Glib::path_get_dirname (session_name);
3375 session_name = Glib::path_get_basename (session_name);
3379 session_path = session_dialog.session_folder();
3381 char illegal = Session::session_name_is_legal (session_name);
3384 MessageDialog msg (session_dialog,
3385 string_compose (_("To ensure compatibility with various systems\n"
3386 "session names may not contain a '%1' character"),
3389 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3394 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3397 if (likely_new && !nsm) {
3399 std::string existing = Glib::build_filename (session_path, session_name);
3401 if (!ask_about_loading_existing_session (existing)) {
3402 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3407 _session_is_new = false;
3412 pop_back_splash (session_dialog);
3413 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3415 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3419 char illegal = Session::session_name_is_legal(session_name);
3422 pop_back_splash (session_dialog);
3423 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3424 "session names may not contain a '%1' character"), illegal));
3426 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3430 _session_is_new = true;
3433 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3435 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3436 meta_session_setup (template_name.substr (11));
3438 } else if (likely_new && template_name.empty()) {
3440 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3444 ret = load_session (session_path, session_name, template_name);
3447 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3451 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3452 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3456 /* clear this to avoid endless attempts to load the
3460 ARDOUR_COMMAND_LINE::session_name = "";
3464 _session_dialog = NULL;
3470 ARDOUR_UI::close_session()
3472 if (!check_audioengine (_main_window)) {
3476 if (unload_session (true)) {
3480 ARDOUR_COMMAND_LINE::session_name = "";
3482 if (get_session_parameters (true, false)) {
3487 /** @param snap_name Snapshot name (without .ardour suffix).
3488 * @return -2 if the load failed because we are not connected to the AudioEngine.
3491 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3493 /* load_session calls flush_pending() which allows
3494 * GUI interaction and potentially loading another session
3495 * (that was easy via snapshot sidebar).
3496 * Recursing into load_session() from load_session() and recusive
3497 * event loops causes all kind of crashes.
3499 assert (!session_load_in_progress);
3500 if (session_load_in_progress) {
3503 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3505 Session *new_session;
3510 unload_status = unload_session ();
3512 if (unload_status < 0) {
3514 } else if (unload_status > 0) {
3520 session_loaded = false;
3522 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3525 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3528 /* this one is special */
3530 catch (AudioEngine::PortRegistrationFailure const& err) {
3532 MessageDialog msg (err.what(),
3535 Gtk::BUTTONS_CLOSE);
3537 msg.set_title (_("Port Registration Error"));
3538 msg.set_secondary_text (_("Click the Close button to try again."));
3539 msg.set_position (Gtk::WIN_POS_CENTER);
3540 pop_back_splash (msg);
3543 int response = msg.run ();
3548 case RESPONSE_CANCEL:
3555 catch (SessionException const& e) {
3556 MessageDialog msg (string_compose(
3557 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3558 path, snap_name, e.what()),
3563 msg.set_title (_("Loading Error"));
3564 msg.set_position (Gtk::WIN_POS_CENTER);
3565 pop_back_splash (msg);
3577 MessageDialog msg (string_compose(
3578 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3584 msg.set_title (_("Loading Error"));
3585 msg.set_position (Gtk::WIN_POS_CENTER);
3586 pop_back_splash (msg);
3598 list<string> const u = new_session->unknown_processors ();
3600 MissingPluginDialog d (_session, u);
3605 if (!new_session->writable()) {
3606 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3611 msg.set_title (_("Read-only Session"));
3612 msg.set_position (Gtk::WIN_POS_CENTER);
3613 pop_back_splash (msg);
3620 /* Now the session been created, add the transport controls */
3621 new_session->add_controllable(roll_controllable);
3622 new_session->add_controllable(stop_controllable);
3623 new_session->add_controllable(goto_start_controllable);
3624 new_session->add_controllable(goto_end_controllable);
3625 new_session->add_controllable(auto_loop_controllable);
3626 new_session->add_controllable(play_selection_controllable);
3627 new_session->add_controllable(rec_controllable);
3629 set_session (new_session);
3631 session_loaded = true;
3634 _session->set_clean ();
3637 #ifdef WINDOWS_VST_SUPPORT
3638 fst_stop_threading();
3642 Timers::TimerSuspender t;
3646 #ifdef WINDOWS_VST_SUPPORT
3647 fst_start_threading();
3651 if (!mix_template.empty ()) {
3652 /* if mix_template is given, assume this is a new session */
3653 string metascript = Glib::build_filename (mix_template, "template.lua");
3654 meta_session_setup (metascript);
3659 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3660 * which is queued by set_session().
3661 * If session-loading fails we hide it explicitly.
3662 * This covers both cases in a central place.
3671 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3673 Session *new_session;
3676 session_loaded = false;
3677 x = unload_session ();
3685 _session_is_new = true;
3688 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3691 catch (SessionException const& e) {
3692 cerr << "Here are the errors associated with this failed session:\n";
3694 cerr << "---------\n";
3695 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3696 msg.set_title (_("Loading Error"));
3697 msg.set_position (Gtk::WIN_POS_CENTER);
3698 pop_back_splash (msg);
3703 cerr << "Here are the errors associated with this failed session:\n";
3705 cerr << "---------\n";
3706 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3707 msg.set_title (_("Loading Error"));
3708 msg.set_position (Gtk::WIN_POS_CENTER);
3709 pop_back_splash (msg);
3714 /* Give the new session the default GUI state, if such things exist */
3717 n = Config->instant_xml (X_("Editor"));
3719 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3720 new_session->add_instant_xml (*n, false);
3722 n = Config->instant_xml (X_("Mixer"));
3724 new_session->add_instant_xml (*n, false);
3727 n = Config->instant_xml (X_("Preferences"));
3729 new_session->add_instant_xml (*n, false);
3732 /* Put the playhead at 0 and scroll fully left */
3733 n = new_session->instant_xml (X_("Editor"));
3735 n->set_property (X_("playhead"), X_("0"));
3736 n->set_property (X_("left-frame"), X_("0"));
3739 set_session (new_session);
3741 session_loaded = true;
3743 new_session->save_state(new_session->name());
3749 static void _lua_print (std::string s) {
3751 std::cout << "LuaInstance: " << s << "\n";
3753 PBD::info << "LuaInstance: " << s << endmsg;
3756 std::map<std::string, std::string>
3757 ARDOUR_UI::route_setup_info (const std::string& script_path)
3759 std::map<std::string, std::string> rv;
3761 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3766 lua.Print.connect (&_lua_print);
3769 lua_State* L = lua.getState();
3770 LuaInstance::register_classes (L);
3771 LuaBindings::set_session (L, _session);
3772 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3773 lua_setglobal (L, "Editor");
3775 lua.do_command ("function ardour () end");
3776 lua.do_file (script_path);
3779 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3780 if (!fn.isFunction ()) {
3783 luabridge::LuaRef rs = fn ();
3784 if (!rs.isTable ()) {
3787 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3788 if (!i.key().isString()) {
3791 std::string key = i.key().tostring();
3792 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3793 rv[key] = i.value().tostring();
3796 } catch (luabridge::LuaException const& e) {
3797 cerr << "LuaException:" << e.what () << endl;
3803 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3805 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3808 assert (add_route_dialog);
3811 if ((count = add_route_dialog->count()) <= 0) {
3816 lua.Print.connect (&_lua_print);
3819 lua_State* L = lua.getState();
3820 LuaInstance::register_classes (L);
3821 LuaBindings::set_session (L, _session);
3822 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3823 lua_setglobal (L, "Editor");
3825 lua.do_command ("function ardour () end");
3826 lua.do_file (script_path);
3828 luabridge::LuaRef args (luabridge::newTable (L));
3830 args["name"] = add_route_dialog->name_template ();
3831 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3832 args["group"] = add_route_dialog->route_group ();
3833 args["strict_io"] = add_route_dialog->use_strict_io ();
3834 args["instrument"] = add_route_dialog->requested_instrument ();
3835 args["track_mode"] = add_route_dialog->mode ();
3836 args["channels"] = add_route_dialog->channel_count ();
3837 args["how_many"] = count;
3840 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3841 if (fn.isFunction()) {
3844 } catch (luabridge::LuaException const& e) {
3845 cerr << "LuaException:" << e.what () << endl;
3847 display_insufficient_ports_message ();
3852 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3854 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3859 lua.Print.connect (&_lua_print);
3862 lua_State* L = lua.getState();
3863 LuaInstance::register_classes (L);
3864 LuaBindings::set_session (L, _session);
3865 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3866 lua_setglobal (L, "Editor");
3868 lua.do_command ("function ardour () end");
3869 lua.do_file (script_path);
3872 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3873 if (fn.isFunction()) {
3876 } catch (luabridge::LuaException const& e) {
3877 cerr << "LuaException:" << e.what () << endl;
3879 display_insufficient_ports_message ();
3884 ARDOUR_UI::launch_chat ()
3886 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3888 dialog.set_title (_("About the Chat"));
3889 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."));
3891 switch (dialog.run()) {
3893 open_uri("http://webchat.freenode.net/?channels=ardour");
3901 ARDOUR_UI::launch_manual ()
3903 PBD::open_uri (Config->get_tutorial_manual_url());
3907 ARDOUR_UI::launch_reference ()
3909 PBD::open_uri (Config->get_reference_manual_url());
3913 ARDOUR_UI::launch_tracker ()
3915 PBD::open_uri ("http://tracker.ardour.org");
3919 ARDOUR_UI::launch_subscribe ()
3921 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3925 ARDOUR_UI::launch_cheat_sheet ()
3928 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3930 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3935 ARDOUR_UI::launch_website ()
3937 PBD::open_uri ("http://ardour.org");
3941 ARDOUR_UI::launch_website_dev ()
3943 PBD::open_uri ("http://ardour.org/development.html");
3947 ARDOUR_UI::launch_forums ()
3949 PBD::open_uri ("https://community.ardour.org/forums");
3953 ARDOUR_UI::launch_howto_report ()
3955 PBD::open_uri ("http://ardour.org/reporting_bugs");
3959 ARDOUR_UI::loading_message (const std::string& msg)
3961 if (ARDOUR_COMMAND_LINE::no_splash) {
3969 splash->message (msg);
3973 ARDOUR_UI::show_splash ()
3977 splash = new Splash;
3987 ARDOUR_UI::hide_splash ()
3994 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3998 removed = rep.paths.size();
4001 MessageDialog msgd (_main_window,
4002 _("No files were ready for clean-up"),
4006 msgd.set_title (_("Clean-up"));
4007 msgd.set_secondary_text (_("If this seems surprising, \n\
4008 check for any existing snapshots.\n\
4009 These may still include regions that\n\
4010 require some unused files to continue to exist."));
4016 ArdourDialog results (_("Clean-up"), true, false);
4018 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4019 CleanupResultsModelColumns() {
4023 Gtk::TreeModelColumn<std::string> visible_name;
4024 Gtk::TreeModelColumn<std::string> fullpath;
4028 CleanupResultsModelColumns results_columns;
4029 Glib::RefPtr<Gtk::ListStore> results_model;
4030 Gtk::TreeView results_display;
4032 results_model = ListStore::create (results_columns);
4033 results_display.set_model (results_model);
4034 results_display.append_column (list_title, results_columns.visible_name);
4036 results_display.set_name ("CleanupResultsList");
4037 results_display.set_headers_visible (true);
4038 results_display.set_headers_clickable (false);
4039 results_display.set_reorderable (false);
4041 Gtk::ScrolledWindow list_scroller;
4044 Gtk::HBox dhbox; // the hbox for the image and text
4045 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4046 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4048 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4050 const string dead_directory = _session->session_directory().dead_path();
4053 %1 - number of files removed
4054 %2 - location of "dead"
4055 %3 - size of files affected
4056 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4059 const char* bprefix;
4060 double space_adjusted = 0;
4062 if (rep.space < 1000) {
4064 space_adjusted = rep.space;
4065 } else if (rep.space < 1000000) {
4066 bprefix = _("kilo");
4067 space_adjusted = floorf((float)rep.space / 1000.0);
4068 } else if (rep.space < 1000000 * 1000) {
4069 bprefix = _("mega");
4070 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4072 bprefix = _("giga");
4073 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4077 txt.set_markup (string_compose (P_("\
4078 The following file was deleted from %2,\n\
4079 releasing %3 %4bytes of disk space", "\
4080 The following %1 files were deleted from %2,\n\
4081 releasing %3 %4bytes of disk space", removed),
4082 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4084 txt.set_markup (string_compose (P_("\
4085 The following file was not in use and \n\
4086 has been moved to: %2\n\n\
4087 After a restart of %5\n\n\
4088 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4089 will release an additional %3 %4bytes of disk space.\n", "\
4090 The following %1 files were not in use and \n\
4091 have been moved to: %2\n\n\
4092 After a restart of %5\n\n\
4093 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4094 will release an additional %3 %4bytes of disk space.\n", removed),
4095 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4098 dhbox.pack_start (*dimage, true, false, 5);
4099 dhbox.pack_start (txt, true, false, 5);
4101 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4102 TreeModel::Row row = *(results_model->append());
4103 row[results_columns.visible_name] = *i;
4104 row[results_columns.fullpath] = *i;
4107 list_scroller.add (results_display);
4108 list_scroller.set_size_request (-1, 150);
4109 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4111 dvbox.pack_start (dhbox, true, false, 5);
4112 dvbox.pack_start (list_scroller, true, false, 5);
4113 ddhbox.pack_start (dvbox, true, false, 5);
4115 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4116 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4117 results.set_default_response (RESPONSE_CLOSE);
4118 results.set_position (Gtk::WIN_POS_MOUSE);
4120 results_display.show();
4121 list_scroller.show();
4128 //results.get_vbox()->show();
4129 results.set_resizable (false);
4136 ARDOUR_UI::cleanup ()
4138 if (_session == 0) {
4139 /* shouldn't happen: menu item is insensitive */
4144 MessageDialog checker (_("Are you sure you want to clean-up?"),
4146 Gtk::MESSAGE_QUESTION,
4149 checker.set_title (_("Clean-up"));
4151 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4152 ALL undo/redo information will be lost if you clean-up.\n\
4153 Clean-up will move all unused files to a \"dead\" location."));
4155 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4156 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4157 checker.set_default_response (RESPONSE_CANCEL);
4159 checker.set_name (_("CleanupDialog"));
4160 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4161 checker.set_position (Gtk::WIN_POS_MOUSE);
4163 switch (checker.run()) {
4164 case RESPONSE_ACCEPT:
4170 ARDOUR::CleanupReport rep;
4172 editor->prepare_for_cleanup ();
4174 /* do not allow flush until a session is reloaded */
4176 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4178 act->set_sensitive (false);
4181 if (_session->cleanup_sources (rep)) {
4182 editor->finish_cleanup ();
4186 editor->finish_cleanup ();
4189 display_cleanup_results (rep, _("Cleaned Files"), false);
4193 ARDOUR_UI::flush_trash ()
4195 if (_session == 0) {
4196 /* shouldn't happen: menu item is insensitive */
4200 ARDOUR::CleanupReport rep;
4202 if (_session->cleanup_trash_sources (rep)) {
4206 display_cleanup_results (rep, _("deleted file"), true);
4210 ARDOUR_UI::cleanup_peakfiles ()
4212 if (_session == 0) {
4213 /* shouldn't happen: menu item is insensitive */
4217 if (! _session->can_cleanup_peakfiles ()) {
4221 // get all region-views in this session
4223 TrackViewList empty;
4225 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4226 std::list<RegionView*> views = rs.by_layer();
4228 // remove displayed audio-region-views waveforms
4229 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4230 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4231 if (!arv) { continue ; }
4232 arv->delete_waves();
4235 // cleanup peak files:
4236 // - stop pending peakfile threads
4237 // - close peakfiles if any
4238 // - remove peak dir in session
4239 // - setup peakfiles (background thread)
4240 _session->cleanup_peakfiles ();
4242 // re-add waves to ARV
4243 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4244 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4245 if (!arv) { continue ; }
4246 arv->create_waves();
4250 PresentationInfo::order_t
4251 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4253 if (editor->get_selection().tracks.empty()) {
4254 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4257 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4260 we want the new routes to have their order keys set starting from
4261 the highest order key in the selection + 1 (if available).
4264 if (place == RouteDialogs::AfterSelection) {
4265 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4267 order_hint = rtav->route()->presentation_info().order();
4270 } else if (place == RouteDialogs::BeforeSelection) {
4271 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4273 order_hint = rtav->route()->presentation_info().order();
4275 } else if (place == RouteDialogs::First) {
4278 /* leave order_hint at max_order */
4285 ARDOUR_UI::start_duplicate_routes ()
4287 if (!duplicate_routes_dialog) {
4288 duplicate_routes_dialog = new DuplicateRouteDialog;
4291 if (duplicate_routes_dialog->restart (_session)) {
4295 duplicate_routes_dialog->present ();
4299 ARDOUR_UI::add_route ()
4301 if (!add_route_dialog.get (false)) {
4302 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4309 if (add_route_dialog->is_visible()) {
4310 /* we're already doing this */
4314 add_route_dialog->set_position (WIN_POS_MOUSE);
4315 add_route_dialog->present();
4319 ARDOUR_UI::add_route_dialog_response (int r)
4322 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4329 case AddRouteDialog::Add:
4330 add_route_dialog->reset_name_edited ();
4332 case AddRouteDialog::AddAndClose:
4333 add_route_dialog->ArdourDialog::on_response (r);
4336 add_route_dialog->ArdourDialog::on_response (r);
4340 std::string template_path = add_route_dialog->get_template_path();
4341 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4342 meta_route_setup (template_path.substr (11));
4346 if ((count = add_route_dialog->count()) <= 0) {
4350 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4351 const string name_template = add_route_dialog->name_template ();
4352 DisplaySuspender ds;
4354 if (!template_path.empty ()) {
4355 if (add_route_dialog->name_template_is_default ()) {
4356 _session->new_route_from_template (count, order, template_path, string ());
4358 _session->new_route_from_template (count, order, template_path, name_template);
4363 ChanCount input_chan= add_route_dialog->channels ();
4364 ChanCount output_chan;
4365 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4366 RouteGroup* route_group = add_route_dialog->route_group ();
4367 AutoConnectOption oac = Config->get_output_auto_connect();
4368 bool strict_io = add_route_dialog->use_strict_io ();
4370 if (oac & AutoConnectMaster) {
4371 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4372 output_chan.set (DataType::MIDI, 0);
4374 output_chan = input_chan;
4377 /* XXX do something with name template */
4379 Session::ProcessorChangeBlocker pcb (_session);
4381 switch (add_route_dialog->type_wanted()) {
4382 case AddRouteDialog::AudioTrack:
4383 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);
4385 case AddRouteDialog::MidiTrack:
4386 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4388 case AddRouteDialog::MixedTrack:
4389 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4391 case AddRouteDialog::AudioBus:
4392 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4394 case AddRouteDialog::MidiBus:
4395 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4397 case AddRouteDialog::VCAMaster:
4398 _session->vca_manager().create_vca (count, name_template);
4404 ARDOUR_UI::stop_video_server (bool ask_confirm)
4406 if (!video_server_process && ask_confirm) {
4407 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4409 if (video_server_process) {
4411 ArdourDialog confirm (_("Stop Video-Server"), true);
4412 Label m (_("Do you really want to stop the Video Server?"));
4413 confirm.get_vbox()->pack_start (m, true, true);
4414 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4415 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4416 confirm.show_all ();
4417 if (confirm.run() == RESPONSE_CANCEL) {
4421 delete video_server_process;
4422 video_server_process =0;
4427 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4429 ARDOUR_UI::start_video_server( float_window, true);
4433 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4439 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4440 if (video_server_process) {
4441 popup_error(_("The Video Server is already started."));
4443 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4449 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4451 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4453 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4455 video_server_dialog->set_transient_for (*float_window);
4458 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4459 video_server_dialog->hide();
4461 ResponseType r = (ResponseType) video_server_dialog->run ();
4462 video_server_dialog->hide();
4463 if (r != RESPONSE_ACCEPT) { return false; }
4464 if (video_server_dialog->show_again()) {
4465 Config->set_show_video_server_dialog(false);
4469 std::string icsd_exec = video_server_dialog->get_exec_path();
4470 std::string icsd_docroot = video_server_dialog->get_docroot();
4471 #ifndef PLATFORM_WINDOWS
4472 if (icsd_docroot.empty()) {
4473 icsd_docroot = VideoUtils::video_get_docroot (Config);
4478 #ifdef PLATFORM_WINDOWS
4479 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4480 /* OK, allow all drive letters */
4483 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4484 warning << _("Specified docroot is not an existing directory.") << endmsg;
4487 #ifndef PLATFORM_WINDOWS
4488 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4489 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4490 warning << _("Given Video Server is not an executable file.") << endmsg;
4494 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4495 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4496 warning << _("Given Video Server is not an executable file.") << endmsg;
4502 argp=(char**) calloc(9,sizeof(char*));
4503 argp[0] = strdup(icsd_exec.c_str());
4504 argp[1] = strdup("-P");
4505 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4506 argp[3] = strdup("-p");
4507 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4508 argp[5] = strdup("-C");
4509 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4510 argp[7] = strdup(icsd_docroot.c_str());
4512 stop_video_server();
4514 #ifdef PLATFORM_WINDOWS
4515 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4516 /* OK, allow all drive letters */
4519 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4520 Config->set_video_advanced_setup(false);
4522 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4523 Config->set_video_server_url(url_str);
4524 Config->set_video_server_docroot(icsd_docroot);
4525 Config->set_video_advanced_setup(true);
4528 if (video_server_process) {
4529 delete video_server_process;
4532 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4533 if (video_server_process->start()) {
4534 warning << _("Cannot launch the video-server") << endmsg;
4537 int timeout = 120; // 6 sec
4538 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4539 Glib::usleep (50000);
4541 if (--timeout <= 0 || !video_server_process->is_running()) break;
4544 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4546 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4547 delete video_server_process;
4548 video_server_process = 0;
4556 ARDOUR_UI::add_video (Gtk::Window* float_window)
4562 if (!start_video_server(float_window, false)) {
4563 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4568 add_video_dialog->set_transient_for (*float_window);
4571 if (add_video_dialog->is_visible()) {
4572 /* we're already doing this */
4576 ResponseType r = (ResponseType) add_video_dialog->run ();
4577 add_video_dialog->hide();
4578 if (r != RESPONSE_ACCEPT) { return; }
4580 bool local_file, orig_local_file;
4581 std::string path = add_video_dialog->file_name(local_file);
4583 std::string orig_path = path;
4584 orig_local_file = local_file;
4586 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4588 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4589 warning << string_compose(_("could not open %1"), path) << endmsg;
4592 if (!local_file && path.length() == 0) {
4593 warning << _("no video-file selected") << endmsg;
4597 std::string audio_from_video;
4598 bool detect_ltc = false;
4600 switch (add_video_dialog->import_option()) {
4601 case VTL_IMPORT_TRANSCODE:
4603 TranscodeVideoDialog *transcode_video_dialog;
4604 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4605 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4606 transcode_video_dialog->hide();
4607 if (r != RESPONSE_ACCEPT) {
4608 delete transcode_video_dialog;
4612 audio_from_video = transcode_video_dialog->get_audiofile();
4614 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4617 else if (!audio_from_video.empty()) {
4618 editor->embed_audio_from_video(
4620 video_timeline->get_offset(),
4621 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4624 switch (transcode_video_dialog->import_option()) {
4625 case VTL_IMPORT_TRANSCODED:
4626 path = transcode_video_dialog->get_filename();
4629 case VTL_IMPORT_REFERENCE:
4632 delete transcode_video_dialog;
4635 delete transcode_video_dialog;
4639 case VTL_IMPORT_NONE:
4643 /* strip _session->session_directory().video_path() from video file if possible */
4644 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4645 path=path.substr(_session->session_directory().video_path().size());
4646 if (path.at(0) == G_DIR_SEPARATOR) {
4647 path=path.substr(1);
4651 video_timeline->set_update_session_fps(auto_set_session_fps);
4653 if (video_timeline->video_file_info(path, local_file)) {
4654 XMLNode* node = new XMLNode(X_("Videotimeline"));
4655 node->set_property (X_("Filename"), path);
4656 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4657 node->set_property (X_("LocalFile"), local_file);
4658 if (orig_local_file) {
4659 node->set_property (X_("OriginalVideoFile"), orig_path);
4661 node->remove_property (X_("OriginalVideoFile"));
4663 _session->add_extra_xml (*node);
4664 _session->set_dirty ();
4666 if (!audio_from_video.empty() && detect_ltc) {
4667 std::vector<LTCFileReader::LTCMap> ltc_seq;
4670 /* TODO ask user about TV standard (LTC alignment if any) */
4671 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4672 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4674 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4676 /* TODO seek near end of file, and read LTC until end.
4677 * if it fails to find any LTC samples, scan complete file
4679 * calculate drift of LTC compared to video-duration,
4680 * ask user for reference (timecode from start/mid/end)
4683 // LTCFileReader will have written error messages
4686 ::g_unlink(audio_from_video.c_str());
4688 if (ltc_seq.size() == 0) {
4689 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4691 /* the very first TC in the file is somteimes not aligned properly */
4692 int i = ltc_seq.size() -1;
4693 ARDOUR::sampleoffset_t video_start_offset =
4694 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4695 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4696 video_timeline->set_offset(video_start_offset);
4700 _session->maybe_update_session_range(
4701 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4702 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4705 if (add_video_dialog->launch_xjadeo() && local_file) {
4706 editor->set_xjadeo_sensitive(true);
4707 editor->toggle_xjadeo_proc(1);
4709 editor->toggle_xjadeo_proc(0);
4711 editor->toggle_ruler_video(true);
4716 ARDOUR_UI::remove_video ()
4718 video_timeline->close_session();
4719 editor->toggle_ruler_video(false);
4722 video_timeline->set_offset_locked(false);
4723 video_timeline->set_offset(0);
4725 /* delete session state */
4726 XMLNode* node = new XMLNode(X_("Videotimeline"));
4727 _session->add_extra_xml(*node);
4728 node = new XMLNode(X_("Videomonitor"));
4729 _session->add_extra_xml(*node);
4730 node = new XMLNode(X_("Videoexport"));
4731 _session->add_extra_xml(*node);
4732 stop_video_server();
4736 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4738 if (localcacheonly) {
4739 video_timeline->vmon_update();
4741 video_timeline->flush_cache();
4743 editor->queue_visual_videotimeline_update();
4747 ARDOUR_UI::export_video (bool range)
4749 if (ARDOUR::Config->get_show_video_export_info()) {
4750 ExportVideoInfobox infobox (_session);
4751 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4752 if (infobox.show_again()) {
4753 ARDOUR::Config->set_show_video_export_info(false);
4756 case GTK_RESPONSE_YES:
4757 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4763 export_video_dialog->set_session (_session);
4764 export_video_dialog->apply_state(editor->get_selection().time, range);
4765 export_video_dialog->run ();
4766 export_video_dialog->hide ();
4770 ARDOUR_UI::preferences_settings () const
4775 node = _session->instant_xml(X_("Preferences"));
4777 node = Config->instant_xml(X_("Preferences"));
4781 node = new XMLNode (X_("Preferences"));
4788 ARDOUR_UI::mixer_settings () const
4793 node = _session->instant_xml(X_("Mixer"));
4795 node = Config->instant_xml(X_("Mixer"));
4799 node = new XMLNode (X_("Mixer"));
4806 ARDOUR_UI::main_window_settings () const
4811 node = _session->instant_xml(X_("Main"));
4813 node = Config->instant_xml(X_("Main"));
4817 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4818 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4823 node = new XMLNode (X_("Main"));
4830 ARDOUR_UI::editor_settings () const
4835 node = _session->instant_xml(X_("Editor"));
4837 node = Config->instant_xml(X_("Editor"));
4841 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4842 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4847 node = new XMLNode (X_("Editor"));
4854 ARDOUR_UI::keyboard_settings () const
4858 node = Config->extra_xml(X_("Keyboard"));
4861 node = new XMLNode (X_("Keyboard"));
4868 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4871 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4872 _session->locations()->add (location);
4877 ARDOUR_UI::halt_on_xrun_message ()
4879 cerr << "HALT on xrun\n";
4880 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4885 ARDOUR_UI::xrun_handler (samplepos_t where)
4891 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4893 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4894 create_xrun_marker(where);
4897 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4898 halt_on_xrun_message ();
4903 ARDOUR_UI::disk_overrun_handler ()
4905 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4907 if (!have_disk_speed_dialog_displayed) {
4908 have_disk_speed_dialog_displayed = true;
4909 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4910 The disk system on your computer\n\
4911 was not able to keep up with %1.\n\
4913 Specifically, it failed to write data to disk\n\
4914 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4915 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4921 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4922 static MessageDialog *scan_dlg = NULL;
4923 static ProgressBar *scan_pbar = NULL;
4924 static HBox *scan_tbox = NULL;
4925 static Gtk::Button *scan_timeout_button;
4928 ARDOUR_UI::cancel_plugin_scan ()
4930 PluginManager::instance().cancel_plugin_scan();
4934 ARDOUR_UI::cancel_plugin_timeout ()
4936 PluginManager::instance().cancel_plugin_timeout();
4937 scan_timeout_button->set_sensitive (false);
4941 ARDOUR_UI::plugin_scan_timeout (int timeout)
4943 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4947 scan_pbar->set_sensitive (false);
4948 scan_timeout_button->set_sensitive (true);
4949 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4952 scan_pbar->set_sensitive (false);
4953 scan_timeout_button->set_sensitive (false);
4959 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4961 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4965 const bool cancelled = PluginManager::instance().cancelled();
4966 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4967 if (cancelled && scan_dlg->is_mapped()) {
4972 if (cancelled || !can_cancel) {
4977 static Gtk::Button *cancel_button;
4979 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4980 VBox* vbox = scan_dlg->get_vbox();
4981 vbox->set_size_request(400,-1);
4982 scan_dlg->set_title (_("Scanning for plugins"));
4984 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4985 cancel_button->set_name ("EditorGTKButton");
4986 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4987 cancel_button->show();
4989 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4991 scan_tbox = manage( new HBox() );
4993 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4994 scan_timeout_button->set_name ("EditorGTKButton");
4995 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4996 scan_timeout_button->show();
4998 scan_pbar = manage(new ProgressBar());
4999 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5000 scan_pbar->set_text(_("Scan Timeout"));
5003 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5004 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5006 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5009 assert(scan_dlg && scan_tbox && cancel_button);
5011 if (type == X_("closeme")) {
5015 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5018 if (!can_cancel || !cancelled) {
5019 scan_timeout_button->set_sensitive(false);
5021 cancel_button->set_sensitive(can_cancel && !cancelled);
5027 ARDOUR_UI::gui_idle_handler ()
5030 /* due to idle calls, gtk_events_pending() may always return true */
5031 while (gtk_events_pending() && --timeout) {
5032 gtk_main_iteration ();
5037 ARDOUR_UI::disk_underrun_handler ()
5039 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5041 if (!have_disk_speed_dialog_displayed) {
5042 have_disk_speed_dialog_displayed = true;
5043 MessageDialog* msg = new MessageDialog (
5044 _main_window, string_compose (_("The disk system on your computer\n\
5045 was not able to keep up with %1.\n\
5047 Specifically, it failed to read data from disk\n\
5048 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5049 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5055 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5057 have_disk_speed_dialog_displayed = false;
5062 ARDOUR_UI::session_dialog (std::string msg)
5064 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5068 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5075 ARDOUR_UI::pending_state_dialog ()
5077 HBox* hbox = manage (new HBox());
5078 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5079 ArdourDialog dialog (_("Crash Recovery"), true);
5080 Label message (string_compose (_("\
5081 This session appears to have been in the\n\
5082 middle of recording when %1 or\n\
5083 the computer was shutdown.\n\
5085 %1 can recover any captured audio for\n\
5086 you, or it can ignore it. Please decide\n\
5087 what you would like to do.\n"), PROGRAM_NAME));
5088 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5089 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5090 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5091 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5092 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5093 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5094 dialog.set_default_response (RESPONSE_ACCEPT);
5095 dialog.set_position (WIN_POS_CENTER);
5100 switch (dialog.run ()) {
5101 case RESPONSE_ACCEPT:
5109 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5111 HBox* hbox = new HBox();
5112 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5113 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5114 Label message (string_compose (_("\
5115 This session was created with a sample rate of %1 Hz, but\n\
5116 %2 is currently running at %3 Hz. If you load this session,\n\
5117 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5119 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5120 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5121 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5122 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5123 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5124 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5125 dialog.set_default_response (RESPONSE_ACCEPT);
5126 dialog.set_position (WIN_POS_CENTER);
5131 switch (dialog.run()) {
5132 case RESPONSE_ACCEPT:
5142 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5144 MessageDialog msg (string_compose (_("\
5145 This session was created with a sample rate of %1 Hz, but\n\
5146 %2 is currently running at %3 Hz.\n\
5147 Audio will be recorded and played at the wrong sample rate.\n\
5148 Re-Configure the Audio Engine in\n\
5149 Menu > Window > Audio/Midi Setup"),
5150 desired, PROGRAM_NAME, actual),
5152 Gtk::MESSAGE_WARNING);
5157 ARDOUR_UI::use_config ()
5159 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5161 set_transport_controllable_state (*node);
5166 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5168 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5170 primary_clock->set (pos);
5172 case DeltaEditPoint:
5173 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5175 case DeltaOriginMarker:
5177 Location* loc = _session->locations()->clock_origin_location ();
5178 primary_clock->set (pos, false, loc ? loc->start() : 0);
5183 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5185 secondary_clock->set (pos);
5187 case DeltaEditPoint:
5188 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5190 case DeltaOriginMarker:
5192 Location* loc = _session->locations()->clock_origin_location ();
5193 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5198 if (big_clock_window) {
5199 big_clock->set (pos);
5201 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5206 ARDOUR_UI::record_state_changed ()
5208 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5211 /* why bother - the clock isn't visible */
5215 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5217 if (big_clock_window) {
5218 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5219 big_clock->set_active (true);
5221 big_clock->set_active (false);
5228 ARDOUR_UI::first_idle ()
5231 _session->allow_auto_play (true);
5235 editor->first_idle();
5238 /* in 1 second, hide the splash screen
5240 * Consider hiding it *now*. If a user opens opens a dialog
5241 * during that one second while the splash is still visible,
5242 * the dialog will push-back the splash.
5243 * Closing the dialog later will pop it back.
5245 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5247 Keyboard::set_can_save_keybindings (true);
5252 ARDOUR_UI::store_clock_modes ()
5254 XMLNode* node = new XMLNode(X_("ClockModes"));
5256 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5257 XMLNode* child = new XMLNode (X_("Clock"));
5259 child->set_property (X_("name"), (*x)->name());
5260 child->set_property (X_("mode"), (*x)->mode());
5261 child->set_property (X_("on"), (*x)->on());
5263 node->add_child_nocopy (*child);
5266 _session->add_extra_xml (*node);
5267 _session->set_dirty ();
5271 ARDOUR_UI::setup_profile ()
5273 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5274 Profile->set_small_screen ();
5277 if (g_getenv ("TRX")) {
5278 Profile->set_trx ();
5281 if (g_getenv ("MIXBUS")) {
5282 Profile->set_mixbus ();
5287 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5289 MissingFileDialog dialog (s, str, type);
5294 int result = dialog.run ();
5301 return 1; // quit entire session load
5304 result = dialog.get_action ();
5310 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5312 AmbiguousFileDialog dialog (file, hits);
5319 return dialog.get_which ();
5322 /** Allocate our thread-local buffers */
5324 ARDOUR_UI::get_process_buffers ()
5326 _process_thread->get_buffers ();
5329 /** Drop our thread-local buffers */
5331 ARDOUR_UI::drop_process_buffers ()
5333 _process_thread->drop_buffers ();
5337 ARDOUR_UI::feedback_detected ()
5339 _feedback_exists = true;
5343 ARDOUR_UI::successful_graph_sort ()
5345 _feedback_exists = false;
5349 ARDOUR_UI::midi_panic ()
5352 _session->midi_panic();
5357 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5359 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5360 const char* end_big = "</span>";
5361 const char* start_mono = "<tt>";
5362 const char* end_mono = "</tt>";
5364 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5365 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5366 "From now on, use the backup copy with older versions of %3"),
5367 xml_path, backup_path, PROGRAM_NAME,
5369 start_mono, end_mono), true);
5375 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5377 using namespace Menu_Helpers;
5379 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5380 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5381 i->set_active (editor_meter->meter_type () == type);
5385 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5387 using namespace Gtk::Menu_Helpers;
5389 Gtk::Menu* m = manage (new Menu);
5390 MenuList& items = m->items ();
5392 RadioMenuItem::Group group;
5394 _suspend_editor_meter_callbacks = true;
5395 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5396 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5397 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5398 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5399 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5400 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5401 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5402 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5403 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5404 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5405 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5407 m->popup (ev->button, ev->time);
5408 _suspend_editor_meter_callbacks = false;
5412 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5414 if (ev->button == 3 && editor_meter) {
5415 popup_editor_meter_menu (ev);
5422 ARDOUR_UI::reset_peak_display ()
5424 if (!_session || !_session->master_out() || !editor_meter) return;
5425 editor_meter->clear_meters();
5426 editor_meter_max_peak = -INFINITY;
5427 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5431 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5433 if (!_session || !_session->master_out()) return;
5434 if (group == _session->master_out()->route_group()) {
5435 reset_peak_display ();
5440 ARDOUR_UI::reset_route_peak_display (Route* route)
5442 if (!_session || !_session->master_out()) return;
5443 if (_session->master_out().get() == route) {
5444 reset_peak_display ();
5449 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5451 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5452 audio_midi_setup->set_position (WIN_POS_CENTER);
5454 if (desired_sample_rate != 0) {
5455 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5456 audio_midi_setup->try_autostart ();
5457 if (ARDOUR::AudioEngine::instance()->running()) {
5464 int response = audio_midi_setup->run();
5466 case Gtk::RESPONSE_DELETE_EVENT:
5467 // after latency callibration engine may run,
5468 // Running() signal was emitted, but dialog will not
5469 // have emitted a response. The user needs to close
5470 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5471 if (!AudioEngine::instance()->running()) {
5476 if (!AudioEngine::instance()->running()) {
5479 audio_midi_setup->hide ();
5487 ARDOUR_UI::transport_numpad_timeout ()
5489 _numpad_locate_happening = false;
5490 if (_numpad_timeout_connection.connected() )
5491 _numpad_timeout_connection.disconnect();
5496 ARDOUR_UI::transport_numpad_decimal ()
5498 _numpad_timeout_connection.disconnect();
5500 if (_numpad_locate_happening) {
5501 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5502 _numpad_locate_happening = false;
5504 _pending_locate_num = 0;
5505 _numpad_locate_happening = true;
5506 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5511 ARDOUR_UI::transport_numpad_event (int num)
5513 if ( _numpad_locate_happening ) {
5514 _pending_locate_num = _pending_locate_num*10 + num;
5517 case 0: toggle_roll(false, false); break;
5518 case 1: transport_rewind(1); break;
5519 case 2: transport_forward(1); break;
5520 case 3: transport_record(true); break;
5521 case 4: toggle_session_auto_loop(); break;
5522 case 5: transport_record(false); toggle_session_auto_loop(); break;
5523 case 6: toggle_punch(); break;
5524 case 7: toggle_click(); break;
5525 case 8: toggle_auto_return(); break;
5526 case 9: toggle_follow_edits(); break;
5532 ARDOUR_UI::set_flat_buttons ()
5534 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5538 ARDOUR_UI::audioengine_became_silent ()
5540 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5542 Gtk::MESSAGE_WARNING,
5546 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5548 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5549 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5550 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5551 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5552 Gtk::HBox pay_button_box;
5553 Gtk::HBox subscribe_button_box;
5555 pay_button_box.pack_start (pay_button, true, false);
5556 subscribe_button_box.pack_start (subscribe_button, true, false);
5558 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 */
5560 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5561 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5563 msg.get_vbox()->pack_start (pay_label);
5564 msg.get_vbox()->pack_start (pay_button_box);
5565 msg.get_vbox()->pack_start (subscribe_label);
5566 msg.get_vbox()->pack_start (subscribe_button_box);
5568 msg.get_vbox()->show_all ();
5570 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5571 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5572 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5577 case Gtk::RESPONSE_YES:
5578 AudioEngine::instance()->reset_silence_countdown ();
5581 case Gtk::RESPONSE_NO:
5583 save_state_canfail ("");
5587 case Gtk::RESPONSE_CANCEL:
5589 /* don't reset, save session and exit */
5595 ARDOUR_UI::hide_application ()
5597 Application::instance ()-> hide ();
5601 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5603 /* icons, titles, WM stuff */
5605 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5607 if (window_icons.empty()) {
5608 Glib::RefPtr<Gdk::Pixbuf> icon;
5609 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5610 window_icons.push_back (icon);
5612 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5613 window_icons.push_back (icon);
5615 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5616 window_icons.push_back (icon);
5618 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5619 window_icons.push_back (icon);
5623 if (!window_icons.empty()) {
5624 window.set_default_icon_list (window_icons);
5627 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5629 if (!name.empty()) {
5633 window.set_title (title.get_string());
5634 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5636 window.set_flags (CAN_FOCUS);
5637 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5639 /* This is a hack to ensure that GTK-accelerators continue to
5640 * work. Once we switch over to entirely native bindings, this will be
5641 * unnecessary and should be removed
5643 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5645 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5646 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5647 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5648 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5652 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5654 Gtkmm2ext::Bindings* bindings = 0;
5655 Gtk::Window* window = 0;
5657 /* until we get ardour bindings working, we are not handling key
5661 if (ev->type != GDK_KEY_PRESS) {
5665 if (event_window == &_main_window) {
5667 window = event_window;
5669 /* find current tab contents */
5671 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5673 /* see if it uses the ardour binding system */
5676 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5679 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5683 window = event_window;
5685 /* see if window uses ardour binding system */
5687 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5690 /* An empty binding set is treated as if it doesn't exist */
5692 if (bindings && bindings->empty()) {
5696 return key_press_focus_accelerator_handler (*window, ev, bindings);
5699 static Gtkmm2ext::Bindings*
5700 get_bindings_from_widget_heirarchy (GtkWidget** w)
5705 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5708 *w = gtk_widget_get_parent (*w);
5711 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5715 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5717 GtkWindow* win = window.gobj();
5718 GtkWidget* focus = gtk_window_get_focus (win);
5719 GtkWidget* binding_widget = focus;
5720 bool special_handling_of_unmodified_accelerators = false;
5721 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5725 /* some widget has keyboard focus */
5727 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5729 /* A particular kind of focusable widget currently has keyboard
5730 * focus. All unmodified key events should go to that widget
5731 * first and not be used as an accelerator by default
5734 special_handling_of_unmodified_accelerators = true;
5738 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5739 if (focus_bindings) {
5740 bindings = focus_bindings;
5741 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5746 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",
5749 Gtkmm2ext::show_gdk_event_state (ev->state),
5750 special_handling_of_unmodified_accelerators,
5751 Keyboard::some_magic_widget_has_focus(),
5753 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5754 ((ev->state & mask) ? "yes" : "no"),
5755 window.get_title()));
5757 /* This exists to allow us to override the way GTK handles
5758 key events. The normal sequence is:
5760 a) event is delivered to a GtkWindow
5761 b) accelerators/mnemonics are activated
5762 c) if (b) didn't handle the event, propagate to
5763 the focus widget and/or focus chain
5765 The problem with this is that if the accelerators include
5766 keys without modifiers, such as the space bar or the
5767 letter "e", then pressing the key while typing into
5768 a text entry widget results in the accelerator being
5769 activated, instead of the desired letter appearing
5772 There is no good way of fixing this, but this
5773 represents a compromise. The idea is that
5774 key events involving modifiers (not Shift)
5775 get routed into the activation pathway first, then
5776 get propagated to the focus widget if necessary.
5778 If the key event doesn't involve modifiers,
5779 we deliver to the focus widget first, thus allowing
5780 it to get "normal text" without interference
5783 Of course, this can also be problematic: if there
5784 is a widget with focus, then it will swallow
5785 all "normal text" accelerators.
5789 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5791 /* no special handling or there are modifiers in effect: accelerate first */
5793 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5794 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5795 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5797 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5798 KeyboardKey k (ev->state, ev->keyval);
5802 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5804 if (bindings->activate (k, Bindings::Press)) {
5805 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5809 if (binding_widget) {
5810 binding_widget = gtk_widget_get_parent (binding_widget);
5811 if (binding_widget) {
5812 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5821 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5823 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5824 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5828 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5830 if (gtk_window_propagate_key_event (win, ev)) {
5831 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5837 /* no modifiers, propagate first */
5839 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5841 if (gtk_window_propagate_key_event (win, ev)) {
5842 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5846 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5847 KeyboardKey k (ev->state, ev->keyval);
5851 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5854 if (bindings->activate (k, Bindings::Press)) {
5855 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5859 if (binding_widget) {
5860 binding_widget = gtk_widget_get_parent (binding_widget);
5861 if (binding_widget) {
5862 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5871 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5873 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5874 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5879 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5884 ARDOUR_UI::load_bindings ()
5886 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5887 error << _("Global keybindings are missing") << endmsg;
5892 ARDOUR_UI::cancel_solo ()
5895 _session->cancel_all_solo ();
5900 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5902 /* this resets focus to the first focusable parent of the given widget,
5903 * or, if there is no focusable parent, cancels focus in the toplevel
5904 * window that the given widget is packed into (if there is one).
5911 Gtk::Widget* top = w->get_toplevel();
5913 if (!top || !top->is_toplevel()) {
5917 w = w->get_parent ();
5921 if (w->is_toplevel()) {
5922 /* Setting the focus widget to a Gtk::Window causes all
5923 * subsequent calls to ::has_focus() on the nominal
5924 * focus widget in that window to return
5925 * false. Workaround: never set focus to the toplevel
5931 if (w->get_can_focus ()) {
5932 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5933 win->set_focus (*w);
5936 w = w->get_parent ();
5939 if (top == &_main_window) {
5943 /* no focusable parent found, cancel focus in top level window.
5944 C++ API cannot be used for this. Thanks, references.
5947 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);