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/slave.h"
109 #include "ardour/system_exec.h"
110 #include "ardour/track.h"
111 #include "ardour/vca_manager.h"
112 #include "ardour/utils.h"
114 #include "LuaBridge/LuaBridge.h"
116 #ifdef WINDOWS_VST_SUPPORT
119 #ifdef AUDIOUNIT_SUPPORT
120 #include "ardour/audio_unit.h"
123 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
128 #include "temporal/time.h"
130 typedef uint64_t microseconds_t;
134 #include "enums_convert.h"
136 #include "add_route_dialog.h"
137 #include "ambiguous_file_dialog.h"
138 #include "ardour_ui.h"
139 #include "audio_clock.h"
140 #include "audio_region_view.h"
141 #include "big_clock_window.h"
142 #include "big_transport_window.h"
143 #include "bundle_manager.h"
144 #include "duplicate_routes_dialog.h"
146 #include "engine_dialog.h"
147 #include "export_video_dialog.h"
148 #include "export_video_infobox.h"
149 #include "gain_meter.h"
150 #include "global_port_matrix.h"
151 #include "gui_object.h"
152 #include "gui_thread.h"
153 #include "idleometer.h"
154 #include "keyboard.h"
155 #include "keyeditor.h"
156 #include "location_ui.h"
157 #include "lua_script_manager.h"
158 #include "luawindow.h"
159 #include "main_clock.h"
160 #include "missing_file_dialog.h"
161 #include "missing_plugin_dialog.h"
162 #include "mixer_ui.h"
163 #include "meterbridge.h"
164 #include "meter_patterns.h"
165 #include "mouse_cursors.h"
168 #include "pingback.h"
169 #include "processor_box.h"
170 #include "public_editor.h"
171 #include "rc_option_editor.h"
172 #include "route_time_axis.h"
173 #include "route_params_ui.h"
174 #include "save_as_dialog.h"
175 #include "save_template_dialog.h"
176 #include "script_selector.h"
177 #include "session_archive_dialog.h"
178 #include "session_dialog.h"
179 #include "session_metadata_dialog.h"
180 #include "session_option_editor.h"
181 #include "speaker_dialog.h"
184 #include "template_dialog.h"
185 #include "time_axis_view_item.h"
186 #include "time_info_box.h"
189 #include "utils_videotl.h"
190 #include "video_server_dialog.h"
191 #include "add_video_dialog.h"
192 #include "transcode_video_dialog.h"
194 #include "pbd/i18n.h"
196 using namespace ARDOUR;
197 using namespace ARDOUR_UI_UTILS;
199 using namespace Gtkmm2ext;
200 using namespace ArdourWidgets;
203 using namespace Editing;
205 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
207 sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
208 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
211 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
213 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
214 "Would you like these files to be copied and used for %1 %2.x?\n\n"
215 "(This will require you to restart %1.)"),
216 PROGRAM_NAME, PROGRAM_VERSION, version),
217 false, /* no markup */
220 true /* modal, though it hardly matters since it is the only window */
223 msg.set_default_response (Gtk::RESPONSE_YES);
226 return (msg.run() == Gtk::RESPONSE_YES);
230 libxml_generic_error_func (void* /* parsing_context*/,
238 vsnprintf (buf, sizeof (buf), msg, ap);
239 error << buf << endmsg;
244 libxml_structured_error_func (void* /* parsing_context*/,
252 replace_all (msg, "\n", "");
255 if (err->file && err->line) {
256 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
259 error << ':' << err->int2;
264 error << X_("XML error: ") << msg << endmsg;
270 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
271 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
272 , session_loaded (false)
273 , session_load_in_progress (false)
274 , gui_object_state (new GUIObjectState)
275 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
276 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
277 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
279 , global_actions (X_("global"))
280 , ignore_dual_punch (false)
281 , main_window_visibility (0)
286 , _mixer_on_top (false)
287 , _initial_verbose_plugin_scan (false)
288 , first_time_engine_run (true)
289 , secondary_clock_spacer (0)
290 , auto_input_button (ArdourButton::led_default_elements)
292 , auto_return_button (ArdourButton::led_default_elements)
293 , follow_edits_button (ArdourButton::led_default_elements)
294 , auditioning_alert_button (_("Audition"))
295 , solo_alert_button (_("Solo"))
296 , feedback_alert_button (_("Feedback"))
297 , error_alert_button ( ArdourButton::just_led_default_elements )
298 , editor_meter_peak_display()
300 , _suspend_editor_meter_callbacks (false)
301 , _numpad_locate_happening (false)
302 , _session_is_new (false)
303 , last_key_press_time (0)
307 , rc_option_editor (0)
308 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
309 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
310 , about (X_("about"), _("About"))
311 , location_ui (X_("locations"), S_("Ranges|Locations"))
312 , route_params (X_("inspector"), _("Tracks and Busses"))
313 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
314 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
315 , lua_script_window (X_("script-manager"), _("Script Manager"))
316 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
317 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
318 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
319 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
320 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
321 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
322 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
323 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
324 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
325 , video_server_process (0)
327 , have_configure_timeout (false)
328 , last_configure_time (0)
330 , have_disk_speed_dialog_displayed (false)
331 , _status_bar_visibility (X_("status-bar"))
332 , _feedback_exists (false)
333 , _log_not_acknowledged (LogLevelNone)
334 , duplicate_routes_dialog (0)
335 , editor_visibility_button (S_("Window|Editor"))
336 , mixer_visibility_button (S_("Window|Mixer"))
337 , prefs_visibility_button (S_("Window|Preferences"))
339 Gtkmm2ext::init (localedir);
341 UIConfiguration::instance().post_gui_init ();
343 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
345 /* "touch" the been-here-before path now that config has been migrated */
346 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
348 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
350 /* configuration was modified, exit immediately */
355 if (string (VERSIONSTRING).find (".pre") != string::npos) {
356 /* check this is not being run from ./ardev etc. */
357 if (!running_from_source_tree ()) {
358 pre_release_dialog ();
362 if (theArdourUI == 0) {
366 /* track main window visibility */
368 main_window_visibility = new VisibilityTracker (_main_window);
370 /* stop libxml from spewing to stdout/stderr */
372 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
373 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
375 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
376 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
377 UIConfiguration::instance().map_parameters (pc);
379 transport_ctrl.setup (this);
381 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
382 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
384 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
386 /* handle dialog requests */
388 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
390 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
392 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
394 /* handle Audio/MIDI setup when session requires it */
396 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
398 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
400 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
402 /* handle sr mismatch with a dialog - cross-thread from engine */
403 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
405 /* handle requests to quit (coming from JACK session) */
407 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
409 /* tell the user about feedback */
411 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
412 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
414 /* handle requests to deal with missing files */
416 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
418 /* and ambiguous files */
420 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
422 /* also plugin scan messages */
423 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
424 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
426 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
428 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
431 /* lets get this party started */
433 setup_gtk_ardour_enums ();
436 SessionEvent::create_per_thread_pool ("GUI", 4096);
438 /* we like keyboards */
440 keyboard = new ArdourKeyboard(*this);
442 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
444 keyboard->set_state (*node, Stateful::loading_state_version);
447 UIConfiguration::instance().reset_dpi ();
449 TimeAxisViewItem::set_constant_heights ();
451 /* Set this up so that our window proxies can register actions */
453 ActionManager::init ();
455 /* The following must happen after ARDOUR::init() so that Config is set up */
457 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
460 key_editor.set_state (*ui_xml, 0);
461 session_option_editor.set_state (*ui_xml, 0);
462 speaker_config_window.set_state (*ui_xml, 0);
463 about.set_state (*ui_xml, 0);
464 add_route_dialog.set_state (*ui_xml, 0);
465 add_video_dialog.set_state (*ui_xml, 0);
466 route_params.set_state (*ui_xml, 0);
467 bundle_manager.set_state (*ui_xml, 0);
468 location_ui.set_state (*ui_xml, 0);
469 big_clock_window.set_state (*ui_xml, 0);
470 big_transport_window.set_state (*ui_xml, 0);
471 audio_port_matrix.set_state (*ui_xml, 0);
472 midi_port_matrix.set_state (*ui_xml, 0);
473 export_video_dialog.set_state (*ui_xml, 0);
474 lua_script_window.set_state (*ui_xml, 0);
475 idleometer.set_state (*ui_xml, 0);
478 /* Separate windows */
480 WM::Manager::instance().register_window (&key_editor);
481 WM::Manager::instance().register_window (&session_option_editor);
482 WM::Manager::instance().register_window (&speaker_config_window);
483 WM::Manager::instance().register_window (&about);
484 WM::Manager::instance().register_window (&add_route_dialog);
485 WM::Manager::instance().register_window (&add_video_dialog);
486 WM::Manager::instance().register_window (&route_params);
487 WM::Manager::instance().register_window (&audio_midi_setup);
488 WM::Manager::instance().register_window (&export_video_dialog);
489 WM::Manager::instance().register_window (&lua_script_window);
490 WM::Manager::instance().register_window (&bundle_manager);
491 WM::Manager::instance().register_window (&location_ui);
492 WM::Manager::instance().register_window (&big_clock_window);
493 WM::Manager::instance().register_window (&big_transport_window);
494 WM::Manager::instance().register_window (&audio_port_matrix);
495 WM::Manager::instance().register_window (&midi_port_matrix);
496 WM::Manager::instance().register_window (&idleometer);
498 /* do not retain position for add route dialog */
499 add_route_dialog.set_state_mask (WindowProxy::Size);
501 /* Trigger setting up the color scheme and loading the GTK RC file */
503 UIConfiguration::instance().load_rc_file (false);
505 _process_thread = new ProcessThread ();
506 _process_thread->init ();
508 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
514 ARDOUR_UI::pre_release_dialog ()
516 ArdourDialog d (_("Pre-Release Warning"), true, false);
517 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
519 Label* label = manage (new Label);
520 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
521 There are still several issues and bugs to be worked on,\n\
522 as well as general workflow improvements, before this can be considered\n\
523 release software. So, a few guidelines:\n\
525 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
526 though it may be so, depending on your workflow.\n\
527 2) Please wait for a helpful writeup of new features.\n\
528 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
529 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
530 making sure to note the product version number as 6.0-pre.\n\
531 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
532 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
533 can get there directly from within the program via the Help->Chat menu option.\n\
535 Full information on all the above can be found on the support page at\n\
537 http://ardour.org/support\n\
538 "), PROGRAM_NAME, VERSIONSTRING));
540 d.get_vbox()->set_border_width (12);
541 d.get_vbox()->pack_start (*label, false, false, 12);
542 d.get_vbox()->show_all ();
547 GlobalPortMatrixWindow*
548 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
553 return new GlobalPortMatrixWindow (_session, type);
557 ARDOUR_UI::attach_to_engine ()
559 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
560 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
564 ARDOUR_UI::engine_stopped ()
566 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
567 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
568 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
569 update_sample_rate (0);
574 ARDOUR_UI::engine_running ()
576 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
577 if (first_time_engine_run) {
579 first_time_engine_run = false;
583 _session->reset_xrun_count ();
585 update_disk_space ();
587 update_sample_rate (AudioEngine::instance()->sample_rate());
588 update_timecode_format ();
589 update_peak_thread_work ();
590 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
591 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
595 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
597 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
598 /* we can't rely on the original string continuing to exist when we are called
599 again in the GUI thread, so make a copy and note that we need to
602 char *copy = strdup (reason);
603 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
607 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
608 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
610 update_sample_rate (0);
614 /* if the reason is a non-empty string, it means that the backend was shutdown
615 rather than just Ardour.
618 if (strlen (reason)) {
619 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
621 msgstr = string_compose (_("\
622 The audio backend has either been shutdown or it\n\
623 disconnected %1 because %1\n\
624 was not fast enough. Try to restart\n\
625 the audio backend and save the session."), PROGRAM_NAME);
628 MessageDialog msg (_main_window, msgstr);
629 pop_back_splash (msg);
633 free (const_cast<char*> (reason));
638 ARDOUR_UI::post_engine ()
640 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
642 #ifdef AUDIOUNIT_SUPPORT
644 if (AUPluginInfo::au_get_crashlog(au_msg)) {
645 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
646 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
647 info << au_msg << endmsg;
651 ARDOUR::init_post_engine ();
653 /* connect to important signals */
655 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
656 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
657 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
658 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
659 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
661 if (setup_windows ()) {
662 throw failed_constructor ();
665 transport_ctrl.map_actions ();
667 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
668 XMLNode* n = Config->extra_xml (X_("UI"));
670 _status_bar_visibility.set_state (*n);
673 check_memory_locking();
675 /* this is the first point at which all the possible actions are
676 * available, because some of the available actions are dependent on
677 * aspects of the engine/backend.
680 if (ARDOUR_COMMAND_LINE::show_key_actions) {
682 Bindings::save_all_bindings_as_html (sstr);
684 if (sstr.str().empty()) {
691 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
693 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
699 #ifdef PLATFORM_WINDOWS
705 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
706 #ifndef PLATFORM_WINDOWS
709 g_unlink (file_name);
711 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
717 #ifndef PLATFORM_WINDOWS
721 PBD::open_uri (string_compose ("file:///%1", file_name));
723 halt_connection.disconnect ();
724 AudioEngine::instance()->stop ();
729 if (ARDOUR_COMMAND_LINE::show_actions) {
732 vector<string> paths;
733 vector<string> labels;
734 vector<string> tooltips;
736 vector<Glib::RefPtr<Gtk::Action> > actions;
737 string ver_in = revision;
738 string ver = ver_in.substr(0, ver_in.find("-"));
741 output << "\n<h2>Menu actions</h2>" << endl;
742 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
743 output << " surfaces or scripts.\n</p>\n" << endl;
744 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
745 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
746 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
747 output << "<table class=\"dl\">\n <thead>" << endl;
748 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
749 output << " </thead>\n <tbody>" << endl;
751 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
753 vector<string>::iterator p;
754 vector<string>::iterator l;
756 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
757 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (10, string::npos);
758 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
760 output << " </tbody>\n </table>" << endl;
762 // output this mess to a browser for easiest X-platform use
763 // it is not pretty HTML, but it works and it's main purpose
764 // is to create raw html to fit in Ardour's manual with no editing
769 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
771 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
777 #ifdef PLATFORM_WINDOWS
783 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
784 #ifndef PLATFORM_WINDOWS
787 g_unlink (file_name);
789 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
795 #ifndef PLATFORM_WINDOWS
799 PBD::open_uri (string_compose ("file:///%1", file_name));
801 halt_connection.disconnect ();
802 AudioEngine::instance()->stop ();
806 /* this being a GUI and all, we want peakfiles */
808 AudioFileSource::set_build_peakfiles (true);
809 AudioFileSource::set_build_missing_peakfiles (true);
811 /* set default clock modes */
813 primary_clock->set_mode (AudioClock::Timecode);
814 secondary_clock->set_mode (AudioClock::BBT);
816 /* start the time-of-day-clock */
819 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
820 update_wall_clock ();
821 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
826 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
827 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
828 Config->map_parameters (pc);
830 UIConfiguration::instance().map_parameters (pc);
834 ARDOUR_UI::~ARDOUR_UI ()
836 UIConfiguration::instance().save_state();
840 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
841 // don't bother at 'real' exit. the OS cleans up for us.
842 delete big_clock; big_clock = 0;
843 delete primary_clock; primary_clock = 0;
844 delete secondary_clock; secondary_clock = 0;
845 delete _process_thread; _process_thread = 0;
846 delete time_info_box; time_info_box = 0;
847 delete meterbridge; meterbridge = 0;
848 delete luawindow; luawindow = 0;
849 delete editor; editor = 0;
850 delete mixer; mixer = 0;
851 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
853 delete gui_object_state; gui_object_state = 0;
854 delete main_window_visibility;
855 FastMeter::flush_pattern_cache ();
856 ArdourFader::flush_pattern_cache ();
860 /* Small trick to flush main-thread event pool.
861 * Other thread-pools are destroyed at pthread_exit(),
862 * but tmain thread termination is too late to trigger Pool::~Pool()
864 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
865 delete ev->event_pool();
870 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
872 if (Splash::instance()) {
873 Splash::instance()->pop_back_for (win);
878 ARDOUR_UI::configure_timeout ()
880 if (last_configure_time == 0) {
881 /* no configure events yet */
885 /* force a gap of 0.5 seconds since the last configure event
888 if (get_microseconds() - last_configure_time < 500000) {
891 have_configure_timeout = false;
892 save_ardour_state ();
898 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
900 if (have_configure_timeout) {
901 last_configure_time = get_microseconds();
903 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
904 have_configure_timeout = true;
911 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
915 if (node.get_property ("roll", str)){
916 roll_controllable->set_id (str);
918 if (node.get_property ("stop", str)) {
919 stop_controllable->set_id (str);
921 if (node.get_property ("goto-start", str)) {
922 goto_start_controllable->set_id (str);
924 if (node.get_property ("goto-end", str)) {
925 goto_end_controllable->set_id (str);
927 if (node.get_property ("auto-loop", str)) {
928 auto_loop_controllable->set_id (str);
930 if (node.get_property ("play-selection", str)) {
931 play_selection_controllable->set_id (str);
933 if (node.get_property ("rec", str)) {
934 rec_controllable->set_id (str);
936 if (node.get_property ("shuttle", str)) {
937 shuttle_box.controllable()->set_id (str);
942 ARDOUR_UI::get_transport_controllable_state ()
944 XMLNode* node = new XMLNode(X_("TransportControllables"));
946 node->set_property (X_("roll"), roll_controllable->id());
947 node->set_property (X_("stop"), stop_controllable->id());
948 node->set_property (X_("goto-start"), goto_start_controllable->id());
949 node->set_property (X_("goto-end"), goto_end_controllable->id());
950 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
951 node->set_property (X_("play-selection"), play_selection_controllable->id());
952 node->set_property (X_("rec"), rec_controllable->id());
953 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
959 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
962 _session->save_state (snapshot_name);
967 ARDOUR_UI::autosave_session ()
969 if (g_main_depth() > 1) {
970 /* inside a recursive main loop,
971 give up because we may not be able to
977 if (!Config->get_periodic_safety_backups()) {
982 _session->maybe_write_autosave();
989 ARDOUR_UI::session_dirty_changed ()
996 ARDOUR_UI::update_autosave ()
998 if (_session && _session->dirty()) {
999 if (_autosave_connection.connected()) {
1000 _autosave_connection.disconnect();
1003 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1004 Config->get_periodic_safety_backup_interval() * 1000);
1007 if (_autosave_connection.connected()) {
1008 _autosave_connection.disconnect();
1014 ARDOUR_UI::check_announcements ()
1017 string _annc_filename;
1020 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1021 #elif defined PLATFORM_WINDOWS
1022 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1024 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1026 _annc_filename.append (VERSIONSTRING);
1028 _announce_string = "";
1030 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1031 FILE* fin = g_fopen (path.c_str(), "rb");
1033 while (!feof (fin)) {
1036 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1039 _announce_string.append (tmp, len);
1044 pingback (VERSIONSTRING, path);
1049 _hide_splash (gpointer arg)
1051 ((ARDOUR_UI*)arg)->hide_splash();
1056 ARDOUR_UI::starting ()
1058 Application* app = Application::instance ();
1059 const char *nsm_url;
1060 bool brand_new_user = ArdourStartup::required ();
1062 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1063 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1065 if (ARDOUR_COMMAND_LINE::check_announcements) {
1066 check_announcements ();
1071 /* we need to create this early because it may need to set the
1072 * audio backend end up.
1076 audio_midi_setup.get (true);
1078 std::cerr << "audio-midi engine setup failed."<< std::endl;
1082 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1083 nsm = new NSM_Client;
1084 if (!nsm->init (nsm_url)) {
1085 /* the ardour executable may have different names:
1087 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1088 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1089 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1091 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1093 const char *process_name = g_getenv ("ARDOUR_SELF");
1094 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1097 // wait for announce reply from nsm server
1098 for ( i = 0; i < 5000; ++i) {
1102 if (nsm->is_active()) {
1107 error << _("NSM server did not announce itself") << endmsg;
1110 // wait for open command from nsm server
1111 for ( i = 0; i < 5000; ++i) {
1113 Glib::usleep (1000);
1114 if (nsm->client_id ()) {
1120 error << _("NSM: no client ID provided") << endmsg;
1124 if (_session && nsm) {
1125 _session->set_nsm_state( nsm->is_active() );
1127 error << _("NSM: no session created") << endmsg;
1131 // nsm requires these actions disabled
1132 vector<string> action_names;
1133 action_names.push_back("SaveAs");
1134 action_names.push_back("Rename");
1135 action_names.push_back("New");
1136 action_names.push_back("Open");
1137 action_names.push_back("Recent");
1138 action_names.push_back("Close");
1140 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1141 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1143 act->set_sensitive (false);
1150 error << _("NSM: initialization failed") << endmsg;
1156 if (brand_new_user) {
1157 _initial_verbose_plugin_scan = true;
1162 _initial_verbose_plugin_scan = false;
1163 switch (s.response ()) {
1164 case Gtk::RESPONSE_OK:
1171 // TODO: maybe IFF brand_new_user
1172 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1173 std::string dspd (Config->get_default_session_parent_dir());
1174 Searchpath ds (ARDOUR::ardour_data_search_path());
1175 ds.add_subdirectory_to_paths ("sessions");
1176 vector<string> demos;
1177 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1179 ARDOUR::RecentSessions rs;
1180 ARDOUR::read_recent_sessions (rs);
1182 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1183 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1184 std::string name = basename_nosuffix (basename_nosuffix (*i));
1185 std::string path = Glib::build_filename (dspd, name);
1186 /* skip if session-dir already exists */
1187 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1190 /* skip sessions that are already in 'recent'.
1191 * eg. a new user changed <session-default-dir> shorly after installation
1193 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1194 if ((*r).first == name) {
1199 PBD::FileArchive ar (*i);
1200 if (0 == ar.inflate (dspd)) {
1201 store_recent_sessions (name, path);
1202 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1208 #ifdef NO_PLUGIN_STATE
1210 ARDOUR::RecentSessions rs;
1211 ARDOUR::read_recent_sessions (rs);
1213 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1215 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1217 /* already used Ardour, have sessions ... warn about plugin state */
1219 ArdourDialog d (_("Free/Demo Version Warning"), true);
1221 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1222 CheckButton c (_("Don't warn me about this again"));
1224 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1225 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1226 _("It will not restore OR save any plugin settings"),
1227 _("If you load an existing session with plugin settings\n"
1228 "they will not be used and will be lost."),
1229 _("To get full access to updates without this limitation\n"
1230 "consider becoming a subscriber for a low cost every month.")));
1231 l.set_justify (JUSTIFY_CENTER);
1233 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1235 d.get_vbox()->pack_start (l, true, true);
1236 d.get_vbox()->pack_start (b, false, false, 12);
1237 d.get_vbox()->pack_start (c, false, false, 12);
1239 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1240 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1244 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1246 if (d.run () != RESPONSE_OK) {
1252 /* go get a session */
1254 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1256 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1257 std::cerr << "Cannot get session parameters."<< std::endl;
1264 WM::Manager::instance().show_visible ();
1266 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1267 * editor window, and we may want stuff to be hidden.
1269 _status_bar_visibility.update ();
1271 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1273 /* all other dialogs are created conditionally */
1279 ARDOUR_UI::check_memory_locking ()
1281 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1282 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1286 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1288 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1290 struct rlimit limits;
1292 long pages, page_size;
1294 size_t pages_len=sizeof(pages);
1295 if ((page_size = getpagesize()) < 0 ||
1296 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1298 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1303 ram = (int64_t) pages * (int64_t) page_size;
1306 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1310 if (limits.rlim_cur != RLIM_INFINITY) {
1312 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1316 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1317 "This might cause %1 to run out of memory before your system "
1318 "runs out of memory. \n\n"
1319 "You can view the memory limit with 'ulimit -l', "
1320 "and it is normally controlled by %2"),
1323 X_("/etc/login.conf")
1325 X_(" /etc/security/limits.conf")
1329 msg.set_default_response (RESPONSE_OK);
1331 VBox* vbox = msg.get_vbox();
1333 CheckButton cb (_("Do not show this window again"));
1334 hbox.pack_start (cb, true, false);
1335 vbox->pack_start (hbox);
1340 pop_back_splash (msg);
1344 if (cb.get_active()) {
1345 XMLNode node (X_("no-memory-warning"));
1346 Config->add_instant_xml (node);
1351 #endif // !__APPLE__
1356 ARDOUR_UI::queue_finish ()
1358 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1362 ARDOUR_UI::idle_finish ()
1365 return false; /* do not call again */
1372 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1374 if (_session->dirty()) {
1375 vector<string> actions;
1376 actions.push_back (_("Don't quit"));
1377 actions.push_back (_("Just quit"));
1378 actions.push_back (_("Save and quit"));
1379 switch (ask_about_saving_session(actions)) {
1384 /* use the default name */
1385 if (save_state_canfail ("")) {
1386 /* failed - don't quit */
1387 MessageDialog msg (_main_window,
1388 string_compose (_("\
1389 %1 was unable to save your session.\n\n\
1390 If you still wish to quit, please use the\n\n\
1391 \"Just quit\" option."), PROGRAM_NAME));
1392 pop_back_splash(msg);
1402 second_connection.disconnect ();
1403 point_one_second_connection.disconnect ();
1404 point_zero_something_second_connection.disconnect();
1405 fps_connection.disconnect();
1408 delete ARDOUR_UI::instance()->video_timeline;
1409 ARDOUR_UI::instance()->video_timeline = NULL;
1410 stop_video_server();
1412 /* Save state before deleting the session, as that causes some
1413 windows to be destroyed before their visible state can be
1416 save_ardour_state ();
1418 if (key_editor.get (false)) {
1419 key_editor->disconnect ();
1422 close_all_dialogs ();
1425 _session->set_clean ();
1426 _session->remove_pending_capture_state ();
1431 halt_connection.disconnect ();
1432 AudioEngine::instance()->stop ();
1433 #ifdef WINDOWS_VST_SUPPORT
1434 fst_stop_threading();
1440 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1442 ArdourDialog window (_("Unsaved Session"));
1443 Gtk::HBox dhbox; // the hbox for the image and text
1444 Gtk::Label prompt_label;
1445 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1449 assert (actions.size() >= 3);
1451 window.add_button (actions[0], RESPONSE_REJECT);
1452 window.add_button (actions[1], RESPONSE_APPLY);
1453 window.add_button (actions[2], RESPONSE_ACCEPT);
1455 window.set_default_response (RESPONSE_ACCEPT);
1457 Gtk::Button noquit_button (msg);
1458 noquit_button.set_name ("EditorGTKButton");
1462 if (_session->snap_name() == _session->name()) {
1463 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1464 _session->snap_name());
1466 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1467 _session->snap_name());
1470 prompt_label.set_text (prompt);
1471 prompt_label.set_name (X_("PrompterLabel"));
1472 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1474 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1475 dhbox.set_homogeneous (false);
1476 dhbox.pack_start (*dimage, false, false, 5);
1477 dhbox.pack_start (prompt_label, true, false, 5);
1478 window.get_vbox()->pack_start (dhbox);
1480 window.set_name (_("Prompter"));
1481 window.set_modal (true);
1482 window.set_resizable (false);
1485 prompt_label.show();
1490 ResponseType r = (ResponseType) window.run();
1495 case RESPONSE_ACCEPT: // save and get out of here
1497 case RESPONSE_APPLY: // get out of here
1508 ARDOUR_UI::every_second ()
1511 update_disk_space ();
1512 update_timecode_format ();
1513 update_peak_thread_work ();
1515 if (nsm && nsm->is_active ()) {
1518 if (!_was_dirty && _session->dirty ()) {
1522 else if (_was_dirty && !_session->dirty ()){
1530 ARDOUR_UI::every_point_one_seconds ()
1532 if (editor) editor->build_region_boundary_cache();
1536 ARDOUR_UI::every_point_zero_something_seconds ()
1538 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1540 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1541 float mpeak = editor_meter->update_meters();
1542 if (mpeak > editor_meter_max_peak) {
1543 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1544 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1551 ARDOUR_UI::set_fps_timeout_connection ()
1553 unsigned int interval = 40;
1554 if (!_session) return;
1555 if (_session->timecode_frames_per_second() != 0) {
1556 /* ideally we'll use a select() to sleep and not accumulate
1557 * idle time to provide a regular periodic signal.
1558 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1559 * However, that'll require a dedicated thread and cross-thread
1560 * signals to the GUI Thread..
1562 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1563 * _session->sample_rate() / _session->nominal_sample_rate()
1564 / _session->timecode_frames_per_second()
1566 #ifdef PLATFORM_WINDOWS
1567 // the smallest windows scheduler time-slice is ~15ms.
1568 // periodic GUI timeouts shorter than that will cause
1569 // WaitForSingleObject to spinlock (100% of one CPU Core)
1570 // and gtk never enters idle mode.
1571 // also changing timeBeginPeriod(1) does not affect that in
1572 // any beneficial way, so we just limit the max rate for now.
1573 interval = std::max(30u, interval); // at most ~33Hz.
1575 interval = std::max(8u, interval); // at most 120Hz.
1578 fps_connection.disconnect();
1579 Timers::set_fps_interval (interval);
1583 ARDOUR_UI::update_sample_rate (samplecnt_t)
1587 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1589 if (!AudioEngine::instance()->connected()) {
1591 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1595 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1598 /* no sample rate available */
1599 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1602 if (fmod (rate, 1000.0) != 0.0) {
1603 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1604 (float) rate / 1000.0f,
1605 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1607 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1609 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1613 sample_rate_label.set_markup (buf);
1617 ARDOUR_UI::update_format ()
1620 format_label.set_text ("");
1625 s << _("File:") << X_(" <span foreground=\"green\">");
1627 switch (_session->config.get_native_file_header_format ()) {
1659 switch (_session->config.get_native_file_data_format ()) {
1673 format_label.set_markup (s.str ());
1677 ARDOUR_UI::update_cpu_load ()
1679 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1680 double const c = AudioEngine::instance()->get_dsp_load ();
1682 const char* const bg = c > 90 ? " background=\"red\"" : "";
1686 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1688 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1690 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1693 dsp_load_label.set_markup (buf);
1696 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1698 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1700 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1703 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1707 ARDOUR_UI::update_peak_thread_work ()
1710 const int c = SourceFactory::peak_work_queue_length ();
1712 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1713 peak_thread_work_label.set_markup (buf);
1715 peak_thread_work_label.set_markup (X_(""));
1720 ARDOUR_UI::count_recenabled_streams (Route& route)
1722 Track* track = dynamic_cast<Track*>(&route);
1723 if (track && track->rec_enable_control()->get_value()) {
1724 rec_enabled_streams += track->n_inputs().n_total();
1729 ARDOUR_UI::format_disk_space_label (float remain_sec)
1731 if (remain_sec < 0) {
1732 disk_space_label.set_text (_("N/A"));
1733 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1739 int sec = floor (remain_sec);
1740 int hrs = sec / 3600;
1741 int mins = (sec / 60) % 60;
1742 int secs = sec % 60;
1743 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1744 ArdourWidgets::set_tooltip (disk_space_label, buf);
1746 if (remain_sec > 86400) {
1747 disk_space_label.set_text (_("Rec: >24h"));
1749 } else if (remain_sec > 32400 /* 9 hours */) {
1750 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1751 } else if (remain_sec > 5940 /* 99 mins */) {
1752 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1754 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1756 disk_space_label.set_text (buf);
1761 ARDOUR_UI::update_disk_space()
1763 if (_session == 0) {
1764 format_disk_space_label (-1);
1768 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1769 samplecnt_t fr = _session->sample_rate();
1772 /* skip update - no SR available */
1773 format_disk_space_label (-1);
1778 /* Available space is unknown */
1779 format_disk_space_label (-1);
1780 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1781 format_disk_space_label (max_samplecnt);
1783 rec_enabled_streams = 0;
1784 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1786 samplecnt_t samples = opt_samples.get_value_or (0);
1788 if (rec_enabled_streams) {
1789 samples /= rec_enabled_streams;
1792 format_disk_space_label (samples / (float)fr);
1798 ARDOUR_UI::update_timecode_format ()
1804 TimecodeSlave* tcslave;
1805 SyncSource sync_src = Config->get_sync_source();
1807 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1808 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1813 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1814 matching ? X_("green") : X_("red"),
1815 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1817 snprintf (buf, sizeof (buf), "TC: n/a");
1820 timecode_format_label.set_markup (buf);
1824 ARDOUR_UI::update_wall_clock ()
1828 static int last_min = -1;
1831 tm_now = localtime (&now);
1832 if (last_min != tm_now->tm_min) {
1834 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1835 wall_clock_label.set_text (buf);
1836 last_min = tm_now->tm_min;
1843 ARDOUR_UI::open_recent_session ()
1845 bool can_return = (_session != 0);
1847 SessionDialog recent_session_dialog;
1851 ResponseType r = (ResponseType) recent_session_dialog.run ();
1854 case RESPONSE_ACCEPT:
1858 recent_session_dialog.hide();
1865 recent_session_dialog.hide();
1869 std::string path = recent_session_dialog.session_folder();
1870 std::string state = recent_session_dialog.session_name (should_be_new);
1872 if (should_be_new == true) {
1876 _session_is_new = false;
1878 if (load_session (path, state) == 0) {
1887 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1889 if (!AudioEngine::instance()->connected()) {
1890 MessageDialog msg (parent, string_compose (
1891 _("%1 is not connected to any audio backend.\n"
1892 "You cannot open or close sessions in this condition"),
1894 pop_back_splash (msg);
1902 ARDOUR_UI::open_session ()
1904 if (!check_audioengine (_main_window)) {
1908 /* ardour sessions are folders */
1909 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1910 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1911 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1912 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1915 string session_parent_dir = Glib::path_get_dirname(_session->path());
1916 open_session_selector.set_current_folder(session_parent_dir);
1918 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1921 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1923 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1924 string default_session_folder = Config->get_default_session_parent_dir();
1925 open_session_selector.add_shortcut_folder (default_session_folder);
1927 catch (Glib::Error const& e) {
1928 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1931 FileFilter session_filter;
1932 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1933 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1934 open_session_selector.add_filter (session_filter);
1936 FileFilter archive_filter;
1937 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1938 archive_filter.set_name (_("Session Archives"));
1940 open_session_selector.add_filter (archive_filter);
1942 open_session_selector.set_filter (session_filter);
1944 int response = open_session_selector.run();
1945 open_session_selector.hide ();
1947 if (response == Gtk::RESPONSE_CANCEL) {
1951 string session_path = open_session_selector.get_filename();
1955 if (session_path.length() > 0) {
1956 int rv = ARDOUR::inflate_session (session_path,
1957 Config->get_default_session_parent_dir(), path, name);
1959 _session_is_new = false;
1960 load_session (path, name);
1963 MessageDialog msg (_main_window,
1964 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1967 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1968 _session_is_new = isnew;
1969 load_session (path, name);
1975 ARDOUR_UI::session_add_mixed_track (
1976 const ChanCount& input,
1977 const ChanCount& output,
1978 RouteGroup* route_group,
1980 const string& name_template,
1982 PluginInfoPtr instrument,
1983 Plugin::PresetRecord* pset,
1984 ARDOUR::PresentationInfo::order_t order)
1988 if (Profile->get_mixbus ()) {
1993 list<boost::shared_ptr<MidiTrack> > tracks;
1994 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1996 if (tracks.size() != how_many) {
1997 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2002 display_insufficient_ports_message ();
2008 ARDOUR_UI::session_add_midi_bus (
2009 RouteGroup* route_group,
2011 const string& name_template,
2013 PluginInfoPtr instrument,
2014 Plugin::PresetRecord* pset,
2015 ARDOUR::PresentationInfo::order_t order)
2017 if (_session == 0) {
2018 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2022 if (Profile->get_mixbus ()) {
2028 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2029 if (routes.size() != how_many) {
2030 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2035 display_insufficient_ports_message ();
2041 ARDOUR_UI::session_add_midi_route (
2043 RouteGroup* route_group,
2045 const string& name_template,
2047 PluginInfoPtr instrument,
2048 Plugin::PresetRecord* pset,
2049 ARDOUR::PresentationInfo::order_t order)
2051 ChanCount one_midi_channel;
2052 one_midi_channel.set (DataType::MIDI, 1);
2055 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2057 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2062 ARDOUR_UI::session_add_audio_route (
2064 int32_t input_channels,
2065 int32_t output_channels,
2066 ARDOUR::TrackMode mode,
2067 RouteGroup* route_group,
2069 string const & name_template,
2071 ARDOUR::PresentationInfo::order_t order)
2073 list<boost::shared_ptr<AudioTrack> > tracks;
2080 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2082 if (tracks.size() != how_many) {
2083 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2089 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2091 if (routes.size() != how_many) {
2092 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2099 display_insufficient_ports_message ();
2104 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2105 (*i)->set_strict_io (true);
2107 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2108 (*i)->set_strict_io (true);
2114 ARDOUR_UI::display_insufficient_ports_message ()
2116 MessageDialog msg (_main_window,
2117 string_compose (_("There are insufficient ports available\n\
2118 to create a new track or bus.\n\
2119 You should save %1, exit and\n\
2120 restart with more ports."), PROGRAM_NAME));
2121 pop_back_splash (msg);
2126 ARDOUR_UI::transport_goto_start ()
2129 _session->goto_start();
2131 /* force displayed area in editor to start no matter
2132 what "follow playhead" setting is.
2136 editor->center_screen (_session->current_start_sample ());
2142 ARDOUR_UI::transport_goto_zero ()
2145 _session->request_locate (0);
2147 /* force displayed area in editor to start no matter
2148 what "follow playhead" setting is.
2152 editor->reset_x_origin (0);
2158 ARDOUR_UI::transport_goto_wallclock ()
2160 if (_session && editor) {
2164 samplepos_t samples;
2167 localtime_r (&now, &tmnow);
2169 samplecnt_t sample_rate = _session->sample_rate();
2171 if (sample_rate == 0) {
2172 /* no frame rate available */
2176 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2177 samples += tmnow.tm_min * (60 * sample_rate);
2178 samples += tmnow.tm_sec * sample_rate;
2180 _session->request_locate (samples, _session->transport_rolling ());
2182 /* force displayed area in editor to start no matter
2183 what "follow playhead" setting is.
2187 editor->center_screen (samples);
2193 ARDOUR_UI::transport_goto_end ()
2196 samplepos_t const sample = _session->current_end_sample();
2197 _session->request_locate (sample);
2199 /* force displayed area in editor to start no matter
2200 what "follow playhead" setting is.
2204 editor->center_screen (sample);
2210 ARDOUR_UI::transport_stop ()
2216 if (_session->is_auditioning()) {
2217 _session->cancel_audition ();
2221 _session->request_stop (false, true);
2224 /** Check if any tracks are record enabled. If none are, record enable all of them.
2225 * @return true if track record-enabled status was changed, false otherwise.
2228 ARDOUR_UI::trx_record_enable_all_tracks ()
2234 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2235 bool none_record_enabled = true;
2237 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2238 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2241 if (t->rec_enable_control()->get_value()) {
2242 none_record_enabled = false;
2247 if (none_record_enabled) {
2248 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2251 return none_record_enabled;
2255 ARDOUR_UI::transport_record (bool roll)
2258 switch (_session->record_status()) {
2259 case Session::Disabled:
2260 if (_session->ntracks() == 0) {
2261 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."));
2265 if (Profile->get_trx()) {
2266 roll = trx_record_enable_all_tracks ();
2268 _session->maybe_enable_record ();
2273 case Session::Recording:
2275 _session->request_stop();
2277 _session->disable_record (false, true);
2281 case Session::Enabled:
2282 _session->disable_record (false, true);
2288 ARDOUR_UI::transport_roll ()
2294 if (_session->is_auditioning()) {
2299 if (_session->config.get_external_sync()) {
2300 switch (Config->get_sync_source()) {
2304 /* transport controlled by the master */
2310 bool rolling = _session->transport_rolling();
2312 if (_session->get_play_loop()) {
2314 /* If loop playback is not a mode, then we should cancel
2315 it when this action is requested. If it is a mode
2316 we just leave it in place.
2319 if (!Config->get_loop_is_mode()) {
2320 /* XXX it is not possible to just leave seamless loop and keep
2321 playing at present (nov 4th 2009)
2323 if (!Config->get_seamless_loop()) {
2324 /* stop loop playback and stop rolling */
2325 _session->request_play_loop (false, true);
2326 } else if (rolling) {
2327 /* stop loop playback but keep rolling */
2328 _session->request_play_loop (false, false);
2332 } else if (_session->get_play_range () ) {
2333 /* stop playing a range if we currently are */
2334 _session->request_play_range (0, true);
2338 _session->request_transport_speed (1.0f);
2343 ARDOUR_UI::get_smart_mode() const
2345 return ( editor->get_smart_mode() );
2350 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2356 if (_session->is_auditioning()) {
2357 _session->cancel_audition ();
2361 if (_session->config.get_external_sync()) {
2362 switch (Config->get_sync_source()) {
2366 /* transport controlled by the master */
2371 bool rolling = _session->transport_rolling();
2372 bool affect_transport = true;
2374 if (rolling && roll_out_of_bounded_mode) {
2375 /* drop out of loop/range playback but leave transport rolling */
2376 if (_session->get_play_loop()) {
2377 if (_session->actively_recording()) {
2379 /* just stop using the loop, then actually stop
2382 _session->request_play_loop (false, affect_transport);
2385 if (Config->get_seamless_loop()) {
2386 /* the disk buffers contain copies of the loop - we can't
2387 just keep playing, so stop the transport. the user
2388 can restart as they wish.
2390 affect_transport = true;
2392 /* disk buffers are normal, so we can keep playing */
2393 affect_transport = false;
2395 _session->request_play_loop (false, affect_transport);
2397 } else if (_session->get_play_range ()) {
2398 affect_transport = false;
2399 _session->request_play_range (0, true);
2403 if (affect_transport) {
2405 _session->request_stop (with_abort, true);
2407 } else if (!with_abort) { /* with_abort == true means the
2408 * command was intended to stop
2409 * transport, not start.
2412 /* the only external sync condition we can be in here
2413 * would be Engine (JACK) sync, in which case we still
2417 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
2418 _session->request_play_range (&editor->get_selection().time, true);
2419 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2421 _session->request_transport_speed (1.0f);
2427 ARDOUR_UI::toggle_session_auto_loop ()
2433 Location * looploc = _session->locations()->auto_loop_location();
2439 if (_session->get_play_loop()) {
2441 /* looping enabled, our job is to disable it */
2443 _session->request_play_loop (false);
2447 /* looping not enabled, our job is to enable it.
2449 loop-is-NOT-mode: this action always starts the transport rolling.
2450 loop-IS-mode: this action simply sets the loop play mechanism, but
2451 does not start transport.
2453 if (Config->get_loop_is_mode()) {
2454 _session->request_play_loop (true, false);
2456 _session->request_play_loop (true, true);
2460 //show the loop markers
2461 looploc->set_hidden (false, this);
2465 ARDOUR_UI::transport_play_selection ()
2471 editor->play_selection ();
2475 ARDOUR_UI::transport_play_preroll ()
2480 editor->play_with_preroll ();
2484 ARDOUR_UI::transport_rec_preroll ()
2489 editor->rec_with_preroll ();
2493 ARDOUR_UI::transport_rec_count_in ()
2498 editor->rec_with_count_in ();
2502 ARDOUR_UI::transport_rewind (int option)
2504 float current_transport_speed;
2507 current_transport_speed = _session->transport_speed();
2509 if (current_transport_speed >= 0.0f) {
2512 _session->request_transport_speed (-1.0f);
2515 _session->request_transport_speed (-4.0f);
2518 _session->request_transport_speed (-0.5f);
2523 _session->request_transport_speed (current_transport_speed * 1.5f);
2529 ARDOUR_UI::transport_forward (int option)
2535 float current_transport_speed = _session->transport_speed();
2537 if (current_transport_speed <= 0.0f) {
2540 _session->request_transport_speed (1.0f);
2543 _session->request_transport_speed (4.0f);
2546 _session->request_transport_speed (0.5f);
2551 _session->request_transport_speed (current_transport_speed * 1.5f);
2556 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2562 boost::shared_ptr<Route> r;
2564 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2566 boost::shared_ptr<Track> t;
2568 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2569 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2575 ARDOUR_UI::map_transport_state ()
2578 layered_button.set_sensitive (false);
2582 shuttle_box.map_transport_state ();
2584 float sp = _session->transport_speed();
2587 layered_button.set_sensitive (!_session->actively_recording ());
2589 layered_button.set_sensitive (true);
2590 update_disk_space ();
2595 ARDOUR_UI::blink_handler (bool blink_on)
2597 sync_blink (blink_on);
2599 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2602 error_blink (blink_on);
2603 solo_blink (blink_on);
2604 audition_blink (blink_on);
2605 feedback_blink (blink_on);
2609 ARDOUR_UI::update_clocks ()
2611 if (!_session) return;
2613 if (editor && !editor->dragging_playhead()) {
2614 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2619 ARDOUR_UI::start_clocking ()
2621 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2622 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2624 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2629 ARDOUR_UI::stop_clocking ()
2631 clock_signal_connection.disconnect ();
2635 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2639 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2641 label->set_text (buf);
2642 bar->set_fraction (fraction);
2644 /* process events, redraws, etc. */
2646 while (gtk_events_pending()) {
2647 gtk_main_iteration ();
2650 return true; /* continue with save-as */
2654 ARDOUR_UI::save_session_as ()
2660 if (_session->dirty()) {
2661 vector<string> actions;
2662 actions.push_back (_("Abort save-as"));
2663 actions.push_back (_("Don't save now, just save-as"));
2664 actions.push_back (_("Save it first"));
2665 switch (ask_about_saving_session(actions)) {
2670 if (save_state_canfail ("")) {
2671 MessageDialog msg (_main_window,
2672 string_compose (_("\
2673 %1 was unable to save your session.\n\n\
2674 If you still wish to proceed, please use the\n\n\
2675 \"Don't save now\" option."), PROGRAM_NAME));
2676 pop_back_splash(msg);
2682 _session->remove_pending_capture_state ();
2687 if (!save_as_dialog) {
2688 save_as_dialog = new SaveAsDialog;
2691 save_as_dialog->set_name (_session->name());
2693 int response = save_as_dialog->run ();
2695 save_as_dialog->hide ();
2698 case Gtk::RESPONSE_OK:
2707 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2708 sa.new_name = save_as_dialog->new_name ();
2709 sa.switch_to = save_as_dialog->switch_to();
2710 sa.copy_media = save_as_dialog->copy_media();
2711 sa.copy_external = save_as_dialog->copy_external();
2712 sa.include_media = save_as_dialog->include_media ();
2714 /* Only bother with a progress dialog if we're going to copy
2715 media into the save-as target. Without that choice, this
2716 will be very fast because we're only talking about a few kB's to
2717 perhaps a couple of MB's of data.
2720 ArdourDialog progress_dialog (_("Save As"), true);
2723 if (sa.include_media && sa.copy_media) {
2725 Gtk::Label* label = manage (new Gtk::Label());
2726 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2728 progress_dialog.get_vbox()->pack_start (*label);
2729 progress_dialog.get_vbox()->pack_start (*progress_bar);
2731 progress_bar->show ();
2733 /* this signal will be emitted from within this, the calling thread,
2734 * after every file is copied. It provides information on percentage
2735 * complete (in terms of total data to copy), the number of files
2736 * copied so far, and the total number to copy.
2739 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2741 progress_dialog.show_all ();
2742 progress_dialog.present ();
2745 if (_session->save_as (sa)) {
2747 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2751 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2752 * the trick is this: if the new session was copy with media included,
2753 * then Session::save_as() will have already done a neat trick to avoid
2754 * us having to unload and load the new state. But if the media was not
2755 * included, then this is required (it avoids us having to otherwise
2756 * drop all references to media (sources).
2759 if (!sa.include_media && sa.switch_to) {
2760 unload_session (false);
2761 load_session (sa.final_session_folder_name, sa.new_name);
2766 ARDOUR_UI::archive_session ()
2774 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2776 SessionArchiveDialog sad;
2777 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2778 int response = sad.run ();
2780 if (response != Gtk::RESPONSE_OK) {
2785 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2786 MessageDialog msg (_("Session Archiving failed."));
2792 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2796 struct tm local_time;
2799 localtime_r (&n, &local_time);
2800 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2801 if (switch_to_it && _session->dirty ()) {
2802 save_state_canfail ("");
2805 save_state (timebuf, switch_to_it);
2810 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2814 prompter.get_result (snapname);
2816 bool do_save = (snapname.length() != 0);
2819 char illegal = Session::session_name_is_legal(snapname);
2821 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2822 "snapshot names may not contain a '%1' character"), illegal));
2828 vector<std::string> p;
2829 get_state_files_in_directory (_session->session_directory().root_path(), p);
2830 vector<string> n = get_file_names_no_extension (p);
2832 if (find (n.begin(), n.end(), snapname) != n.end()) {
2834 do_save = overwrite_file_dialog (prompter,
2835 _("Confirm Snapshot Overwrite"),
2836 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2840 save_state (snapname, switch_to_it);
2850 /** Ask the user for the name of a new snapshot and then take it.
2854 ARDOUR_UI::snapshot_session (bool switch_to_it)
2856 if (switch_to_it && _session->dirty()) {
2857 vector<string> actions;
2858 actions.push_back (_("Abort saving snapshot"));
2859 actions.push_back (_("Don't save now, just snapshot"));
2860 actions.push_back (_("Save it first"));
2861 switch (ask_about_saving_session(actions)) {
2866 if (save_state_canfail ("")) {
2867 MessageDialog msg (_main_window,
2868 string_compose (_("\
2869 %1 was unable to save your session.\n\n\
2870 If you still wish to proceed, please use the\n\n\
2871 \"Don't save now\" option."), PROGRAM_NAME));
2872 pop_back_splash(msg);
2878 _session->remove_pending_capture_state ();
2883 Prompter prompter (true);
2884 prompter.set_name ("Prompter");
2885 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2887 prompter.set_title (_("Snapshot and switch"));
2888 prompter.set_prompt (_("New session name"));
2890 prompter.set_title (_("Take Snapshot"));
2891 prompter.set_prompt (_("Name of new snapshot"));
2895 prompter.set_initial_text (_session->snap_name());
2897 Glib::DateTime tm (g_date_time_new_now_local ());
2898 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2901 bool finished = false;
2903 switch (prompter.run()) {
2904 case RESPONSE_ACCEPT:
2906 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2917 /** Ask the user for a new session name and then rename the session to it.
2921 ARDOUR_UI::rename_session ()
2927 Prompter prompter (true);
2930 prompter.set_name ("Prompter");
2931 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2932 prompter.set_title (_("Rename Session"));
2933 prompter.set_prompt (_("New session name"));
2936 switch (prompter.run()) {
2937 case RESPONSE_ACCEPT:
2939 prompter.get_result (name);
2941 bool do_rename = (name.length() != 0);
2944 char illegal = Session::session_name_is_legal (name);
2947 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2948 "session names may not contain a '%1' character"), illegal));
2953 switch (_session->rename (name)) {
2955 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2956 msg.set_position (WIN_POS_MOUSE);
2964 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2965 msg.set_position (WIN_POS_MOUSE);
2981 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2983 if (!_session || _session->deletion_in_progress()) {
2987 XMLNode* node = new XMLNode (X_("UI"));
2989 WM::Manager::instance().add_state (*node);
2991 node->add_child_nocopy (gui_object_state->get_state());
2993 _session->add_extra_xml (*node);
2995 if (export_video_dialog) {
2996 _session->add_extra_xml (export_video_dialog->get_state());
2999 save_state_canfail (name, switch_to_it);
3003 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3008 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3013 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3018 ARDOUR_UI::primary_clock_value_changed ()
3021 _session->request_locate (primary_clock->current_time ());
3026 ARDOUR_UI::big_clock_value_changed ()
3029 _session->request_locate (big_clock->current_time ());
3034 ARDOUR_UI::secondary_clock_value_changed ()
3037 _session->request_locate (secondary_clock->current_time ());
3041 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3043 if (response == RESPONSE_ACCEPT) {
3044 const string name = d->get_template_name ();
3045 const string desc = d->get_description ();
3047 int failed = _session->save_template (name, desc);
3049 if (failed == -2) { /* file already exists. */
3050 bool overwrite = overwrite_file_dialog (*d,
3051 _("Confirm Template Overwrite"),
3052 _("A template already exists with that name. Do you want to overwrite it?"));
3055 _session->save_template (name, desc, true);
3067 ARDOUR_UI::save_template ()
3069 if (!check_audioengine (_main_window)) {
3073 const std::string desc = SessionMetadata::Metadata()->description ();
3074 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3075 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3079 void ARDOUR_UI::manage_templates ()
3086 ARDOUR_UI::edit_metadata ()
3088 SessionMetadataEditor dialog;
3089 dialog.set_session (_session);
3090 dialog.grab_focus ();
3095 ARDOUR_UI::import_metadata ()
3097 SessionMetadataImporter dialog;
3098 dialog.set_session (_session);
3103 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3105 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3107 MessageDialog msg (str,
3109 Gtk::MESSAGE_WARNING,
3110 Gtk::BUTTONS_YES_NO,
3114 msg.set_name (X_("OpenExistingDialog"));
3115 msg.set_title (_("Open Existing Session"));
3116 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3117 msg.set_position (Gtk::WIN_POS_CENTER);
3118 pop_back_splash (msg);
3120 switch (msg.run()) {
3129 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3131 BusProfile bus_profile;
3134 bus_profile.master_out_channels = 2;
3136 /* get settings from advanced section of NSD */
3137 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3140 // NULL profile: no master, no monitor
3141 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3149 ARDOUR_UI::load_from_application_api (const std::string& path)
3151 /* OS X El Capitan (and probably later) now somehow passes the command
3152 line arguments to an app via the openFile delegate protocol. Ardour
3153 already does its own command line processing, and having both
3154 pathways active causes crashes. So, if the command line was already
3155 set, do nothing here.
3158 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3162 ARDOUR_COMMAND_LINE::session_name = path;
3164 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3166 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3168 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3169 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3170 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3171 * -> SessionDialog is not displayed
3174 if (_session_dialog) {
3175 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3176 std::string session_path = path;
3177 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3178 session_path = Glib::path_get_dirname (session_path);
3180 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3181 _session_dialog->set_provided_session (session_name, session_path);
3182 _session_dialog->response (RESPONSE_NONE);
3183 _session_dialog->hide();
3188 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3189 /* /path/to/foo => /path/to/foo, foo */
3190 rv = load_session (path, basename_nosuffix (path));
3192 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3193 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3196 // if load_session fails -> pop up SessionDialog.
3198 ARDOUR_COMMAND_LINE::session_name = "";
3200 if (get_session_parameters (true, false)) {
3206 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3208 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3210 string session_name;
3211 string session_path;
3212 string template_name;
3214 bool likely_new = false;
3215 bool cancel_not_quit;
3217 /* deal with any existing DIRTY session now, rather than later. don't
3218 * treat a non-dirty session this way, so that it stays visible
3219 * as we bring up the new session dialog.
3222 if (_session && ARDOUR_UI::instance()->video_timeline) {
3223 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3226 /* if there is already a session, relabel the button
3227 on the SessionDialog so that we don't Quit directly
3229 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3231 if (_session && _session->dirty()) {
3232 if (unload_session (false)) {
3233 /* unload cancelled by user */
3236 ARDOUR_COMMAND_LINE::session_name = "";
3239 if (!load_template.empty()) {
3240 should_be_new = true;
3241 template_name = load_template;
3244 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3245 session_path = ARDOUR_COMMAND_LINE::session_name;
3247 if (!session_path.empty()) {
3248 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3249 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3250 /* session/snapshot file, change path to be dir */
3251 session_path = Glib::path_get_dirname (session_path);
3256 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3258 _session_dialog = &session_dialog;
3261 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3263 /* if they named a specific statefile, use it, otherwise they are
3264 just giving a session folder, and we want to use it as is
3265 to find the session.
3268 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3270 if (suffix != string::npos) {
3271 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3272 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3273 session_name = Glib::path_get_basename (session_name);
3275 session_path = ARDOUR_COMMAND_LINE::session_name;
3276 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3281 session_dialog.clear_given ();
3284 if (should_be_new || session_name.empty()) {
3285 /* need the dialog to get info from user */
3287 cerr << "run dialog\n";
3289 switch (session_dialog.run()) {
3290 case RESPONSE_ACCEPT:
3293 /* this is used for async * app->ShouldLoad(). */
3294 continue; // while loop
3297 if (quit_on_cancel) {
3298 ARDOUR_UI::finish ();
3299 Gtkmm2ext::Application::instance()->cleanup();
3301 pthread_cancel_all ();
3302 return -1; // caller is responsible to call exit()
3308 session_dialog.hide ();
3311 /* if we run the startup dialog again, offer more than just "new session" */
3313 should_be_new = false;
3315 session_name = session_dialog.session_name (likely_new);
3316 session_path = session_dialog.session_folder ();
3323 int rv = ARDOUR::inflate_session (session_name,
3324 Config->get_default_session_parent_dir(), session_path, session_name);
3326 MessageDialog msg (session_dialog,
3327 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3332 session_dialog.set_provided_session (session_name, session_path);
3336 // XXX check archive, inflate
3337 string::size_type suffix = session_name.find (statefile_suffix);
3339 if (suffix != string::npos) {
3340 session_name = session_name.substr (0, suffix);
3343 /* this shouldn't happen, but we catch it just in case it does */
3345 if (session_name.empty()) {
3349 if (session_dialog.use_session_template()) {
3350 template_name = session_dialog.session_template_name();
3351 _session_is_new = true;
3354 if (session_name[0] == G_DIR_SEPARATOR ||
3355 #ifdef PLATFORM_WINDOWS
3356 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3358 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3359 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3364 /* absolute path or cwd-relative path specified for session name: infer session folder
3365 from what was given.
3368 session_path = Glib::path_get_dirname (session_name);
3369 session_name = Glib::path_get_basename (session_name);
3373 session_path = session_dialog.session_folder();
3375 char illegal = Session::session_name_is_legal (session_name);
3378 MessageDialog msg (session_dialog,
3379 string_compose (_("To ensure compatibility with various systems\n"
3380 "session names may not contain a '%1' character"),
3383 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3388 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3391 if (likely_new && !nsm) {
3393 std::string existing = Glib::build_filename (session_path, session_name);
3395 if (!ask_about_loading_existing_session (existing)) {
3396 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3401 _session_is_new = false;
3406 pop_back_splash (session_dialog);
3407 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3409 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3413 char illegal = Session::session_name_is_legal(session_name);
3416 pop_back_splash (session_dialog);
3417 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3418 "session names may not contain a '%1' character"), illegal));
3420 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3424 _session_is_new = true;
3427 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3429 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3430 meta_session_setup (template_name.substr (11));
3432 } else if (likely_new && template_name.empty()) {
3434 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3438 ret = load_session (session_path, session_name, template_name);
3441 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3445 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3446 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3450 /* clear this to avoid endless attempts to load the
3454 ARDOUR_COMMAND_LINE::session_name = "";
3458 _session_dialog = NULL;
3464 ARDOUR_UI::close_session()
3466 if (!check_audioengine (_main_window)) {
3470 if (unload_session (true)) {
3474 ARDOUR_COMMAND_LINE::session_name = "";
3476 if (get_session_parameters (true, false)) {
3481 /** @param snap_name Snapshot name (without .ardour suffix).
3482 * @return -2 if the load failed because we are not connected to the AudioEngine.
3485 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3487 /* load_session calls flush_pending() which allows
3488 * GUI interaction and potentially loading another session
3489 * (that was easy via snapshot sidebar).
3490 * Recursing into load_session() from load_session() and recusive
3491 * event loops causes all kind of crashes.
3493 assert (!session_load_in_progress);
3494 if (session_load_in_progress) {
3497 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3499 Session *new_session;
3504 unload_status = unload_session ();
3506 if (unload_status < 0) {
3508 } else if (unload_status > 0) {
3514 session_loaded = false;
3516 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3519 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3522 /* this one is special */
3524 catch (AudioEngine::PortRegistrationFailure const& err) {
3526 MessageDialog msg (err.what(),
3529 Gtk::BUTTONS_CLOSE);
3531 msg.set_title (_("Port Registration Error"));
3532 msg.set_secondary_text (_("Click the Close button to try again."));
3533 msg.set_position (Gtk::WIN_POS_CENTER);
3534 pop_back_splash (msg);
3537 int response = msg.run ();
3542 case RESPONSE_CANCEL:
3549 catch (SessionException const& e) {
3550 MessageDialog msg (string_compose(
3551 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3552 path, snap_name, e.what()),
3557 msg.set_title (_("Loading Error"));
3558 msg.set_position (Gtk::WIN_POS_CENTER);
3559 pop_back_splash (msg);
3571 MessageDialog msg (string_compose(
3572 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3578 msg.set_title (_("Loading Error"));
3579 msg.set_position (Gtk::WIN_POS_CENTER);
3580 pop_back_splash (msg);
3592 list<string> const u = new_session->unknown_processors ();
3594 MissingPluginDialog d (_session, u);
3599 if (!new_session->writable()) {
3600 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3605 msg.set_title (_("Read-only Session"));
3606 msg.set_position (Gtk::WIN_POS_CENTER);
3607 pop_back_splash (msg);
3614 /* Now the session been created, add the transport controls */
3615 new_session->add_controllable(roll_controllable);
3616 new_session->add_controllable(stop_controllable);
3617 new_session->add_controllable(goto_start_controllable);
3618 new_session->add_controllable(goto_end_controllable);
3619 new_session->add_controllable(auto_loop_controllable);
3620 new_session->add_controllable(play_selection_controllable);
3621 new_session->add_controllable(rec_controllable);
3623 set_session (new_session);
3625 session_loaded = true;
3628 _session->set_clean ();
3631 #ifdef WINDOWS_VST_SUPPORT
3632 fst_stop_threading();
3636 Timers::TimerSuspender t;
3640 #ifdef WINDOWS_VST_SUPPORT
3641 fst_start_threading();
3645 if (!mix_template.empty ()) {
3646 /* if mix_template is given, assume this is a new session */
3647 string metascript = Glib::build_filename (mix_template, "template.lua");
3648 meta_session_setup (metascript);
3653 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3654 * which is queued by set_session().
3655 * If session-loading fails we hide it explicitly.
3656 * This covers both cases in a central place.
3665 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3667 Session *new_session;
3670 session_loaded = false;
3671 x = unload_session ();
3679 _session_is_new = true;
3682 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3685 catch (SessionException const& e) {
3686 cerr << "Here are the errors associated with this failed session:\n";
3688 cerr << "---------\n";
3689 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3690 msg.set_title (_("Loading Error"));
3691 msg.set_position (Gtk::WIN_POS_CENTER);
3692 pop_back_splash (msg);
3697 cerr << "Here are the errors associated with this failed session:\n";
3699 cerr << "---------\n";
3700 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3701 msg.set_title (_("Loading Error"));
3702 msg.set_position (Gtk::WIN_POS_CENTER);
3703 pop_back_splash (msg);
3708 /* Give the new session the default GUI state, if such things exist */
3711 n = Config->instant_xml (X_("Editor"));
3713 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3714 new_session->add_instant_xml (*n, false);
3716 n = Config->instant_xml (X_("Mixer"));
3718 new_session->add_instant_xml (*n, false);
3721 n = Config->instant_xml (X_("Preferences"));
3723 new_session->add_instant_xml (*n, false);
3726 /* Put the playhead at 0 and scroll fully left */
3727 n = new_session->instant_xml (X_("Editor"));
3729 n->set_property (X_("playhead"), X_("0"));
3730 n->set_property (X_("left-frame"), X_("0"));
3733 set_session (new_session);
3735 session_loaded = true;
3737 new_session->save_state(new_session->name());
3743 static void _lua_print (std::string s) {
3745 std::cout << "LuaInstance: " << s << "\n";
3747 PBD::info << "LuaInstance: " << s << endmsg;
3750 std::map<std::string, std::string>
3751 ARDOUR_UI::route_setup_info (const std::string& script_path)
3753 std::map<std::string, std::string> rv;
3755 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3760 lua.Print.connect (&_lua_print);
3763 lua_State* L = lua.getState();
3764 LuaInstance::register_classes (L);
3765 LuaBindings::set_session (L, _session);
3766 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3767 lua_setglobal (L, "Editor");
3769 lua.do_command ("function ardour () end");
3770 lua.do_file (script_path);
3773 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3774 if (!fn.isFunction ()) {
3777 luabridge::LuaRef rs = fn ();
3778 if (!rs.isTable ()) {
3781 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3782 if (!i.key().isString()) {
3785 std::string key = i.key().tostring();
3786 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3787 rv[key] = i.value().tostring();
3790 } catch (luabridge::LuaException const& e) {
3791 cerr << "LuaException:" << e.what () << endl;
3797 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3799 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3802 assert (add_route_dialog);
3805 if ((count = add_route_dialog->count()) <= 0) {
3810 lua.Print.connect (&_lua_print);
3813 lua_State* L = lua.getState();
3814 LuaInstance::register_classes (L);
3815 LuaBindings::set_session (L, _session);
3816 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3817 lua_setglobal (L, "Editor");
3819 lua.do_command ("function ardour () end");
3820 lua.do_file (script_path);
3822 luabridge::LuaRef args (luabridge::newTable (L));
3824 args["name"] = add_route_dialog->name_template ();
3825 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3826 args["group"] = add_route_dialog->route_group ();
3827 args["strict_io"] = add_route_dialog->use_strict_io ();
3828 args["instrument"] = add_route_dialog->requested_instrument ();
3829 args["track_mode"] = add_route_dialog->mode ();
3830 args["channels"] = add_route_dialog->channel_count ();
3831 args["how_many"] = count;
3834 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3835 if (fn.isFunction()) {
3838 } catch (luabridge::LuaException const& e) {
3839 cerr << "LuaException:" << e.what () << endl;
3841 display_insufficient_ports_message ();
3846 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3848 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3853 lua.Print.connect (&_lua_print);
3856 lua_State* L = lua.getState();
3857 LuaInstance::register_classes (L);
3858 LuaBindings::set_session (L, _session);
3859 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3860 lua_setglobal (L, "Editor");
3862 lua.do_command ("function ardour () end");
3863 lua.do_file (script_path);
3866 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3867 if (fn.isFunction()) {
3870 } catch (luabridge::LuaException const& e) {
3871 cerr << "LuaException:" << e.what () << endl;
3873 display_insufficient_ports_message ();
3878 ARDOUR_UI::launch_chat ()
3880 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3882 dialog.set_title (_("About the Chat"));
3883 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."));
3885 switch (dialog.run()) {
3888 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3889 #elif defined PLATFORM_WINDOWS
3890 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3892 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);