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/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/scoped_file_descriptor.h"
69 #include "pbd/xml++.h"
71 #include "gtkmm2ext/application.h"
72 #include "gtkmm2ext/bindings.h"
73 #include "gtkmm2ext/gtk_ui.h"
74 #include "gtkmm2ext/utils.h"
75 #include "gtkmm2ext/click_box.h"
76 #include "gtkmm2ext/fastmeter.h"
77 #include "gtkmm2ext/popup.h"
78 #include "gtkmm2ext/window_title.h"
80 #include "ardour/ardour.h"
81 #include "ardour/audio_backend.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/automation_watch.h"
86 #include "ardour/diskstream.h"
87 #include "ardour/filename_extensions.h"
88 #include "ardour/filesystem_paths.h"
89 #include "ardour/ltc_file_reader.h"
90 #include "ardour/midi_track.h"
91 #include "ardour/port.h"
92 #include "ardour/plugin_manager.h"
93 #include "ardour/process_thread.h"
94 #include "ardour/profile.h"
95 #include "ardour/recent_sessions.h"
96 #include "ardour/record_enable_control.h"
97 #include "ardour/session_directory.h"
98 #include "ardour/session_route.h"
99 #include "ardour/session_state_utils.h"
100 #include "ardour/session_utils.h"
101 #include "ardour/source_factory.h"
102 #include "ardour/slave.h"
103 #include "ardour/system_exec.h"
104 #include "ardour/track.h"
105 #include "ardour/vca_manager.h"
106 #include "ardour/utils.h"
108 #include "LuaBridge/LuaBridge.h"
110 #ifdef WINDOWS_VST_SUPPORT
113 #ifdef AUDIOUNIT_SUPPORT
114 #include "ardour/audio_unit.h"
117 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
122 #include "timecode/time.h"
124 typedef uint64_t microseconds_t;
129 #include "add_route_dialog.h"
130 #include "ambiguous_file_dialog.h"
131 #include "ardour_ui.h"
132 #include "audio_clock.h"
133 #include "audio_region_view.h"
134 #include "big_clock_window.h"
135 #include "bundle_manager.h"
136 #include "duplicate_routes_dialog.h"
138 #include "engine_dialog.h"
139 #include "export_video_dialog.h"
140 #include "export_video_infobox.h"
141 #include "gain_meter.h"
142 #include "global_port_matrix.h"
143 #include "gui_object.h"
144 #include "gui_thread.h"
145 #include "keyboard.h"
146 #include "keyeditor.h"
147 #include "location_ui.h"
148 #include "lua_script_manager.h"
149 #include "luawindow.h"
150 #include "main_clock.h"
151 #include "missing_file_dialog.h"
152 #include "missing_plugin_dialog.h"
153 #include "mixer_ui.h"
154 #include "meterbridge.h"
155 #include "mouse_cursors.h"
158 #include "pingback.h"
159 #include "processor_box.h"
160 #include "prompter.h"
161 #include "public_editor.h"
162 #include "rc_option_editor.h"
163 #include "route_time_axis.h"
164 #include "route_params_ui.h"
165 #include "save_as_dialog.h"
166 #include "script_selector.h"
167 #include "session_archive_dialog.h"
168 #include "session_dialog.h"
169 #include "session_metadata_dialog.h"
170 #include "session_option_editor.h"
171 #include "speaker_dialog.h"
174 #include "time_axis_view_item.h"
175 #include "time_info_box.h"
178 #include "utils_videotl.h"
179 #include "video_server_dialog.h"
180 #include "add_video_dialog.h"
181 #include "transcode_video_dialog.h"
183 #include "pbd/i18n.h"
185 using namespace ARDOUR;
186 using namespace ARDOUR_UI_UTILS;
188 using namespace Gtkmm2ext;
191 using namespace Editing;
193 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
195 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
196 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
199 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
201 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
202 "Would you like these files to be copied and used for %1 %2.x?\n\n"
203 "(This will require you to restart %1.)"),
204 PROGRAM_NAME, PROGRAM_VERSION, version),
205 false, /* no markup */
208 true /* modal, though it hardly matters since it is the only window */
211 msg.set_default_response (Gtk::RESPONSE_YES);
214 return (msg.run() == Gtk::RESPONSE_YES);
218 libxml_generic_error_func (void* /* parsing_context*/,
226 vsnprintf (buf, sizeof (buf), msg, ap);
227 error << buf << endmsg;
232 libxml_structured_error_func (void* /* parsing_context*/,
240 replace_all (msg, "\n", "");
243 if (err->file && err->line) {
244 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
247 error << ':' << err->int2;
252 error << X_("XML error: ") << msg << endmsg;
258 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
259 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
260 , session_loaded (false)
261 , gui_object_state (new GUIObjectState)
262 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
263 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
264 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
266 , global_actions (X_("global"))
267 , ignore_dual_punch (false)
268 , main_window_visibility (0)
273 , _mixer_on_top (false)
274 , _initial_verbose_plugin_scan (false)
275 , first_time_engine_run (true)
276 , secondary_clock_spacer (0)
277 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
278 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
279 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
280 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
281 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
282 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
283 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
284 , auto_input_button (ArdourButton::led_default_elements)
286 , auto_return_button (ArdourButton::led_default_elements)
287 , follow_edits_button (ArdourButton::led_default_elements)
288 , auditioning_alert_button (_("Audition"))
289 , solo_alert_button (_("Solo"))
290 , feedback_alert_button (_("Feedback"))
291 , error_alert_button ( ArdourButton::just_led_default_elements )
293 , editor_meter_peak_display()
294 , _numpad_locate_happening (false)
295 , _session_is_new (false)
296 , last_key_press_time (0)
300 , rc_option_editor (0)
301 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
302 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
303 , about (X_("about"), _("About"))
304 , location_ui (X_("locations"), S_("Ranges|Locations"))
305 , route_params (X_("inspector"), _("Tracks and Busses"))
306 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
307 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
308 , lua_script_window (X_("script-manager"), _("Script Manager"))
309 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
310 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
311 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
312 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
313 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
314 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
315 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
316 , video_server_process (0)
318 , have_configure_timeout (false)
319 , last_configure_time (0)
321 , have_disk_speed_dialog_displayed (false)
322 , _status_bar_visibility (X_("status-bar"))
323 , _feedback_exists (false)
324 , _log_not_acknowledged (LogLevelNone)
325 , duplicate_routes_dialog (0)
326 , editor_visibility_button (S_("Window|Editor"))
327 , mixer_visibility_button (S_("Window|Mixer"))
328 , prefs_visibility_button (S_("Window|Preferences"))
330 Gtkmm2ext::init (localedir);
332 UIConfiguration::instance().post_gui_init ();
334 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
336 /* "touch" the been-here-before path now that config has been migrated */
337 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
339 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
341 /* configuration was modified, exit immediately */
346 if (string (VERSIONSTRING).find (".pre") != string::npos) {
347 /* check this is not being run from ./ardev etc. */
348 if (!running_from_source_tree ()) {
349 pre_release_dialog ();
353 if (theArdourUI == 0) {
357 /* track main window visibility */
359 main_window_visibility = new VisibilityTracker (_main_window);
361 /* stop libxml from spewing to stdout/stderr */
363 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
364 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
366 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
367 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
368 UIConfiguration::instance().map_parameters (pc);
370 roll_button.set_controllable (roll_controllable);
371 stop_button.set_controllable (stop_controllable);
372 goto_start_button.set_controllable (goto_start_controllable);
373 goto_end_button.set_controllable (goto_end_controllable);
374 auto_loop_button.set_controllable (auto_loop_controllable);
375 play_selection_button.set_controllable (play_selection_controllable);
376 rec_button.set_controllable (rec_controllable);
378 roll_button.set_name ("transport button");
379 stop_button.set_name ("transport button");
380 goto_start_button.set_name ("transport button");
381 goto_end_button.set_name ("transport button");
382 auto_loop_button.set_name ("transport button");
383 play_selection_button.set_name ("transport button");
384 rec_button.set_name ("transport recenable button");
385 midi_panic_button.set_name ("transport button");
387 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
388 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
390 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
392 /* handle dialog requests */
394 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
396 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
398 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
400 /* handle Audio/MIDI setup when session requires it */
402 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
404 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
406 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
408 /* handle sr mismatch with a dialog - cross-thread from engine */
409 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
411 /* handle requests to quit (coming from JACK session) */
413 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
415 /* tell the user about feedback */
417 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
418 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
420 /* handle requests to deal with missing files */
422 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
424 /* and ambiguous files */
426 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
428 /* also plugin scan messages */
429 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
430 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
432 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
434 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
437 /* lets get this party started */
439 setup_gtk_ardour_enums ();
442 SessionEvent::create_per_thread_pool ("GUI", 4096);
444 /* we like keyboards */
446 keyboard = new ArdourKeyboard(*this);
448 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
450 keyboard->set_state (*node, Stateful::loading_state_version);
453 UIConfiguration::instance().reset_dpi ();
455 TimeAxisViewItem::set_constant_heights ();
457 /* Set this up so that our window proxies can register actions */
459 ActionManager::init ();
461 /* The following must happen after ARDOUR::init() so that Config is set up */
463 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
466 key_editor.set_state (*ui_xml, 0);
467 session_option_editor.set_state (*ui_xml, 0);
468 speaker_config_window.set_state (*ui_xml, 0);
469 about.set_state (*ui_xml, 0);
470 add_route_dialog.set_state (*ui_xml, 0);
471 add_video_dialog.set_state (*ui_xml, 0);
472 route_params.set_state (*ui_xml, 0);
473 bundle_manager.set_state (*ui_xml, 0);
474 location_ui.set_state (*ui_xml, 0);
475 big_clock_window.set_state (*ui_xml, 0);
476 audio_port_matrix.set_state (*ui_xml, 0);
477 midi_port_matrix.set_state (*ui_xml, 0);
478 export_video_dialog.set_state (*ui_xml, 0);
479 lua_script_window.set_state (*ui_xml, 0);
482 /* Separate windows */
484 WM::Manager::instance().register_window (&key_editor);
485 WM::Manager::instance().register_window (&session_option_editor);
486 WM::Manager::instance().register_window (&speaker_config_window);
487 WM::Manager::instance().register_window (&about);
488 WM::Manager::instance().register_window (&add_route_dialog);
489 WM::Manager::instance().register_window (&add_video_dialog);
490 WM::Manager::instance().register_window (&route_params);
491 WM::Manager::instance().register_window (&audio_midi_setup);
492 WM::Manager::instance().register_window (&export_video_dialog);
493 WM::Manager::instance().register_window (&lua_script_window);
494 WM::Manager::instance().register_window (&bundle_manager);
495 WM::Manager::instance().register_window (&location_ui);
496 WM::Manager::instance().register_window (&big_clock_window);
497 WM::Manager::instance().register_window (&audio_port_matrix);
498 WM::Manager::instance().register_window (&midi_port_matrix);
500 /* do not retain position for add route dialog */
501 add_route_dialog.set_state_mask (WindowProxy::Size);
503 /* Trigger setting up the color scheme and loading the GTK RC file */
505 UIConfiguration::instance().load_rc_file (false);
507 _process_thread = new ProcessThread ();
508 _process_thread->init ();
510 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
516 ARDOUR_UI::pre_release_dialog ()
518 ArdourDialog d (_("Pre-Release Warning"), true, false);
519 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
521 Label* label = manage (new Label);
522 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
523 There are still several issues and bugs to be worked on,\n\
524 as well as general workflow improvements, before this can be considered\n\
525 release software. So, a few guidelines:\n\
527 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
528 though it may be so, depending on your workflow.\n\
529 2) Please wait for a helpful writeup of new features.\n\
530 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
531 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
532 making sure to note the product version number as 5.0-pre.\n\
533 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
534 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
535 can get there directly from within the program via the Help->Chat menu option.\n\
537 Full information on all the above can be found on the support page at\n\
539 http://ardour.org/support\n\
540 "), PROGRAM_NAME, VERSIONSTRING));
542 d.get_vbox()->set_border_width (12);
543 d.get_vbox()->pack_start (*label, false, false, 12);
544 d.get_vbox()->show_all ();
549 GlobalPortMatrixWindow*
550 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
555 return new GlobalPortMatrixWindow (_session, type);
559 ARDOUR_UI::attach_to_engine ()
561 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
562 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
566 ARDOUR_UI::engine_stopped ()
568 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
569 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
570 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
571 update_sample_rate (0);
576 ARDOUR_UI::engine_running ()
578 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
579 if (first_time_engine_run) {
581 first_time_engine_run = false;
585 _session->reset_xrun_count ();
587 update_disk_space ();
589 update_xrun_count ();
590 update_sample_rate (AudioEngine::instance()->sample_rate());
591 update_timecode_format ();
592 update_peak_thread_work ();
593 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
594 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
598 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
600 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
601 /* we can't rely on the original string continuing to exist when we are called
602 again in the GUI thread, so make a copy and note that we need to
605 char *copy = strdup (reason);
606 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
610 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
611 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
613 update_sample_rate (0);
617 /* if the reason is a non-empty string, it means that the backend was shutdown
618 rather than just Ardour.
621 if (strlen (reason)) {
622 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
624 msgstr = string_compose (_("\
625 The audio backend has either been shutdown or it\n\
626 disconnected %1 because %1\n\
627 was not fast enough. Try to restart\n\
628 the audio backend and save the session."), PROGRAM_NAME);
631 MessageDialog msg (_main_window, msgstr);
632 pop_back_splash (msg);
636 free (const_cast<char*> (reason));
641 ARDOUR_UI::post_engine ()
643 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
645 #ifdef AUDIOUNIT_SUPPORT
647 if (AUPluginInfo::au_get_crashlog(au_msg)) {
648 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
649 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
650 info << au_msg << endmsg;
654 ARDOUR::init_post_engine ();
656 /* connect to important signals */
658 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
659 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
660 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
661 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
662 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
664 if (setup_windows ()) {
665 throw failed_constructor ();
668 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
669 XMLNode* n = Config->extra_xml (X_("UI"));
671 _status_bar_visibility.set_state (*n);
674 check_memory_locking();
676 /* this is the first point at which all the possible actions are
677 * available, because some of the available actions are dependent on
678 * aspects of the engine/backend.
681 if (ARDOUR_COMMAND_LINE::show_key_actions) {
684 vector<string> paths;
685 vector<string> labels;
686 vector<string> tooltips;
688 vector<Glib::RefPtr<Gtk::Action> > actions;
690 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
692 vector<string>::iterator k;
693 vector<string>::iterator p;
695 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
700 cout << *p << " => " << *k << endl;
704 halt_connection.disconnect ();
705 AudioEngine::instance()->stop ();
709 /* this being a GUI and all, we want peakfiles */
711 AudioFileSource::set_build_peakfiles (true);
712 AudioFileSource::set_build_missing_peakfiles (true);
714 /* set default clock modes */
716 primary_clock->set_mode (AudioClock::Timecode);
717 secondary_clock->set_mode (AudioClock::BBT);
719 /* start the time-of-day-clock */
722 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
723 update_wall_clock ();
724 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
729 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
730 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
731 Config->map_parameters (pc);
733 UIConfiguration::instance().map_parameters (pc);
737 ARDOUR_UI::~ARDOUR_UI ()
739 UIConfiguration::instance().save_state();
743 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
744 // don't bother at 'real' exit. the OS cleans up for us.
745 delete big_clock; big_clock = 0;
746 delete primary_clock; primary_clock = 0;
747 delete secondary_clock; secondary_clock = 0;
748 delete _process_thread; _process_thread = 0;
749 delete time_info_box; time_info_box = 0;
750 delete meterbridge; meterbridge = 0;
751 delete luawindow; luawindow = 0;
752 delete editor; editor = 0;
753 delete mixer; mixer = 0;
754 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
756 delete gui_object_state; gui_object_state = 0;
757 delete main_window_visibility;
758 FastMeter::flush_pattern_cache ();
759 PixFader::flush_pattern_cache ();
763 /* Small trick to flush main-thread event pool.
764 * Other thread-pools are destroyed at pthread_exit(),
765 * but tmain thread termination is too late to trigger Pool::~Pool()
767 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.
768 delete ev->event_pool();
773 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
775 if (Splash::instance()) {
776 Splash::instance()->pop_back_for (win);
781 ARDOUR_UI::configure_timeout ()
783 if (last_configure_time == 0) {
784 /* no configure events yet */
788 /* force a gap of 0.5 seconds since the last configure event
791 if (get_microseconds() - last_configure_time < 500000) {
794 have_configure_timeout = false;
795 save_ardour_state ();
801 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
803 if (have_configure_timeout) {
804 last_configure_time = get_microseconds();
806 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
807 have_configure_timeout = true;
814 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
816 XMLProperty const * prop;
818 if ((prop = node.property ("roll")) != 0) {
819 roll_controllable->set_id (prop->value());
821 if ((prop = node.property ("stop")) != 0) {
822 stop_controllable->set_id (prop->value());
824 if ((prop = node.property ("goto-start")) != 0) {
825 goto_start_controllable->set_id (prop->value());
827 if ((prop = node.property ("goto-end")) != 0) {
828 goto_end_controllable->set_id (prop->value());
830 if ((prop = node.property ("auto-loop")) != 0) {
831 auto_loop_controllable->set_id (prop->value());
833 if ((prop = node.property ("play-selection")) != 0) {
834 play_selection_controllable->set_id (prop->value());
836 if ((prop = node.property ("rec")) != 0) {
837 rec_controllable->set_id (prop->value());
839 if ((prop = node.property ("shuttle")) != 0) {
840 shuttle_box.controllable()->set_id (prop->value());
845 ARDOUR_UI::get_transport_controllable_state ()
847 XMLNode* node = new XMLNode(X_("TransportControllables"));
850 roll_controllable->id().print (buf, sizeof (buf));
851 node->add_property (X_("roll"), buf);
852 stop_controllable->id().print (buf, sizeof (buf));
853 node->add_property (X_("stop"), buf);
854 goto_start_controllable->id().print (buf, sizeof (buf));
855 node->add_property (X_("goto_start"), buf);
856 goto_end_controllable->id().print (buf, sizeof (buf));
857 node->add_property (X_("goto_end"), buf);
858 auto_loop_controllable->id().print (buf, sizeof (buf));
859 node->add_property (X_("auto_loop"), buf);
860 play_selection_controllable->id().print (buf, sizeof (buf));
861 node->add_property (X_("play_selection"), buf);
862 rec_controllable->id().print (buf, sizeof (buf));
863 node->add_property (X_("rec"), buf);
864 shuttle_box.controllable()->id().print (buf, sizeof (buf));
865 node->add_property (X_("shuttle"), buf);
871 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
874 _session->save_state (snapshot_name);
879 ARDOUR_UI::autosave_session ()
881 if (g_main_depth() > 1) {
882 /* inside a recursive main loop,
883 give up because we may not be able to
889 if (!Config->get_periodic_safety_backups()) {
894 _session->maybe_write_autosave();
901 ARDOUR_UI::session_dirty_changed ()
908 ARDOUR_UI::update_autosave ()
910 if (_session && _session->dirty()) {
911 if (_autosave_connection.connected()) {
912 _autosave_connection.disconnect();
915 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
916 Config->get_periodic_safety_backup_interval() * 1000);
919 if (_autosave_connection.connected()) {
920 _autosave_connection.disconnect();
926 ARDOUR_UI::check_announcements ()
929 string _annc_filename;
932 _annc_filename = PROGRAM_NAME "_announcements_osx_";
933 #elif defined PLATFORM_WINDOWS
934 _annc_filename = PROGRAM_NAME "_announcements_windows_";
936 _annc_filename = PROGRAM_NAME "_announcements_linux_";
938 _annc_filename.append (VERSIONSTRING);
940 _announce_string = "";
942 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
943 FILE* fin = g_fopen (path.c_str(), "rb");
945 while (!feof (fin)) {
948 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
951 _announce_string.append (tmp, len);
956 pingback (VERSIONSTRING, path);
961 _hide_splash (gpointer arg)
963 ((ARDOUR_UI*)arg)->hide_splash();
968 ARDOUR_UI::starting ()
970 Application* app = Application::instance ();
972 bool brand_new_user = ArdourStartup::required ();
974 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
975 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
977 if (ARDOUR_COMMAND_LINE::check_announcements) {
978 check_announcements ();
983 /* we need to create this early because it may need to set the
984 * audio backend end up.
988 audio_midi_setup.get (true);
990 std::cerr << "audio-midi engine setup failed."<< std::endl;
994 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
995 nsm = new NSM_Client;
996 if (!nsm->init (nsm_url)) {
997 /* the ardour executable may have different names:
999 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1000 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1001 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1003 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1005 const char *process_name = g_getenv ("ARDOUR_SELF");
1006 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1009 // wait for announce reply from nsm server
1010 for ( i = 0; i < 5000; ++i) {
1014 if (nsm->is_active()) {
1019 error << _("NSM server did not announce itself") << endmsg;
1022 // wait for open command from nsm server
1023 for ( i = 0; i < 5000; ++i) {
1025 Glib::usleep (1000);
1026 if (nsm->client_id ()) {
1032 error << _("NSM: no client ID provided") << endmsg;
1036 if (_session && nsm) {
1037 _session->set_nsm_state( nsm->is_active() );
1039 error << _("NSM: no session created") << endmsg;
1043 // nsm requires these actions disabled
1044 vector<string> action_names;
1045 action_names.push_back("SaveAs");
1046 action_names.push_back("Rename");
1047 action_names.push_back("New");
1048 action_names.push_back("Open");
1049 action_names.push_back("Recent");
1050 action_names.push_back("Close");
1052 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1053 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1055 act->set_sensitive (false);
1062 error << _("NSM: initialization failed") << endmsg;
1068 if (brand_new_user) {
1069 _initial_verbose_plugin_scan = true;
1074 _initial_verbose_plugin_scan = false;
1075 switch (s.response ()) {
1076 case Gtk::RESPONSE_OK:
1083 // TODO: maybe IFF brand_new_user
1084 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1085 std::string dspd (Config->get_default_session_parent_dir());
1086 Searchpath ds (ARDOUR::ardour_data_search_path());
1087 ds.add_subdirectory_to_paths ("sessions");
1088 vector<string> demos;
1089 find_files_matching_pattern (demos, ds, "*.tar.xz");
1091 ARDOUR::RecentSessions rs;
1092 ARDOUR::read_recent_sessions (rs);
1094 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1095 /* "demo-session" must be inside "demo-session.tar.xz"
1098 std::string name = basename_nosuffix (basename_nosuffix (*i));
1099 std::string path = Glib::build_filename (dspd, name);
1100 /* skip if session-dir already exists */
1101 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1104 /* skip sessions that are already in 'recent'.
1105 * eg. a new user changed <session-default-dir> shorly after installation
1107 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1108 if ((*r).first == name) {
1113 PBD::FileArchive ar (*i);
1114 if (0 == ar.inflate (dspd)) {
1115 store_recent_sessions (name, path);
1116 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1122 #ifdef NO_PLUGIN_STATE
1124 ARDOUR::RecentSessions rs;
1125 ARDOUR::read_recent_sessions (rs);
1127 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1129 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1131 /* already used Ardour, have sessions ... warn about plugin state */
1133 ArdourDialog d (_("Free/Demo Version Warning"), true);
1135 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1136 CheckButton c (_("Don't warn me about this again"));
1138 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"),
1139 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1140 _("It will not restore OR save any plugin settings"),
1141 _("If you load an existing session with plugin settings\n"
1142 "they will not be used and will be lost."),
1143 _("To get full access to updates without this limitation\n"
1144 "consider becoming a subscriber for a low cost every month.")));
1145 l.set_justify (JUSTIFY_CENTER);
1147 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1149 d.get_vbox()->pack_start (l, true, true);
1150 d.get_vbox()->pack_start (b, false, false, 12);
1151 d.get_vbox()->pack_start (c, false, false, 12);
1153 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1154 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1158 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1160 if (d.run () != RESPONSE_OK) {
1166 /* go get a session */
1168 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1170 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1171 std::cerr << "Cannot get session parameters."<< std::endl;
1178 WM::Manager::instance().show_visible ();
1180 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1181 * editor window, and we may want stuff to be hidden.
1183 _status_bar_visibility.update ();
1185 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1187 if (splash && splash->is_visible()) {
1188 // in 1 second, hide the splash screen
1189 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1192 /* all other dialogs are created conditionally */
1198 ARDOUR_UI::check_memory_locking ()
1200 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1201 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1205 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1207 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1209 struct rlimit limits;
1211 long pages, page_size;
1213 size_t pages_len=sizeof(pages);
1214 if ((page_size = getpagesize()) < 0 ||
1215 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1217 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1222 ram = (int64_t) pages * (int64_t) page_size;
1225 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1229 if (limits.rlim_cur != RLIM_INFINITY) {
1231 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1235 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1236 "This might cause %1 to run out of memory before your system "
1237 "runs out of memory. \n\n"
1238 "You can view the memory limit with 'ulimit -l', "
1239 "and it is normally controlled by %2"),
1242 X_("/etc/login.conf")
1244 X_(" /etc/security/limits.conf")
1248 msg.set_default_response (RESPONSE_OK);
1250 VBox* vbox = msg.get_vbox();
1252 CheckButton cb (_("Do not show this window again"));
1253 hbox.pack_start (cb, true, false);
1254 vbox->pack_start (hbox);
1259 pop_back_splash (msg);
1263 if (cb.get_active()) {
1264 XMLNode node (X_("no-memory-warning"));
1265 Config->add_instant_xml (node);
1270 #endif // !__APPLE__
1275 ARDOUR_UI::queue_finish ()
1277 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1281 ARDOUR_UI::idle_finish ()
1284 return false; /* do not call again */
1291 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1293 if (_session->dirty()) {
1294 vector<string> actions;
1295 actions.push_back (_("Don't quit"));
1296 actions.push_back (_("Just quit"));
1297 actions.push_back (_("Save and quit"));
1298 switch (ask_about_saving_session(actions)) {
1303 /* use the default name */
1304 if (save_state_canfail ("")) {
1305 /* failed - don't quit */
1306 MessageDialog msg (_main_window,
1307 string_compose (_("\
1308 %1 was unable to save your session.\n\n\
1309 If you still wish to quit, please use the\n\n\
1310 \"Just quit\" option."), PROGRAM_NAME));
1311 pop_back_splash(msg);
1321 second_connection.disconnect ();
1322 point_one_second_connection.disconnect ();
1323 point_zero_something_second_connection.disconnect();
1324 fps_connection.disconnect();
1327 delete ARDOUR_UI::instance()->video_timeline;
1328 ARDOUR_UI::instance()->video_timeline = NULL;
1329 stop_video_server();
1331 /* Save state before deleting the session, as that causes some
1332 windows to be destroyed before their visible state can be
1335 save_ardour_state ();
1337 if (key_editor.get (false)) {
1338 key_editor->disconnect ();
1341 close_all_dialogs ();
1344 _session->set_clean ();
1345 _session->remove_pending_capture_state ();
1350 halt_connection.disconnect ();
1351 AudioEngine::instance()->stop ();
1352 #ifdef WINDOWS_VST_SUPPORT
1353 fst_stop_threading();
1359 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1361 ArdourDialog window (_("Unsaved Session"));
1362 Gtk::HBox dhbox; // the hbox for the image and text
1363 Gtk::Label prompt_label;
1364 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1368 assert (actions.size() >= 3);
1370 window.add_button (actions[0], RESPONSE_REJECT);
1371 window.add_button (actions[1], RESPONSE_APPLY);
1372 window.add_button (actions[2], RESPONSE_ACCEPT);
1374 window.set_default_response (RESPONSE_ACCEPT);
1376 Gtk::Button noquit_button (msg);
1377 noquit_button.set_name ("EditorGTKButton");
1381 if (_session->snap_name() == _session->name()) {
1382 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?"),
1383 _session->snap_name());
1385 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?"),
1386 _session->snap_name());
1389 prompt_label.set_text (prompt);
1390 prompt_label.set_name (X_("PrompterLabel"));
1391 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1393 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1394 dhbox.set_homogeneous (false);
1395 dhbox.pack_start (*dimage, false, false, 5);
1396 dhbox.pack_start (prompt_label, true, false, 5);
1397 window.get_vbox()->pack_start (dhbox);
1399 window.set_name (_("Prompter"));
1400 window.set_modal (true);
1401 window.set_resizable (false);
1404 prompt_label.show();
1409 ResponseType r = (ResponseType) window.run();
1414 case RESPONSE_ACCEPT: // save and get out of here
1416 case RESPONSE_APPLY: // get out of here
1427 ARDOUR_UI::every_second ()
1430 update_xrun_count ();
1431 update_buffer_load ();
1432 update_disk_space ();
1433 update_timecode_format ();
1434 update_peak_thread_work ();
1436 if (nsm && nsm->is_active ()) {
1439 if (!_was_dirty && _session->dirty ()) {
1443 else if (_was_dirty && !_session->dirty ()){
1451 ARDOUR_UI::every_point_one_seconds ()
1453 // TODO get rid of this..
1454 // ShuttleControl is updated directly via TransportStateChange signal
1458 ARDOUR_UI::every_point_zero_something_seconds ()
1460 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1462 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1463 float mpeak = editor_meter->update_meters();
1464 if (mpeak > editor_meter_max_peak) {
1465 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1466 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1473 ARDOUR_UI::set_fps_timeout_connection ()
1475 unsigned int interval = 40;
1476 if (!_session) return;
1477 if (_session->timecode_frames_per_second() != 0) {
1478 /* ideally we'll use a select() to sleep and not accumulate
1479 * idle time to provide a regular periodic signal.
1480 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1481 * However, that'll require a dedicated thread and cross-thread
1482 * signals to the GUI Thread..
1484 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1485 * _session->frame_rate() / _session->nominal_frame_rate()
1486 / _session->timecode_frames_per_second()
1488 #ifdef PLATFORM_WINDOWS
1489 // the smallest windows scheduler time-slice is ~15ms.
1490 // periodic GUI timeouts shorter than that will cause
1491 // WaitForSingleObject to spinlock (100% of one CPU Core)
1492 // and gtk never enters idle mode.
1493 // also changing timeBeginPeriod(1) does not affect that in
1494 // any beneficial way, so we just limit the max rate for now.
1495 interval = std::max(30u, interval); // at most ~33Hz.
1497 interval = std::max(8u, interval); // at most 120Hz.
1500 fps_connection.disconnect();
1501 Timers::set_fps_interval (interval);
1505 ARDOUR_UI::update_sample_rate (framecnt_t)
1509 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1511 if (!AudioEngine::instance()->connected()) {
1513 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1517 framecnt_t rate = AudioEngine::instance()->sample_rate();
1520 /* no sample rate available */
1521 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1524 if (fmod (rate, 1000.0) != 0.0) {
1525 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1526 (float) rate / 1000.0f,
1527 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1529 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1531 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1535 sample_rate_label.set_markup (buf);
1539 ARDOUR_UI::update_format ()
1542 format_label.set_text ("");
1547 s << _("File:") << X_(" <span foreground=\"green\">");
1549 switch (_session->config.get_native_file_header_format ()) {
1581 switch (_session->config.get_native_file_data_format ()) {
1595 format_label.set_markup (s.str ());
1599 ARDOUR_UI::update_xrun_count ()
1603 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1604 should also be changed.
1608 const unsigned int x = _session->get_xrun_count ();
1610 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1612 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1615 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1617 xrun_label.set_markup (buf);
1618 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1622 ARDOUR_UI::update_cpu_load ()
1626 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1627 should also be changed.
1630 double const c = AudioEngine::instance()->get_dsp_load ();
1631 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1632 cpu_load_label.set_markup (buf);
1636 ARDOUR_UI::update_peak_thread_work ()
1639 const int c = SourceFactory::peak_work_queue_length ();
1641 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1642 peak_thread_work_label.set_markup (buf);
1644 peak_thread_work_label.set_markup (X_(""));
1649 ARDOUR_UI::update_buffer_load ()
1653 uint32_t const playback = _session ? _session->playback_load () : 100;
1654 uint32_t const capture = _session ? _session->capture_load () : 100;
1656 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1657 should also be changed.
1663 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1664 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1665 playback <= 5 ? X_("red") : X_("green"),
1667 capture <= 5 ? X_("red") : X_("green"),
1671 buffer_load_label.set_markup (buf);
1673 buffer_load_label.set_text ("");
1678 ARDOUR_UI::count_recenabled_streams (Route& route)
1680 Track* track = dynamic_cast<Track*>(&route);
1681 if (track && track->rec_enable_control()->get_value()) {
1682 rec_enabled_streams += track->n_inputs().n_total();
1687 ARDOUR_UI::update_disk_space()
1689 if (_session == 0) {
1693 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1695 framecnt_t fr = _session->frame_rate();
1698 /* skip update - no SR available */
1703 /* Available space is unknown */
1704 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1705 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1706 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1708 rec_enabled_streams = 0;
1709 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1711 framecnt_t frames = opt_frames.get_value_or (0);
1713 if (rec_enabled_streams) {
1714 frames /= rec_enabled_streams;
1721 hrs = frames / (fr * 3600);
1724 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1726 frames -= hrs * fr * 3600;
1727 mins = frames / (fr * 60);
1728 frames -= mins * fr * 60;
1731 bool const low = (hrs == 0 && mins <= 30);
1735 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1736 low ? X_("red") : X_("green"),
1742 disk_space_label.set_markup (buf);
1746 ARDOUR_UI::update_timecode_format ()
1752 TimecodeSlave* tcslave;
1753 SyncSource sync_src = Config->get_sync_source();
1755 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1756 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1761 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1762 matching ? X_("green") : X_("red"),
1763 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1765 snprintf (buf, sizeof (buf), "TC: n/a");
1768 timecode_format_label.set_markup (buf);
1772 ARDOUR_UI::update_wall_clock ()
1776 static int last_min = -1;
1779 tm_now = localtime (&now);
1780 if (last_min != tm_now->tm_min) {
1782 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1783 wall_clock_label.set_text (buf);
1784 last_min = tm_now->tm_min;
1791 ARDOUR_UI::open_recent_session ()
1793 bool can_return = (_session != 0);
1795 SessionDialog recent_session_dialog;
1799 ResponseType r = (ResponseType) recent_session_dialog.run ();
1802 case RESPONSE_ACCEPT:
1806 recent_session_dialog.hide();
1813 recent_session_dialog.hide();
1817 std::string path = recent_session_dialog.session_folder();
1818 std::string state = recent_session_dialog.session_name (should_be_new);
1820 if (should_be_new == true) {
1824 _session_is_new = false;
1826 if (load_session (path, state) == 0) {
1832 if (splash && splash->is_visible()) {
1833 // in 1 second, hide the splash screen
1834 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1839 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1841 if (!AudioEngine::instance()->connected()) {
1842 MessageDialog msg (parent, string_compose (
1843 _("%1 is not connected to any audio backend.\n"
1844 "You cannot open or close sessions in this condition"),
1846 pop_back_splash (msg);
1854 ARDOUR_UI::open_session ()
1856 if (!check_audioengine (_main_window)) {
1860 /* ardour sessions are folders */
1861 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1862 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1863 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1864 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1867 string session_parent_dir = Glib::path_get_dirname(_session->path());
1868 open_session_selector.set_current_folder(session_parent_dir);
1870 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1873 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1875 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1876 string default_session_folder = Config->get_default_session_parent_dir();
1877 open_session_selector.add_shortcut_folder (default_session_folder);
1879 catch (Glib::Error & e) {
1880 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1883 FileFilter session_filter;
1884 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1885 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1886 open_session_selector.add_filter (session_filter);
1888 FileFilter archive_filter;
1889 archive_filter.add_pattern (X_("*.tar.xz"));
1890 archive_filter.set_name (_("Session Archives"));
1892 open_session_selector.add_filter (archive_filter);
1894 open_session_selector.set_filter (session_filter);
1896 int response = open_session_selector.run();
1897 open_session_selector.hide ();
1899 if (response == Gtk::RESPONSE_CANCEL) {
1903 string session_path = open_session_selector.get_filename();
1907 if (session_path.length() > 0) {
1908 int rv = ARDOUR::inflate_session (session_path,
1909 Config->get_default_session_parent_dir(), path, name);
1911 _session_is_new = false;
1912 load_session (path, name);
1915 MessageDialog msg (_main_window,
1916 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1919 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1920 _session_is_new = isnew;
1921 load_session (path, name);
1927 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1933 _session->vca_manager().create_vca (n, name_template);
1937 ARDOUR_UI::session_add_mixed_track (
1938 const ChanCount& input,
1939 const ChanCount& output,
1940 RouteGroup* route_group,
1942 const string& name_template,
1944 PluginInfoPtr instrument,
1945 Plugin::PresetRecord* pset,
1946 ARDOUR::PresentationInfo::order_t order)
1948 if (_session == 0) {
1949 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1953 if (Profile->get_mixbus ()) {
1958 list<boost::shared_ptr<MidiTrack> > tracks;
1959 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1961 if (tracks.size() != how_many) {
1962 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1967 display_insufficient_ports_message ();
1973 ARDOUR_UI::session_add_midi_bus (
1974 RouteGroup* route_group,
1976 const string& name_template,
1978 PluginInfoPtr instrument,
1979 Plugin::PresetRecord* pset,
1980 ARDOUR::PresentationInfo::order_t order)
1982 if (_session == 0) {
1983 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1987 if (Profile->get_mixbus ()) {
1993 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
1994 if (routes.size() != how_many) {
1995 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2000 display_insufficient_ports_message ();
2006 ARDOUR_UI::session_add_midi_route (
2008 RouteGroup* route_group,
2010 const string& name_template,
2012 PluginInfoPtr instrument,
2013 Plugin::PresetRecord* pset,
2014 ARDOUR::PresentationInfo::order_t order)
2016 ChanCount one_midi_channel;
2017 one_midi_channel.set (DataType::MIDI, 1);
2020 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2022 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2027 ARDOUR_UI::session_add_audio_route (
2029 int32_t input_channels,
2030 int32_t output_channels,
2031 ARDOUR::TrackMode mode,
2032 RouteGroup* route_group,
2034 string const & name_template,
2036 ARDOUR::PresentationInfo::order_t order)
2038 list<boost::shared_ptr<AudioTrack> > tracks;
2041 if (_session == 0) {
2042 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2048 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2050 if (tracks.size() != how_many) {
2051 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2057 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2059 if (routes.size() != how_many) {
2060 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2067 display_insufficient_ports_message ();
2072 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2073 (*i)->set_strict_io (true);
2075 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2076 (*i)->set_strict_io (true);
2082 ARDOUR_UI::display_insufficient_ports_message ()
2084 MessageDialog msg (_main_window,
2085 string_compose (_("There are insufficient ports available\n\
2086 to create a new track or bus.\n\
2087 You should save %1, exit and\n\
2088 restart with more ports."), PROGRAM_NAME));
2089 pop_back_splash (msg);
2094 ARDOUR_UI::transport_goto_start ()
2097 _session->goto_start();
2099 /* force displayed area in editor to start no matter
2100 what "follow playhead" setting is.
2104 editor->center_screen (_session->current_start_frame ());
2110 ARDOUR_UI::transport_goto_zero ()
2113 _session->request_locate (0);
2115 /* force displayed area in editor to start no matter
2116 what "follow playhead" setting is.
2120 editor->reset_x_origin (0);
2126 ARDOUR_UI::transport_goto_wallclock ()
2128 if (_session && editor) {
2135 localtime_r (&now, &tmnow);
2137 framecnt_t frame_rate = _session->frame_rate();
2139 if (frame_rate == 0) {
2140 /* no frame rate available */
2144 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2145 frames += tmnow.tm_min * (60 * frame_rate);
2146 frames += tmnow.tm_sec * frame_rate;
2148 _session->request_locate (frames, _session->transport_rolling ());
2150 /* force displayed area in editor to start no matter
2151 what "follow playhead" setting is.
2155 editor->center_screen (frames);
2161 ARDOUR_UI::transport_goto_end ()
2164 framepos_t const frame = _session->current_end_frame();
2165 _session->request_locate (frame);
2167 /* force displayed area in editor to start no matter
2168 what "follow playhead" setting is.
2172 editor->center_screen (frame);
2178 ARDOUR_UI::transport_stop ()
2184 if (_session->is_auditioning()) {
2185 _session->cancel_audition ();
2189 _session->request_stop (false, true);
2192 /** Check if any tracks are record enabled. If none are, record enable all of them.
2193 * @return true if track record-enabled status was changed, false otherwise.
2196 ARDOUR_UI::trx_record_enable_all_tracks ()
2202 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2203 bool none_record_enabled = true;
2205 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2206 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2209 if (t->rec_enable_control()->get_value()) {
2210 none_record_enabled = false;
2215 if (none_record_enabled) {
2216 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2219 return none_record_enabled;
2223 ARDOUR_UI::transport_record (bool roll)
2226 switch (_session->record_status()) {
2227 case Session::Disabled:
2228 if (_session->ntracks() == 0) {
2229 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."));
2233 if (Profile->get_trx()) {
2234 roll = trx_record_enable_all_tracks ();
2236 _session->maybe_enable_record ();
2241 case Session::Recording:
2243 _session->request_stop();
2245 _session->disable_record (false, true);
2249 case Session::Enabled:
2250 _session->disable_record (false, true);
2256 ARDOUR_UI::transport_roll ()
2262 if (_session->is_auditioning()) {
2267 if (_session->config.get_external_sync()) {
2268 switch (Config->get_sync_source()) {
2272 /* transport controlled by the master */
2278 bool rolling = _session->transport_rolling();
2280 if (_session->get_play_loop()) {
2282 /* If loop playback is not a mode, then we should cancel
2283 it when this action is requested. If it is a mode
2284 we just leave it in place.
2287 if (!Config->get_loop_is_mode()) {
2288 /* XXX it is not possible to just leave seamless loop and keep
2289 playing at present (nov 4th 2009)
2291 if (!Config->get_seamless_loop()) {
2292 /* stop loop playback and stop rolling */
2293 _session->request_play_loop (false, true);
2294 } else if (rolling) {
2295 /* stop loop playback but keep rolling */
2296 _session->request_play_loop (false, false);
2300 } else if (_session->get_play_range () ) {
2301 /* stop playing a range if we currently are */
2302 _session->request_play_range (0, true);
2306 _session->request_transport_speed (1.0f);
2311 ARDOUR_UI::get_smart_mode() const
2313 return ( editor->get_smart_mode() );
2318 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2324 if (_session->is_auditioning()) {
2325 _session->cancel_audition ();
2329 if (_session->config.get_external_sync()) {
2330 switch (Config->get_sync_source()) {
2334 /* transport controlled by the master */
2339 bool rolling = _session->transport_rolling();
2340 bool affect_transport = true;
2342 if (rolling && roll_out_of_bounded_mode) {
2343 /* drop out of loop/range playback but leave transport rolling */
2344 if (_session->get_play_loop()) {
2345 if (_session->actively_recording()) {
2347 /* just stop using the loop, then actually stop
2350 _session->request_play_loop (false, affect_transport);
2353 if (Config->get_seamless_loop()) {
2354 /* the disk buffers contain copies of the loop - we can't
2355 just keep playing, so stop the transport. the user
2356 can restart as they wish.
2358 affect_transport = true;
2360 /* disk buffers are normal, so we can keep playing */
2361 affect_transport = false;
2363 _session->request_play_loop (false, affect_transport);
2365 } else if (_session->get_play_range ()) {
2366 affect_transport = false;
2367 _session->request_play_range (0, true);
2371 if (affect_transport) {
2373 _session->request_stop (with_abort, true);
2375 } else if (!with_abort) { /* with_abort == true means the
2376 * command was intended to stop
2377 * transport, not start.
2380 /* the only external sync condition we can be in here
2381 * would be Engine (JACK) sync, in which case we still
2385 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2386 _session->request_play_range (&editor->get_selection().time, true);
2387 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2389 _session->request_transport_speed (1.0f);
2395 ARDOUR_UI::toggle_session_auto_loop ()
2401 Location * looploc = _session->locations()->auto_loop_location();
2407 if (_session->get_play_loop()) {
2409 /* looping enabled, our job is to disable it */
2411 _session->request_play_loop (false);
2415 /* looping not enabled, our job is to enable it.
2417 loop-is-NOT-mode: this action always starts the transport rolling.
2418 loop-IS-mode: this action simply sets the loop play mechanism, but
2419 does not start transport.
2421 if (Config->get_loop_is_mode()) {
2422 _session->request_play_loop (true, false);
2424 _session->request_play_loop (true, true);
2428 //show the loop markers
2429 looploc->set_hidden (false, this);
2433 ARDOUR_UI::transport_play_selection ()
2439 editor->play_selection ();
2443 ARDOUR_UI::transport_play_preroll ()
2448 editor->play_with_preroll ();
2452 ARDOUR_UI::transport_rec_preroll ()
2457 editor->rec_with_preroll ();
2461 ARDOUR_UI::transport_rec_count_in ()
2466 editor->rec_with_count_in ();
2470 ARDOUR_UI::transport_rewind (int option)
2472 float current_transport_speed;
2475 current_transport_speed = _session->transport_speed();
2477 if (current_transport_speed >= 0.0f) {
2480 _session->request_transport_speed (-1.0f);
2483 _session->request_transport_speed (-4.0f);
2486 _session->request_transport_speed (-0.5f);
2491 _session->request_transport_speed (current_transport_speed * 1.5f);
2497 ARDOUR_UI::transport_forward (int option)
2503 float current_transport_speed = _session->transport_speed();
2505 if (current_transport_speed <= 0.0f) {
2508 _session->request_transport_speed (1.0f);
2511 _session->request_transport_speed (4.0f);
2514 _session->request_transport_speed (0.5f);
2519 _session->request_transport_speed (current_transport_speed * 1.5f);
2524 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2530 boost::shared_ptr<Route> r;
2532 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2534 boost::shared_ptr<Track> t;
2536 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2537 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2543 ARDOUR_UI::map_transport_state ()
2546 auto_loop_button.unset_active_state ();
2547 play_selection_button.unset_active_state ();
2548 roll_button.unset_active_state ();
2549 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2550 layered_button.set_sensitive (false);
2554 shuttle_box.map_transport_state ();
2556 float sp = _session->transport_speed();
2562 if (_session->get_play_range()) {
2564 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2565 roll_button.unset_active_state ();
2566 auto_loop_button.unset_active_state ();
2568 } else if (_session->get_play_loop ()) {
2570 auto_loop_button.set_active (true);
2571 play_selection_button.set_active (false);
2572 if (Config->get_loop_is_mode()) {
2573 roll_button.set_active (true);
2575 roll_button.set_active (false);
2580 roll_button.set_active (true);
2581 play_selection_button.set_active (false);
2582 auto_loop_button.set_active (false);
2585 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2586 /* light up both roll and play-selection if they are joined */
2587 roll_button.set_active (true);
2588 play_selection_button.set_active (true);
2590 layered_button.set_sensitive (!_session->actively_recording ());
2592 stop_button.set_active (false);
2596 layered_button.set_sensitive (true);
2597 stop_button.set_active (true);
2598 roll_button.set_active (false);
2599 play_selection_button.set_active (false);
2600 if (Config->get_loop_is_mode ()) {
2601 auto_loop_button.set_active (_session->get_play_loop());
2603 auto_loop_button.set_active (false);
2605 update_disk_space ();
2610 ARDOUR_UI::blink_handler (bool blink_on)
2612 transport_rec_enable_blink (blink_on);
2613 solo_blink (blink_on);
2614 sync_blink (blink_on);
2615 audition_blink (blink_on);
2616 feedback_blink (blink_on);
2617 error_blink (blink_on);
2621 ARDOUR_UI::update_clocks ()
2623 if (!_session) return;
2625 if (editor && !editor->dragging_playhead()) {
2626 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2631 ARDOUR_UI::start_clocking ()
2633 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2634 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2636 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2641 ARDOUR_UI::stop_clocking ()
2643 clock_signal_connection.disconnect ();
2647 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2651 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2653 label->set_text (buf);
2654 bar->set_fraction (fraction);
2656 /* process events, redraws, etc. */
2658 while (gtk_events_pending()) {
2659 gtk_main_iteration ();
2662 return true; /* continue with save-as */
2666 ARDOUR_UI::save_session_as ()
2672 if (!save_as_dialog) {
2673 save_as_dialog = new SaveAsDialog;
2676 save_as_dialog->set_name (_session->name());
2678 int response = save_as_dialog->run ();
2680 save_as_dialog->hide ();
2683 case Gtk::RESPONSE_OK:
2692 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2693 sa.new_name = save_as_dialog->new_name ();
2694 sa.switch_to = save_as_dialog->switch_to();
2695 sa.copy_media = save_as_dialog->copy_media();
2696 sa.copy_external = save_as_dialog->copy_external();
2697 sa.include_media = save_as_dialog->include_media ();
2699 /* Only bother with a progress dialog if we're going to copy
2700 media into the save-as target. Without that choice, this
2701 will be very fast because we're only talking about a few kB's to
2702 perhaps a couple of MB's of data.
2705 ArdourDialog progress_dialog (_("Save As"), true);
2707 if (sa.include_media && sa.copy_media) {
2710 Gtk::ProgressBar progress_bar;
2712 progress_dialog.get_vbox()->pack_start (label);
2713 progress_dialog.get_vbox()->pack_start (progress_bar);
2715 progress_bar.show ();
2717 /* this signal will be emitted from within this, the calling thread,
2718 * after every file is copied. It provides information on percentage
2719 * complete (in terms of total data to copy), the number of files
2720 * copied so far, and the total number to copy.
2725 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2727 progress_dialog.show_all ();
2728 progress_dialog.present ();
2731 if (_session->save_as (sa)) {
2733 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2737 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2738 * the trick is this: if the new session was copy with media included,
2739 * then Session::save_as() will have already done a neat trick to avoid
2740 * us having to unload and load the new state. But if the media was not
2741 * included, then this is required (it avoids us having to otherwise
2742 * drop all references to media (sources).
2745 if (!sa.include_media && sa.switch_to) {
2746 unload_session (false);
2747 load_session (sa.final_session_folder_name, sa.new_name);
2753 ARDOUR_UI::archive_session ()
2761 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2763 SessionArchiveDialog sad;
2764 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2765 int response = sad.run ();
2767 if (response != Gtk::RESPONSE_OK) {
2772 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2773 MessageDialog msg (_("Session Archiving failed."));
2779 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2783 struct tm local_time;
2786 localtime_r (&n, &local_time);
2787 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2789 save_state (timebuf, switch_to_it);
2794 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2798 prompter.get_result (snapname);
2800 bool do_save = (snapname.length() != 0);
2803 char illegal = Session::session_name_is_legal(snapname);
2805 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2806 "snapshot names may not contain a '%1' character"), illegal));
2812 vector<std::string> p;
2813 get_state_files_in_directory (_session->session_directory().root_path(), p);
2814 vector<string> n = get_file_names_no_extension (p);
2816 if (find (n.begin(), n.end(), snapname) != n.end()) {
2818 do_save = overwrite_file_dialog (prompter,
2819 _("Confirm Snapshot Overwrite"),
2820 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2824 save_state (snapname, switch_to_it);
2834 /** Ask the user for the name of a new snapshot and then take it.
2838 ARDOUR_UI::snapshot_session (bool switch_to_it)
2840 ArdourPrompter prompter (true);
2842 prompter.set_name ("Prompter");
2843 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2845 prompter.set_title (_("Snapshot and switch"));
2846 prompter.set_prompt (_("New session name"));
2848 prompter.set_title (_("Take Snapshot"));
2849 prompter.set_prompt (_("Name of new snapshot"));
2853 prompter.set_initial_text (_session->snap_name());
2855 Glib::DateTime tm (g_date_time_new_now_local ());
2856 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2859 bool finished = false;
2861 switch (prompter.run()) {
2862 case RESPONSE_ACCEPT:
2864 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2875 /** Ask the user for a new session name and then rename the session to it.
2879 ARDOUR_UI::rename_session ()
2885 ArdourPrompter prompter (true);
2888 prompter.set_name ("Prompter");
2889 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2890 prompter.set_title (_("Rename Session"));
2891 prompter.set_prompt (_("New session name"));
2894 switch (prompter.run()) {
2895 case RESPONSE_ACCEPT:
2897 prompter.get_result (name);
2899 bool do_rename = (name.length() != 0);
2902 char illegal = Session::session_name_is_legal (name);
2905 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2906 "session names may not contain a '%1' character"), illegal));
2911 switch (_session->rename (name)) {
2913 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2914 msg.set_position (WIN_POS_MOUSE);
2922 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2923 msg.set_position (WIN_POS_MOUSE);
2939 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2941 if (!_session || _session->deletion_in_progress()) {
2945 XMLNode* node = new XMLNode (X_("UI"));
2947 WM::Manager::instance().add_state (*node);
2949 node->add_child_nocopy (gui_object_state->get_state());
2951 _session->add_extra_xml (*node);
2953 if (export_video_dialog) {
2954 _session->add_extra_xml (export_video_dialog->get_state());
2957 save_state_canfail (name, switch_to_it);
2961 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2966 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2971 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2976 ARDOUR_UI::primary_clock_value_changed ()
2979 _session->request_locate (primary_clock->current_time ());
2984 ARDOUR_UI::big_clock_value_changed ()
2987 _session->request_locate (big_clock->current_time ());
2992 ARDOUR_UI::secondary_clock_value_changed ()
2995 _session->request_locate (secondary_clock->current_time ());
3000 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3002 if (_session == 0) {
3006 if (_session->step_editing()) {
3010 Session::RecordState const r = _session->record_status ();
3011 bool const h = _session->have_rec_enabled_track ();
3013 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3015 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3017 rec_button.set_active_state (Gtkmm2ext::Off);
3019 } else if (r == Session::Recording && h) {
3020 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3022 rec_button.unset_active_state ();
3027 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3031 prompter.get_result (name);
3033 if (name.length()) {
3034 int failed = _session->save_template (name);
3036 if (failed == -2) { /* file already exists. */
3037 bool overwrite = overwrite_file_dialog (prompter,
3038 _("Confirm Template Overwrite"),
3039 _("A template already exists with that name. Do you want to overwrite it?"));
3042 _session->save_template (name, true);
3054 ARDOUR_UI::save_template ()
3056 ArdourPrompter prompter (true);
3058 if (!check_audioengine (_main_window)) {
3062 prompter.set_name (X_("Prompter"));
3063 prompter.set_title (_("Save Template"));
3064 prompter.set_prompt (_("Name for template:"));
3065 prompter.set_initial_text(_session->name() + _("-template"));
3066 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3068 bool finished = false;
3070 switch (prompter.run()) {
3071 case RESPONSE_ACCEPT:
3072 finished = process_save_template_prompter (prompter);
3083 ARDOUR_UI::edit_metadata ()
3085 SessionMetadataEditor dialog;
3086 dialog.set_session (_session);
3087 dialog.grab_focus ();
3092 ARDOUR_UI::import_metadata ()
3094 SessionMetadataImporter dialog;
3095 dialog.set_session (_session);
3100 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3102 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3104 MessageDialog msg (str,
3106 Gtk::MESSAGE_WARNING,
3107 Gtk::BUTTONS_YES_NO,
3111 msg.set_name (X_("OpenExistingDialog"));
3112 msg.set_title (_("Open Existing Session"));
3113 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3114 msg.set_position (Gtk::WIN_POS_CENTER);
3115 pop_back_splash (msg);
3117 switch (msg.run()) {
3126 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3128 BusProfile bus_profile;
3132 bus_profile.master_out_channels = 2;
3133 bus_profile.input_ac = AutoConnectPhysical;
3134 bus_profile.output_ac = AutoConnectMaster;
3135 bus_profile.requested_physical_in = 0; // use all available
3136 bus_profile.requested_physical_out = 0; // use all available
3140 /* get settings from advanced section of NSD */
3142 if (sd.create_master_bus()) {
3143 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3145 bus_profile.master_out_channels = 0;
3148 if (sd.connect_inputs()) {
3149 bus_profile.input_ac = AutoConnectPhysical;
3151 bus_profile.input_ac = AutoConnectOption (0);
3154 bus_profile.output_ac = AutoConnectOption (0);
3156 if (sd.connect_outputs ()) {
3157 if (sd.connect_outs_to_master()) {
3158 bus_profile.output_ac = AutoConnectMaster;
3159 } else if (sd.connect_outs_to_physical()) {
3160 bus_profile.output_ac = AutoConnectPhysical;
3164 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3165 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3168 if (build_session (session_path, session_name, bus_profile)) {
3176 ARDOUR_UI::load_from_application_api (const std::string& path)
3178 /* OS X El Capitan (and probably later) now somehow passes the command
3179 line arguments to an app via the openFile delegate protocol. Ardour
3180 already does its own command line processing, and having both
3181 pathways active causes crashes. So, if the command line was already
3182 set, do nothing here.
3185 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3189 ARDOUR_COMMAND_LINE::session_name = path;
3191 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3193 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3195 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3196 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3197 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3198 * -> SessionDialog is not displayed
3201 if (_session_dialog) {
3202 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3203 std::string session_path = path;
3204 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3205 session_path = Glib::path_get_dirname (session_path);
3207 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3208 _session_dialog->set_provided_session (session_name, session_path);
3209 _session_dialog->response (RESPONSE_NONE);
3210 _session_dialog->hide();
3215 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3216 /* /path/to/foo => /path/to/foo, foo */
3217 rv = load_session (path, basename_nosuffix (path));
3219 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3220 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3223 // if load_session fails -> pop up SessionDialog.
3225 ARDOUR_COMMAND_LINE::session_name = "";
3227 if (get_session_parameters (true, false)) {
3233 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3235 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3237 string session_name;
3238 string session_path;
3239 string template_name;
3241 bool likely_new = false;
3242 bool cancel_not_quit;
3244 /* deal with any existing DIRTY session now, rather than later. don't
3245 * treat a non-dirty session this way, so that it stays visible
3246 * as we bring up the new session dialog.
3249 if (_session && ARDOUR_UI::instance()->video_timeline) {
3250 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3253 /* if there is already a session, relabel the button
3254 on the SessionDialog so that we don't Quit directly
3256 cancel_not_quit = (_session != 0);
3258 if (_session && _session->dirty()) {
3259 if (unload_session (false)) {
3260 /* unload cancelled by user */
3263 ARDOUR_COMMAND_LINE::session_name = "";
3266 if (!load_template.empty()) {
3267 should_be_new = true;
3268 template_name = load_template;
3271 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3272 session_path = ARDOUR_COMMAND_LINE::session_name;
3274 if (!session_path.empty()) {
3275 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3276 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3277 /* session/snapshot file, change path to be dir */
3278 session_path = Glib::path_get_dirname (session_path);
3283 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3285 _session_dialog = &session_dialog;
3288 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3290 /* if they named a specific statefile, use it, otherwise they are
3291 just giving a session folder, and we want to use it as is
3292 to find the session.
3295 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3297 if (suffix != string::npos) {
3298 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3299 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3300 session_name = Glib::path_get_basename (session_name);
3302 session_path = ARDOUR_COMMAND_LINE::session_name;
3303 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3308 session_dialog.clear_given ();
3311 if (should_be_new || session_name.empty()) {
3312 /* need the dialog to get info from user */
3314 cerr << "run dialog\n";
3316 switch (session_dialog.run()) {
3317 case RESPONSE_ACCEPT:
3320 /* this is used for async * app->ShouldLoad(). */
3321 continue; // while loop
3324 if (quit_on_cancel) {
3325 // JE - Currently (July 2014) this section can only get reached if the
3326 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3327 // point does NOT indicate an abnormal termination). Therefore, let's
3328 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3330 pthread_cancel_all ();
3338 session_dialog.hide ();
3341 /* if we run the startup dialog again, offer more than just "new session" */
3343 should_be_new = false;
3345 session_name = session_dialog.session_name (likely_new);
3346 session_path = session_dialog.session_folder ();
3353 int rv = ARDOUR::inflate_session (session_name,
3354 Config->get_default_session_parent_dir(), session_path, session_name);
3356 MessageDialog msg (session_dialog,
3357 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3362 session_dialog.set_provided_session (session_name, session_path);
3366 // XXX check archive, inflate
3367 string::size_type suffix = session_name.find (statefile_suffix);
3369 if (suffix != string::npos) {
3370 session_name = session_name.substr (0, suffix);
3373 /* this shouldn't happen, but we catch it just in case it does */
3375 if (session_name.empty()) {
3379 if (session_dialog.use_session_template()) {
3380 template_name = session_dialog.session_template_name();
3381 _session_is_new = true;
3384 if (session_name[0] == G_DIR_SEPARATOR ||
3385 #ifdef PLATFORM_WINDOWS
3386 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3388 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3389 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3394 /* absolute path or cwd-relative path specified for session name: infer session folder
3395 from what was given.
3398 session_path = Glib::path_get_dirname (session_name);
3399 session_name = Glib::path_get_basename (session_name);
3403 session_path = session_dialog.session_folder();
3405 char illegal = Session::session_name_is_legal (session_name);
3408 MessageDialog msg (session_dialog,
3409 string_compose (_("To ensure compatibility with various systems\n"
3410 "session names may not contain a '%1' character"),
3413 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3418 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3421 if (likely_new && !nsm) {
3423 std::string existing = Glib::build_filename (session_path, session_name);
3425 if (!ask_about_loading_existing_session (existing)) {
3426 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3431 _session_is_new = false;
3436 pop_back_splash (session_dialog);
3437 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3439 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3443 char illegal = Session::session_name_is_legal(session_name);
3446 pop_back_splash (session_dialog);
3447 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3448 "session names may not contain a '%1' character"), illegal));
3450 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3454 _session_is_new = true;
3457 if (likely_new && template_name.empty()) {
3459 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3463 ret = load_session (session_path, session_name, template_name);
3466 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3470 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3471 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3475 /* clear this to avoid endless attempts to load the
3479 ARDOUR_COMMAND_LINE::session_name = "";
3483 _session_dialog = NULL;
3489 ARDOUR_UI::close_session()
3491 if (!check_audioengine (_main_window)) {
3495 if (unload_session (true)) {
3499 ARDOUR_COMMAND_LINE::session_name = "";
3501 if (get_session_parameters (true, false)) {
3504 if (splash && splash->is_visible()) {
3505 // in 1 second, hide the splash screen
3506 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3510 /** @param snap_name Snapshot name (without .ardour suffix).
3511 * @return -2 if the load failed because we are not connected to the AudioEngine.
3514 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3516 Session *new_session;
3521 unload_status = unload_session ();
3523 if (unload_status < 0) {
3525 } else if (unload_status > 0) {
3531 session_loaded = false;
3533 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3536 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3539 /* this one is special */
3541 catch (AudioEngine::PortRegistrationFailure& err) {
3543 MessageDialog msg (err.what(),
3546 Gtk::BUTTONS_CLOSE);
3548 msg.set_title (_("Port Registration Error"));
3549 msg.set_secondary_text (_("Click the Close button to try again."));
3550 msg.set_position (Gtk::WIN_POS_CENTER);
3551 pop_back_splash (msg);
3554 int response = msg.run ();
3559 case RESPONSE_CANCEL:
3566 catch (SessionException e) {
3567 MessageDialog msg (string_compose(
3568 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3569 path, snap_name, e.what()),
3574 msg.set_title (_("Loading Error"));
3575 msg.set_position (Gtk::WIN_POS_CENTER);
3576 pop_back_splash (msg);
3588 MessageDialog msg (string_compose(
3589 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3595 msg.set_title (_("Loading Error"));
3596 msg.set_position (Gtk::WIN_POS_CENTER);
3597 pop_back_splash (msg);
3609 list<string> const u = new_session->unknown_processors ();
3611 MissingPluginDialog d (_session, u);
3616 if (!new_session->writable()) {
3617 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3622 msg.set_title (_("Read-only Session"));
3623 msg.set_position (Gtk::WIN_POS_CENTER);
3624 pop_back_splash (msg);
3631 /* Now the session been created, add the transport controls */
3632 new_session->add_controllable(roll_controllable);
3633 new_session->add_controllable(stop_controllable);
3634 new_session->add_controllable(goto_start_controllable);
3635 new_session->add_controllable(goto_end_controllable);
3636 new_session->add_controllable(auto_loop_controllable);
3637 new_session->add_controllable(play_selection_controllable);
3638 new_session->add_controllable(rec_controllable);
3640 set_session (new_session);
3642 session_loaded = true;
3645 _session->set_clean ();
3648 #ifdef WINDOWS_VST_SUPPORT
3649 fst_stop_threading();
3653 Timers::TimerSuspender t;
3657 #ifdef WINDOWS_VST_SUPPORT
3658 fst_start_threading();
3667 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3669 Session *new_session;
3672 session_loaded = false;
3673 x = unload_session ();
3681 _session_is_new = true;
3684 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3687 catch (SessionException e) {
3688 cerr << "Here are the errors associated with this failed session:\n";
3690 cerr << "---------\n";
3691 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3692 msg.set_title (_("Loading Error"));
3693 msg.set_position (Gtk::WIN_POS_CENTER);
3694 pop_back_splash (msg);
3699 cerr << "Here are the errors associated with this failed session:\n";
3701 cerr << "---------\n";
3702 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3703 msg.set_title (_("Loading Error"));
3704 msg.set_position (Gtk::WIN_POS_CENTER);
3705 pop_back_splash (msg);
3710 /* Give the new session the default GUI state, if such things exist */
3713 n = Config->instant_xml (X_("Editor"));
3715 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3716 new_session->add_instant_xml (*n, false);
3718 n = Config->instant_xml (X_("Mixer"));
3720 new_session->add_instant_xml (*n, false);
3723 n = Config->instant_xml (X_("Preferences"));
3725 new_session->add_instant_xml (*n, false);
3728 /* Put the playhead at 0 and scroll fully left */
3729 n = new_session->instant_xml (X_("Editor"));
3731 n->add_property (X_("playhead"), X_("0"));
3732 n->add_property (X_("left-frame"), X_("0"));
3735 set_session (new_session);
3737 session_loaded = true;
3739 new_session->save_state(new_session->name());
3745 ARDOUR_UI::launch_chat ()
3747 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3749 dialog.set_title (_("About the Chat"));
3750 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."));
3752 switch (dialog.run()) {
3755 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3756 #elif defined PLATFORM_WINDOWS
3757 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3759 open_uri("http://webchat.freenode.net/?channels=ardour");
3768 ARDOUR_UI::launch_manual ()
3770 PBD::open_uri (Config->get_tutorial_manual_url());
3774 ARDOUR_UI::launch_reference ()
3776 PBD::open_uri (Config->get_reference_manual_url());
3780 ARDOUR_UI::launch_tracker ()
3782 PBD::open_uri ("http://tracker.ardour.org");
3786 ARDOUR_UI::launch_subscribe ()
3788 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3792 ARDOUR_UI::launch_cheat_sheet ()
3795 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3797 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3802 ARDOUR_UI::launch_website ()
3804 PBD::open_uri ("http://ardour.org");
3808 ARDOUR_UI::launch_website_dev ()
3810 PBD::open_uri ("http://ardour.org/development.html");
3814 ARDOUR_UI::launch_forums ()
3816 PBD::open_uri ("https://community.ardour.org/forums");
3820 ARDOUR_UI::launch_howto_report ()
3822 PBD::open_uri ("http://ardour.org/reporting_bugs");
3826 ARDOUR_UI::loading_message (const std::string& msg)
3828 if (ARDOUR_COMMAND_LINE::no_splash) {
3836 splash->message (msg);
3840 ARDOUR_UI::show_splash ()
3844 splash = new Splash;
3854 ARDOUR_UI::hide_splash ()
3861 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3865 removed = rep.paths.size();
3868 MessageDialog msgd (_main_window,
3869 _("No files were ready for clean-up"),
3873 msgd.set_title (_("Clean-up"));
3874 msgd.set_secondary_text (_("If this seems suprising, \n\
3875 check for any existing snapshots.\n\
3876 These may still include regions that\n\
3877 require some unused files to continue to exist."));
3883 ArdourDialog results (_("Clean-up"), true, false);
3885 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3886 CleanupResultsModelColumns() {
3890 Gtk::TreeModelColumn<std::string> visible_name;
3891 Gtk::TreeModelColumn<std::string> fullpath;
3895 CleanupResultsModelColumns results_columns;
3896 Glib::RefPtr<Gtk::ListStore> results_model;
3897 Gtk::TreeView results_display;
3899 results_model = ListStore::create (results_columns);
3900 results_display.set_model (results_model);
3901 results_display.append_column (list_title, results_columns.visible_name);
3903 results_display.set_name ("CleanupResultsList");
3904 results_display.set_headers_visible (true);
3905 results_display.set_headers_clickable (false);
3906 results_display.set_reorderable (false);
3908 Gtk::ScrolledWindow list_scroller;
3911 Gtk::HBox dhbox; // the hbox for the image and text
3912 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3913 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3915 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3917 const string dead_directory = _session->session_directory().dead_path();
3920 %1 - number of files removed
3921 %2 - location of "dead"
3922 %3 - size of files affected
3923 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3926 const char* bprefix;
3927 double space_adjusted = 0;
3929 if (rep.space < 1000) {
3931 space_adjusted = rep.space;
3932 } else if (rep.space < 1000000) {
3933 bprefix = _("kilo");
3934 space_adjusted = floorf((float)rep.space / 1000.0);
3935 } else if (rep.space < 1000000 * 1000) {
3936 bprefix = _("mega");
3937 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3939 bprefix = _("giga");
3940 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3944 txt.set_markup (string_compose (P_("\
3945 The following file was deleted from %2,\n\
3946 releasing %3 %4bytes of disk space", "\
3947 The following %1 files were deleted from %2,\n\
3948 releasing %3 %4bytes of disk space", removed),
3949 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3951 txt.set_markup (string_compose (P_("\
3952 The following file was not in use and \n\
3953 has been moved to: %2\n\n\
3954 After a restart of %5\n\n\
3955 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3956 will release an additional %3 %4bytes of disk space.\n", "\
3957 The following %1 files were not in use and \n\
3958 have been moved to: %2\n\n\
3959 After a restart of %5\n\n\
3960 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3961 will release an additional %3 %4bytes of disk space.\n", removed),
3962 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3965 dhbox.pack_start (*dimage, true, false, 5);
3966 dhbox.pack_start (txt, true, false, 5);
3968 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3969 TreeModel::Row row = *(results_model->append());
3970 row[results_columns.visible_name] = *i;
3971 row[results_columns.fullpath] = *i;
3974 list_scroller.add (results_display);
3975 list_scroller.set_size_request (-1, 150);
3976 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3978 dvbox.pack_start (dhbox, true, false, 5);
3979 dvbox.pack_start (list_scroller, true, false, 5);
3980 ddhbox.pack_start (dvbox, true, false, 5);
3982 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3983 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3984 results.set_default_response (RESPONSE_CLOSE);
3985 results.set_position (Gtk::WIN_POS_MOUSE);
3987 results_display.show();
3988 list_scroller.show();
3995 //results.get_vbox()->show();
3996 results.set_resizable (false);
4003 ARDOUR_UI::cleanup ()
4005 if (_session == 0) {
4006 /* shouldn't happen: menu item is insensitive */
4011 MessageDialog checker (_("Are you sure you want to clean-up?"),
4013 Gtk::MESSAGE_QUESTION,
4016 checker.set_title (_("Clean-up"));
4018 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4019 ALL undo/redo information will be lost if you clean-up.\n\
4020 Clean-up will move all unused files to a \"dead\" location."));
4022 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4023 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4024 checker.set_default_response (RESPONSE_CANCEL);
4026 checker.set_name (_("CleanupDialog"));
4027 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4028 checker.set_position (Gtk::WIN_POS_MOUSE);
4030 switch (checker.run()) {
4031 case RESPONSE_ACCEPT:
4037 ARDOUR::CleanupReport rep;
4039 editor->prepare_for_cleanup ();
4041 /* do not allow flush until a session is reloaded */
4043 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4045 act->set_sensitive (false);
4048 if (_session->cleanup_sources (rep)) {
4049 editor->finish_cleanup ();
4053 editor->finish_cleanup ();
4056 display_cleanup_results (rep, _("Cleaned Files"), false);
4060 ARDOUR_UI::flush_trash ()
4062 if (_session == 0) {
4063 /* shouldn't happen: menu item is insensitive */
4067 ARDOUR::CleanupReport rep;
4069 if (_session->cleanup_trash_sources (rep)) {
4073 display_cleanup_results (rep, _("deleted file"), true);
4077 ARDOUR_UI::cleanup_peakfiles ()
4079 if (_session == 0) {
4080 /* shouldn't happen: menu item is insensitive */
4084 if (! _session->can_cleanup_peakfiles ()) {
4088 // get all region-views in this session
4090 TrackViewList empty;
4092 editor->get_regions_after(rs, (framepos_t) 0, empty);
4093 std::list<RegionView*> views = rs.by_layer();
4095 // remove displayed audio-region-views waveforms
4096 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4097 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4098 if (!arv) { continue ; }
4099 arv->delete_waves();
4102 // cleanup peak files:
4103 // - stop pending peakfile threads
4104 // - close peakfiles if any
4105 // - remove peak dir in session
4106 // - setup peakfiles (background thread)
4107 _session->cleanup_peakfiles ();
4109 // re-add waves to ARV
4110 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4111 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4112 if (!arv) { continue ; }
4113 arv->create_waves();
4117 PresentationInfo::order_t
4118 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4120 if (editor->get_selection().tracks.empty()) {
4121 return PresentationInfo::max_order;
4124 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4127 we want the new routes to have their order keys set starting from
4128 the highest order key in the selection + 1 (if available).
4131 if (place == RouteDialogs::AfterSelection) {
4132 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4134 order_hint = rtav->route()->presentation_info().order();
4137 } else if (place == RouteDialogs::BeforeSelection) {
4138 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4140 order_hint = rtav->route()->presentation_info().order();
4142 } else if (place == RouteDialogs::First) {
4145 /* leave order_hint at max_order */
4152 ARDOUR_UI::start_duplicate_routes ()
4154 if (!duplicate_routes_dialog) {
4155 duplicate_routes_dialog = new DuplicateRouteDialog;
4158 if (duplicate_routes_dialog->restart (_session)) {
4162 duplicate_routes_dialog->present ();
4166 ARDOUR_UI::add_route ()
4168 if (!add_route_dialog.get (false)) {
4169 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4176 if (add_route_dialog->is_visible()) {
4177 /* we're already doing this */
4181 add_route_dialog->set_position (WIN_POS_MOUSE);
4182 add_route_dialog->present();
4186 ARDOUR_UI::add_route_dialog_finished (int r)
4190 add_route_dialog->hide();
4193 case RESPONSE_ACCEPT:
4200 if ((count = add_route_dialog->count()) <= 0) {
4204 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4205 string template_path = add_route_dialog->track_template();
4206 DisplaySuspender ds;
4208 if (!template_path.empty()) {
4209 if (add_route_dialog->name_template_is_default()) {
4210 _session->new_route_from_template (count, order, template_path, string());
4212 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4217 ChanCount input_chan= add_route_dialog->channels ();
4218 ChanCount output_chan;
4219 string name_template = add_route_dialog->name_template ();
4220 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4221 RouteGroup* route_group = add_route_dialog->route_group ();
4222 AutoConnectOption oac = Config->get_output_auto_connect();
4223 bool strict_io = add_route_dialog->use_strict_io ();
4225 if (oac & AutoConnectMaster) {
4226 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4227 output_chan.set (DataType::MIDI, 0);
4229 output_chan = input_chan;
4232 /* XXX do something with name template */
4234 Session::ProcessorChangeBlocker pcb (_session);
4236 switch (add_route_dialog->type_wanted()) {
4237 case AddRouteDialog::AudioTrack:
4238 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4240 case AddRouteDialog::MidiTrack:
4241 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4243 case AddRouteDialog::MixedTrack:
4244 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4246 case AddRouteDialog::AudioBus:
4247 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4249 case AddRouteDialog::MidiBus:
4250 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4252 case AddRouteDialog::VCAMaster:
4253 session_add_vca (name_template, count);
4259 ARDOUR_UI::stop_video_server (bool ask_confirm)
4261 if (!video_server_process && ask_confirm) {
4262 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4264 if (video_server_process) {
4266 ArdourDialog confirm (_("Stop Video-Server"), true);
4267 Label m (_("Do you really want to stop the Video Server?"));
4268 confirm.get_vbox()->pack_start (m, true, true);
4269 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4270 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4271 confirm.show_all ();
4272 if (confirm.run() == RESPONSE_CANCEL) {
4276 delete video_server_process;
4277 video_server_process =0;
4282 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4284 ARDOUR_UI::start_video_server( float_window, true);
4288 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4294 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4295 if (video_server_process) {
4296 popup_error(_("The Video Server is already started."));
4298 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4304 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4306 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4308 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4310 video_server_dialog->set_transient_for (*float_window);
4313 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4314 video_server_dialog->hide();
4316 ResponseType r = (ResponseType) video_server_dialog->run ();
4317 video_server_dialog->hide();
4318 if (r != RESPONSE_ACCEPT) { return false; }
4319 if (video_server_dialog->show_again()) {
4320 Config->set_show_video_server_dialog(false);
4324 std::string icsd_exec = video_server_dialog->get_exec_path();
4325 std::string icsd_docroot = video_server_dialog->get_docroot();
4326 #ifndef PLATFORM_WINDOWS
4327 if (icsd_docroot.empty()) {
4328 icsd_docroot = VideoUtils::video_get_docroot (Config);
4333 #ifdef PLATFORM_WINDOWS
4334 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4335 /* OK, allow all drive letters */
4338 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4339 warning << _("Specified docroot is not an existing directory.") << endmsg;
4342 #ifndef PLATFORM_WINDOWS
4343 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4344 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4345 warning << _("Given Video Server is not an executable file.") << endmsg;
4349 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4350 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4351 warning << _("Given Video Server is not an executable file.") << endmsg;
4357 argp=(char**) calloc(9,sizeof(char*));
4358 argp[0] = strdup(icsd_exec.c_str());
4359 argp[1] = strdup("-P");
4360 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4361 argp[3] = strdup("-p");
4362 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4363 argp[5] = strdup("-C");
4364 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4365 argp[7] = strdup(icsd_docroot.c_str());
4367 stop_video_server();
4369 #ifdef PLATFORM_WINDOWS
4370 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4371 /* OK, allow all drive letters */
4374 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4375 Config->set_video_advanced_setup(false);
4377 std::ostringstream osstream;
4378 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4379 Config->set_video_server_url(osstream.str());
4380 Config->set_video_server_docroot(icsd_docroot);
4381 Config->set_video_advanced_setup(true);
4384 if (video_server_process) {
4385 delete video_server_process;
4388 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4389 if (video_server_process->start()) {
4390 warning << _("Cannot launch the video-server") << endmsg;
4393 int timeout = 120; // 6 sec
4394 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4395 Glib::usleep (50000);
4397 if (--timeout <= 0 || !video_server_process->is_running()) break;
4400 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4402 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4403 delete video_server_process;
4404 video_server_process = 0;
4412 ARDOUR_UI::add_video (Gtk::Window* float_window)
4418 if (!start_video_server(float_window, false)) {
4419 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4424 add_video_dialog->set_transient_for (*float_window);
4427 if (add_video_dialog->is_visible()) {
4428 /* we're already doing this */
4432 ResponseType r = (ResponseType) add_video_dialog->run ();
4433 add_video_dialog->hide();
4434 if (r != RESPONSE_ACCEPT) { return; }
4436 bool local_file, orig_local_file;
4437 std::string path = add_video_dialog->file_name(local_file);
4439 std::string orig_path = path;
4440 orig_local_file = local_file;
4442 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4444 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4445 warning << string_compose(_("could not open %1"), path) << endmsg;
4448 if (!local_file && path.length() == 0) {
4449 warning << _("no video-file selected") << endmsg;
4453 std::string audio_from_video;
4454 bool detect_ltc = false;
4456 switch (add_video_dialog->import_option()) {
4457 case VTL_IMPORT_TRANSCODE:
4459 TranscodeVideoDialog *transcode_video_dialog;
4460 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4461 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4462 transcode_video_dialog->hide();
4463 if (r != RESPONSE_ACCEPT) {
4464 delete transcode_video_dialog;
4468 audio_from_video = transcode_video_dialog->get_audiofile();
4470 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4473 else if (!audio_from_video.empty()) {
4474 editor->embed_audio_from_video(
4476 video_timeline->get_offset(),
4477 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4480 switch (transcode_video_dialog->import_option()) {
4481 case VTL_IMPORT_TRANSCODED:
4482 path = transcode_video_dialog->get_filename();
4485 case VTL_IMPORT_REFERENCE:
4488 delete transcode_video_dialog;
4491 delete transcode_video_dialog;
4495 case VTL_IMPORT_NONE:
4499 /* strip _session->session_directory().video_path() from video file if possible */
4500 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4501 path=path.substr(_session->session_directory().video_path().size());
4502 if (path.at(0) == G_DIR_SEPARATOR) {
4503 path=path.substr(1);
4507 video_timeline->set_update_session_fps(auto_set_session_fps);
4509 if (video_timeline->video_file_info(path, local_file)) {
4510 XMLNode* node = new XMLNode(X_("Videotimeline"));
4511 node->add_property (X_("Filename"), path);
4512 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4513 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4514 if (orig_local_file) {
4515 node->add_property (X_("OriginalVideoFile"), orig_path);
4517 node->remove_property (X_("OriginalVideoFile"));
4519 _session->add_extra_xml (*node);
4520 _session->set_dirty ();
4522 if (!audio_from_video.empty() && detect_ltc) {
4523 std::vector<LTCFileReader::LTCMap> ltc_seq;
4526 /* TODO ask user about TV standard (LTC alignment if any) */
4527 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4528 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4530 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4532 /* TODO seek near end of file, and read LTC until end.
4533 * if it fails to find any LTC frames, scan complete file
4535 * calculate drift of LTC compared to video-duration,
4536 * ask user for reference (timecode from start/mid/end)
4539 // LTCFileReader will have written error messages
4542 ::g_unlink(audio_from_video.c_str());
4544 if (ltc_seq.size() == 0) {
4545 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4547 /* the very first TC in the file is somteimes not aligned properly */
4548 int i = ltc_seq.size() -1;
4549 ARDOUR::frameoffset_t video_start_offset =
4550 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4551 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4552 video_timeline->set_offset(video_start_offset);
4556 _session->maybe_update_session_range(
4557 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4558 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4561 if (add_video_dialog->launch_xjadeo() && local_file) {
4562 editor->set_xjadeo_sensitive(true);
4563 editor->toggle_xjadeo_proc(1);
4565 editor->toggle_xjadeo_proc(0);
4567 editor->toggle_ruler_video(true);
4572 ARDOUR_UI::remove_video ()
4574 video_timeline->close_session();
4575 editor->toggle_ruler_video(false);
4578 video_timeline->set_offset_locked(false);
4579 video_timeline->set_offset(0);
4581 /* delete session state */
4582 XMLNode* node = new XMLNode(X_("Videotimeline"));
4583 _session->add_extra_xml(*node);
4584 node = new XMLNode(X_("Videomonitor"));
4585 _session->add_extra_xml(*node);
4586 node = new XMLNode(X_("Videoexport"));
4587 _session->add_extra_xml(*node);
4588 stop_video_server();
4592 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4594 if (localcacheonly) {
4595 video_timeline->vmon_update();
4597 video_timeline->flush_cache();
4599 editor->queue_visual_videotimeline_update();
4603 ARDOUR_UI::export_video (bool range)
4605 if (ARDOUR::Config->get_show_video_export_info()) {
4606 ExportVideoInfobox infobox (_session);
4607 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4608 if (infobox.show_again()) {
4609 ARDOUR::Config->set_show_video_export_info(false);
4612 case GTK_RESPONSE_YES:
4613 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4619 export_video_dialog->set_session (_session);
4620 export_video_dialog->apply_state(editor->get_selection().time, range);
4621 export_video_dialog->run ();
4622 export_video_dialog->hide ();
4626 ARDOUR_UI::preferences_settings () const
4631 node = _session->instant_xml(X_("Preferences"));
4633 node = Config->instant_xml(X_("Preferences"));
4637 node = new XMLNode (X_("Preferences"));
4644 ARDOUR_UI::mixer_settings () const
4649 node = _session->instant_xml(X_("Mixer"));
4651 node = Config->instant_xml(X_("Mixer"));
4655 node = new XMLNode (X_("Mixer"));
4662 ARDOUR_UI::main_window_settings () const
4667 node = _session->instant_xml(X_("Main"));
4669 node = Config->instant_xml(X_("Main"));
4673 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4674 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4679 node = new XMLNode (X_("Main"));
4686 ARDOUR_UI::editor_settings () const
4691 node = _session->instant_xml(X_("Editor"));
4693 node = Config->instant_xml(X_("Editor"));
4697 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4698 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4703 node = new XMLNode (X_("Editor"));
4710 ARDOUR_UI::keyboard_settings () const
4714 node = Config->extra_xml(X_("Keyboard"));
4717 node = new XMLNode (X_("Keyboard"));
4724 ARDOUR_UI::create_xrun_marker (framepos_t where)
4727 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4728 _session->locations()->add (location);
4733 ARDOUR_UI::halt_on_xrun_message ()
4735 cerr << "HALT on xrun\n";
4736 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4741 ARDOUR_UI::xrun_handler (framepos_t where)
4747 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4749 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4750 create_xrun_marker(where);
4753 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4754 halt_on_xrun_message ();
4759 ARDOUR_UI::disk_overrun_handler ()
4761 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4763 if (!have_disk_speed_dialog_displayed) {
4764 have_disk_speed_dialog_displayed = true;
4765 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4766 The disk system on your computer\n\
4767 was not able to keep up with %1.\n\
4769 Specifically, it failed to write data to disk\n\
4770 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4771 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4777 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4778 static MessageDialog *scan_dlg = NULL;
4779 static ProgressBar *scan_pbar = NULL;
4780 static HBox *scan_tbox = NULL;
4781 static Gtk::Button *scan_timeout_button;
4784 ARDOUR_UI::cancel_plugin_scan ()
4786 PluginManager::instance().cancel_plugin_scan();
4790 ARDOUR_UI::cancel_plugin_timeout ()
4792 PluginManager::instance().cancel_plugin_timeout();
4793 scan_timeout_button->set_sensitive (false);
4797 ARDOUR_UI::plugin_scan_timeout (int timeout)
4799 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4803 scan_pbar->set_sensitive (false);
4804 scan_timeout_button->set_sensitive (true);
4805 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4808 scan_pbar->set_sensitive (false);
4809 scan_timeout_button->set_sensitive (false);
4815 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4817 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4821 const bool cancelled = PluginManager::instance().cancelled();
4822 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4823 if (cancelled && scan_dlg->is_mapped()) {
4828 if (cancelled || !can_cancel) {
4833 static Gtk::Button *cancel_button;
4835 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4836 VBox* vbox = scan_dlg->get_vbox();
4837 vbox->set_size_request(400,-1);
4838 scan_dlg->set_title (_("Scanning for plugins"));
4840 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4841 cancel_button->set_name ("EditorGTKButton");
4842 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4843 cancel_button->show();
4845 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4847 scan_tbox = manage( new HBox() );
4849 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4850 scan_timeout_button->set_name ("EditorGTKButton");
4851 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4852 scan_timeout_button->show();
4854 scan_pbar = manage(new ProgressBar());
4855 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4856 scan_pbar->set_text(_("Scan Timeout"));
4859 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4860 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4862 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4865 assert(scan_dlg && scan_tbox && cancel_button);
4867 if (type == X_("closeme")) {
4871 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4874 if (!can_cancel || !cancelled) {
4875 scan_timeout_button->set_sensitive(false);
4877 cancel_button->set_sensitive(can_cancel && !cancelled);
4883 ARDOUR_UI::gui_idle_handler ()
4886 /* due to idle calls, gtk_events_pending() may always return true */
4887 while (gtk_events_pending() && --timeout) {
4888 gtk_main_iteration ();
4893 ARDOUR_UI::disk_underrun_handler ()
4895 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4897 if (!have_disk_speed_dialog_displayed) {
4898 have_disk_speed_dialog_displayed = true;
4899 MessageDialog* msg = new MessageDialog (
4900 _main_window, string_compose (_("The disk system on your computer\n\
4901 was not able to keep up with %1.\n\
4903 Specifically, it failed to read data from disk\n\
4904 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4905 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4911 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4913 have_disk_speed_dialog_displayed = false;
4918 ARDOUR_UI::session_dialog (std::string msg)
4920 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4924 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4931 ARDOUR_UI::pending_state_dialog ()
4933 HBox* hbox = manage (new HBox());
4934 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4935 ArdourDialog dialog (_("Crash Recovery"), true);
4936 Label message (string_compose (_("\
4937 This session appears to have been in the\n\
4938 middle of recording when %1 or\n\
4939 the computer was shutdown.\n\
4941 %1 can recover any captured audio for\n\
4942 you, or it can ignore it. Please decide\n\
4943 what you would like to do.\n"), PROGRAM_NAME));
4944 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4945 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4946 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4947 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4948 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4949 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4950 dialog.set_default_response (RESPONSE_ACCEPT);
4951 dialog.set_position (WIN_POS_CENTER);
4956 switch (dialog.run ()) {
4957 case RESPONSE_ACCEPT:
4965 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4967 HBox* hbox = new HBox();
4968 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4969 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4970 Label message (string_compose (_("\
4971 This session was created with a sample rate of %1 Hz, but\n\
4972 %2 is currently running at %3 Hz. If you load this session,\n\
4973 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4975 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4976 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4977 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4978 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4979 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4980 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4981 dialog.set_default_response (RESPONSE_ACCEPT);
4982 dialog.set_position (WIN_POS_CENTER);
4987 switch (dialog.run()) {
4988 case RESPONSE_ACCEPT:
4998 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5000 MessageDialog msg (string_compose (_("\
5001 This session was created with a sample rate of %1 Hz, but\n\
5002 %2 is currently running at %3 Hz.\n\
5003 Audio will be recorded and played at the wrong sample rate.\n\
5004 Re-Configure the Audio Engine in\n\
5005 Menu > Window > Audio/Midi Setup"),
5006 desired, PROGRAM_NAME, actual),
5008 Gtk::MESSAGE_WARNING);
5013 ARDOUR_UI::use_config ()
5015 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5017 set_transport_controllable_state (*node);
5022 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5024 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5025 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5027 primary_clock->set (pos);
5030 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5031 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5033 secondary_clock->set (pos);
5036 if (big_clock_window) {
5037 big_clock->set (pos);
5039 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5043 ARDOUR_UI::step_edit_status_change (bool yn)
5045 // XXX should really store pre-step edit status of things
5046 // we make insensitive
5049 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5050 rec_button.set_sensitive (false);
5052 rec_button.unset_active_state ();;
5053 rec_button.set_sensitive (true);
5058 ARDOUR_UI::record_state_changed ()
5060 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5063 /* why bother - the clock isn't visible */
5067 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5069 if (big_clock_window) {
5070 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5071 big_clock->set_active (true);
5073 big_clock->set_active (false);
5080 ARDOUR_UI::first_idle ()
5083 _session->allow_auto_play (true);
5087 editor->first_idle();
5090 Keyboard::set_can_save_keybindings (true);
5095 ARDOUR_UI::store_clock_modes ()
5097 XMLNode* node = new XMLNode(X_("ClockModes"));
5099 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5100 XMLNode* child = new XMLNode (X_("Clock"));
5102 child->add_property (X_("name"), (*x)->name());
5103 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5104 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5106 node->add_child_nocopy (*child);
5109 _session->add_extra_xml (*node);
5110 _session->set_dirty ();
5113 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5114 : Controllable (name), ui (u), type(tp)
5120 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5123 /* do nothing: these are radio-style actions */
5127 const char *action = 0;
5131 action = X_("Roll");
5134 action = X_("Stop");
5137 action = X_("GotoStart");
5140 action = X_("GotoEnd");
5143 action = X_("Loop");
5146 action = X_("PlaySelection");
5149 action = X_("Record");
5159 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5167 ARDOUR_UI::TransportControllable::get_value (void) const
5194 ARDOUR_UI::setup_profile ()
5196 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5197 Profile->set_small_screen ();
5200 if (g_getenv ("TRX")) {
5201 Profile->set_trx ();
5204 if (g_getenv ("MIXBUS")) {
5205 Profile->set_mixbus ();
5210 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5212 MissingFileDialog dialog (s, str, type);
5217 int result = dialog.run ();
5224 return 1; // quit entire session load
5227 result = dialog.get_action ();
5233 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5235 AmbiguousFileDialog dialog (file, hits);
5242 return dialog.get_which ();
5245 /** Allocate our thread-local buffers */
5247 ARDOUR_UI::get_process_buffers ()
5249 _process_thread->get_buffers ();
5252 /** Drop our thread-local buffers */
5254 ARDOUR_UI::drop_process_buffers ()
5256 _process_thread->drop_buffers ();
5260 ARDOUR_UI::feedback_detected ()
5262 _feedback_exists = true;
5266 ARDOUR_UI::successful_graph_sort ()
5268 _feedback_exists = false;
5272 ARDOUR_UI::midi_panic ()
5275 _session->midi_panic();
5280 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5282 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5283 const char* end_big = "</span>";
5284 const char* start_mono = "<tt>";
5285 const char* end_mono = "</tt>";
5287 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5288 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5289 "From now on, use the backup copy with older versions of %3"),
5290 xml_path, backup_path, PROGRAM_NAME,
5292 start_mono, end_mono), true);
5299 ARDOUR_UI::reset_peak_display ()
5301 if (!_session || !_session->master_out() || !editor_meter) return;
5302 editor_meter->clear_meters();
5303 editor_meter_max_peak = -INFINITY;
5304 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5308 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5310 if (!_session || !_session->master_out()) return;
5311 if (group == _session->master_out()->route_group()) {
5312 reset_peak_display ();
5317 ARDOUR_UI::reset_route_peak_display (Route* route)
5319 if (!_session || !_session->master_out()) return;
5320 if (_session->master_out().get() == route) {
5321 reset_peak_display ();
5326 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5328 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5329 audio_midi_setup->set_position (WIN_POS_CENTER);
5331 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5332 audio_midi_setup->try_autostart ();
5333 if (ARDOUR::AudioEngine::instance()->running()) {
5339 int response = audio_midi_setup->run();
5340 printf("RESPONSE %d\n", response);
5342 case Gtk::RESPONSE_DELETE_EVENT:
5345 if (!AudioEngine::instance()->running()) {
5348 audio_midi_setup->hide ();
5356 ARDOUR_UI::transport_numpad_timeout ()
5358 _numpad_locate_happening = false;
5359 if (_numpad_timeout_connection.connected() )
5360 _numpad_timeout_connection.disconnect();
5365 ARDOUR_UI::transport_numpad_decimal ()
5367 _numpad_timeout_connection.disconnect();
5369 if (_numpad_locate_happening) {
5370 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5371 _numpad_locate_happening = false;
5373 _pending_locate_num = 0;
5374 _numpad_locate_happening = true;
5375 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5380 ARDOUR_UI::transport_numpad_event (int num)
5382 if ( _numpad_locate_happening ) {
5383 _pending_locate_num = _pending_locate_num*10 + num;
5386 case 0: toggle_roll(false, false); break;
5387 case 1: transport_rewind(1); break;
5388 case 2: transport_forward(1); break;
5389 case 3: transport_record(true); break;
5390 case 4: toggle_session_auto_loop(); break;
5391 case 5: transport_record(false); toggle_session_auto_loop(); break;
5392 case 6: toggle_punch(); break;
5393 case 7: toggle_click(); break;
5394 case 8: toggle_auto_return(); break;
5395 case 9: toggle_follow_edits(); break;
5401 ARDOUR_UI::set_flat_buttons ()
5403 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5407 ARDOUR_UI::audioengine_became_silent ()
5409 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5411 Gtk::MESSAGE_WARNING,
5415 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5417 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5418 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5419 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5420 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5421 Gtk::HBox pay_button_box;
5422 Gtk::HBox subscribe_button_box;
5424 pay_button_box.pack_start (pay_button, true, false);
5425 subscribe_button_box.pack_start (subscribe_button, true, false);
5427 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 */
5429 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5430 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5432 msg.get_vbox()->pack_start (pay_label);
5433 msg.get_vbox()->pack_start (pay_button_box);
5434 msg.get_vbox()->pack_start (subscribe_label);
5435 msg.get_vbox()->pack_start (subscribe_button_box);
5437 msg.get_vbox()->show_all ();
5439 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5440 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5441 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5446 case Gtk::RESPONSE_YES:
5447 AudioEngine::instance()->reset_silence_countdown ();
5450 case Gtk::RESPONSE_NO:
5452 save_state_canfail ("");
5456 case Gtk::RESPONSE_CANCEL:
5458 /* don't reset, save session and exit */
5464 ARDOUR_UI::hide_application ()
5466 Application::instance ()-> hide ();
5470 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5472 /* icons, titles, WM stuff */
5474 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5476 if (window_icons.empty()) {
5477 Glib::RefPtr<Gdk::Pixbuf> icon;
5478 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5479 window_icons.push_back (icon);
5481 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5482 window_icons.push_back (icon);
5484 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5485 window_icons.push_back (icon);
5487 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5488 window_icons.push_back (icon);
5492 if (!window_icons.empty()) {
5493 window.set_default_icon_list (window_icons);
5496 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5498 if (!name.empty()) {
5502 window.set_title (title.get_string());
5503 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5505 window.set_flags (CAN_FOCUS);
5506 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5508 /* This is a hack to ensure that GTK-accelerators continue to
5509 * work. Once we switch over to entirely native bindings, this will be
5510 * unnecessary and should be removed
5512 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5514 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5515 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5516 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5517 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5521 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5523 Gtkmm2ext::Bindings* bindings = 0;
5524 Gtk::Window* window = 0;
5526 /* until we get ardour bindings working, we are not handling key
5530 if (ev->type != GDK_KEY_PRESS) {
5534 if (event_window == &_main_window) {
5536 window = event_window;
5538 /* find current tab contents */
5540 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5542 /* see if it uses the ardour binding system */
5545 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5548 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5552 window = event_window;
5554 /* see if window uses ardour binding system */
5556 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5559 /* An empty binding set is treated as if it doesn't exist */
5561 if (bindings && bindings->empty()) {
5565 return key_press_focus_accelerator_handler (*window, ev, bindings);
5568 static Gtkmm2ext::Bindings*
5569 get_bindings_from_widget_heirarchy (GtkWidget** w)
5574 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5577 *w = gtk_widget_get_parent (*w);
5580 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5584 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5586 GtkWindow* win = window.gobj();
5587 GtkWidget* focus = gtk_window_get_focus (win);
5588 GtkWidget* binding_widget = focus;
5589 bool special_handling_of_unmodified_accelerators = false;
5590 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5594 /* some widget has keyboard focus */
5596 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5598 /* A particular kind of focusable widget currently has keyboard
5599 * focus. All unmodified key events should go to that widget
5600 * first and not be used as an accelerator by default
5603 special_handling_of_unmodified_accelerators = true;
5607 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5608 if (focus_bindings) {
5609 bindings = focus_bindings;
5610 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5615 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",
5618 Gtkmm2ext::show_gdk_event_state (ev->state),
5619 special_handling_of_unmodified_accelerators,
5620 Keyboard::some_magic_widget_has_focus(),
5622 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5623 ((ev->state & mask) ? "yes" : "no"),
5624 window.get_title()));
5626 /* This exists to allow us to override the way GTK handles
5627 key events. The normal sequence is:
5629 a) event is delivered to a GtkWindow
5630 b) accelerators/mnemonics are activated
5631 c) if (b) didn't handle the event, propagate to
5632 the focus widget and/or focus chain
5634 The problem with this is that if the accelerators include
5635 keys without modifiers, such as the space bar or the
5636 letter "e", then pressing the key while typing into
5637 a text entry widget results in the accelerator being
5638 activated, instead of the desired letter appearing
5641 There is no good way of fixing this, but this
5642 represents a compromise. The idea is that
5643 key events involving modifiers (not Shift)
5644 get routed into the activation pathway first, then
5645 get propagated to the focus widget if necessary.
5647 If the key event doesn't involve modifiers,
5648 we deliver to the focus widget first, thus allowing
5649 it to get "normal text" without interference
5652 Of course, this can also be problematic: if there
5653 is a widget with focus, then it will swallow
5654 all "normal text" accelerators.
5658 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5660 /* no special handling or there are modifiers in effect: accelerate first */
5662 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5663 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5664 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5666 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5667 KeyboardKey k (ev->state, ev->keyval);
5671 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5673 if (bindings->activate (k, Bindings::Press)) {
5674 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5678 if (binding_widget) {
5679 binding_widget = gtk_widget_get_parent (binding_widget);
5680 if (binding_widget) {
5681 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5690 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5692 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5693 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5697 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5699 if (gtk_window_propagate_key_event (win, ev)) {
5700 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5706 /* no modifiers, propagate first */
5708 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5710 if (gtk_window_propagate_key_event (win, ev)) {
5711 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5715 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5716 KeyboardKey k (ev->state, ev->keyval);
5720 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5723 if (bindings->activate (k, Bindings::Press)) {
5724 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5728 if (binding_widget) {
5729 binding_widget = gtk_widget_get_parent (binding_widget);
5730 if (binding_widget) {
5731 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5740 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5742 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5743 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5748 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5753 ARDOUR_UI::load_bindings ()
5755 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5756 error << _("Global keybindings are missing") << endmsg;
5761 ARDOUR_UI::cancel_solo ()
5764 _session->cancel_all_solo ();
5769 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5771 /* this resets focus to the first focusable parent of the given widget,
5772 * or, if there is no focusable parent, cancels focus in the toplevel
5773 * window that the given widget is packed into (if there is one).
5780 Gtk::Widget* top = w->get_toplevel();
5782 if (!top || !top->is_toplevel()) {
5786 w = w->get_parent ();
5790 if (w->is_toplevel()) {
5791 /* Setting the focus widget to a Gtk::Window causes all
5792 * subsequent calls to ::has_focus() on the nominal
5793 * focus widget in that window to return
5794 * false. Workaround: never set focus to the toplevel
5800 if (w->get_can_focus ()) {
5801 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5802 win->set_focus (*w);
5805 w = w->get_parent ();
5808 if (top == &_main_window) {
5812 /* no focusable parent found, cancel focus in top level window.
5813 C++ API cannot be used for this. Thanks, references.
5816 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);