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 "idleometer.h"
146 #include "keyboard.h"
147 #include "keyeditor.h"
148 #include "location_ui.h"
149 #include "lua_script_manager.h"
150 #include "luawindow.h"
151 #include "main_clock.h"
152 #include "missing_file_dialog.h"
153 #include "missing_plugin_dialog.h"
154 #include "mixer_ui.h"
155 #include "meterbridge.h"
156 #include "meter_patterns.h"
157 #include "mouse_cursors.h"
160 #include "pingback.h"
161 #include "processor_box.h"
162 #include "prompter.h"
163 #include "public_editor.h"
164 #include "rc_option_editor.h"
165 #include "route_time_axis.h"
166 #include "route_params_ui.h"
167 #include "save_as_dialog.h"
168 #include "script_selector.h"
169 #include "session_archive_dialog.h"
170 #include "session_dialog.h"
171 #include "session_metadata_dialog.h"
172 #include "session_option_editor.h"
173 #include "speaker_dialog.h"
176 #include "time_axis_view_item.h"
177 #include "time_info_box.h"
180 #include "utils_videotl.h"
181 #include "video_server_dialog.h"
182 #include "add_video_dialog.h"
183 #include "transcode_video_dialog.h"
185 #include "pbd/i18n.h"
187 using namespace ARDOUR;
188 using namespace ARDOUR_UI_UTILS;
190 using namespace Gtkmm2ext;
193 using namespace Editing;
195 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
197 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
198 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
201 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
203 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
204 "Would you like these files to be copied and used for %1 %2.x?\n\n"
205 "(This will require you to restart %1.)"),
206 PROGRAM_NAME, PROGRAM_VERSION, version),
207 false, /* no markup */
210 true /* modal, though it hardly matters since it is the only window */
213 msg.set_default_response (Gtk::RESPONSE_YES);
216 return (msg.run() == Gtk::RESPONSE_YES);
220 libxml_generic_error_func (void* /* parsing_context*/,
228 vsnprintf (buf, sizeof (buf), msg, ap);
229 error << buf << endmsg;
234 libxml_structured_error_func (void* /* parsing_context*/,
242 replace_all (msg, "\n", "");
245 if (err->file && err->line) {
246 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
249 error << ':' << err->int2;
254 error << X_("XML error: ") << msg << endmsg;
260 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
261 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
262 , session_loaded (false)
263 , gui_object_state (new GUIObjectState)
264 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
265 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
266 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
268 , global_actions (X_("global"))
269 , ignore_dual_punch (false)
270 , main_window_visibility (0)
275 , _mixer_on_top (false)
276 , _initial_verbose_plugin_scan (false)
277 , first_time_engine_run (true)
278 , secondary_clock_spacer (0)
279 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
280 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
281 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
282 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
283 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
284 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
285 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
286 , auto_input_button (ArdourButton::led_default_elements)
288 , auto_return_button (ArdourButton::led_default_elements)
289 , follow_edits_button (ArdourButton::led_default_elements)
290 , auditioning_alert_button (_("Audition"))
291 , solo_alert_button (_("Solo"))
292 , feedback_alert_button (_("Feedback"))
293 , error_alert_button ( ArdourButton::just_led_default_elements )
295 , editor_meter_peak_display()
296 , _suspend_editor_meter_callbacks (false)
297 , _numpad_locate_happening (false)
298 , _session_is_new (false)
299 , last_key_press_time (0)
303 , rc_option_editor (0)
304 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
305 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
306 , about (X_("about"), _("About"))
307 , location_ui (X_("locations"), S_("Ranges|Locations"))
308 , route_params (X_("inspector"), _("Tracks and Busses"))
309 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
310 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
311 , lua_script_window (X_("script-manager"), _("Script Manager"))
312 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
313 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
314 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
315 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
316 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
317 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
318 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
319 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
320 , video_server_process (0)
322 , have_configure_timeout (false)
323 , last_configure_time (0)
325 , have_disk_speed_dialog_displayed (false)
326 , _status_bar_visibility (X_("status-bar"))
327 , _feedback_exists (false)
328 , _log_not_acknowledged (LogLevelNone)
329 , duplicate_routes_dialog (0)
330 , editor_visibility_button (S_("Window|Editor"))
331 , mixer_visibility_button (S_("Window|Mixer"))
332 , prefs_visibility_button (S_("Window|Preferences"))
334 Gtkmm2ext::init (localedir);
336 UIConfiguration::instance().post_gui_init ();
338 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
340 /* "touch" the been-here-before path now that config has been migrated */
341 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
343 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
345 /* configuration was modified, exit immediately */
350 if (string (VERSIONSTRING).find (".pre") != string::npos) {
351 /* check this is not being run from ./ardev etc. */
352 if (!running_from_source_tree ()) {
353 pre_release_dialog ();
357 if (theArdourUI == 0) {
361 /* track main window visibility */
363 main_window_visibility = new VisibilityTracker (_main_window);
365 /* stop libxml from spewing to stdout/stderr */
367 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
368 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
370 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
371 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
372 UIConfiguration::instance().map_parameters (pc);
374 roll_button.set_controllable (roll_controllable);
375 stop_button.set_controllable (stop_controllable);
376 goto_start_button.set_controllable (goto_start_controllable);
377 goto_end_button.set_controllable (goto_end_controllable);
378 auto_loop_button.set_controllable (auto_loop_controllable);
379 play_selection_button.set_controllable (play_selection_controllable);
380 rec_button.set_controllable (rec_controllable);
382 roll_button.set_name ("transport button");
383 stop_button.set_name ("transport button");
384 goto_start_button.set_name ("transport button");
385 goto_end_button.set_name ("transport button");
386 auto_loop_button.set_name ("transport button");
387 play_selection_button.set_name ("transport button");
388 rec_button.set_name ("transport recenable button");
389 midi_panic_button.set_name ("transport button");
391 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
392 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
394 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
396 /* handle dialog requests */
398 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
400 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
402 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
404 /* handle Audio/MIDI setup when session requires it */
406 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
408 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
410 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
412 /* handle sr mismatch with a dialog - cross-thread from engine */
413 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
415 /* handle requests to quit (coming from JACK session) */
417 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
419 /* tell the user about feedback */
421 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
422 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
424 /* handle requests to deal with missing files */
426 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
428 /* and ambiguous files */
430 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
432 /* also plugin scan messages */
433 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
434 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
436 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
438 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
441 /* lets get this party started */
443 setup_gtk_ardour_enums ();
446 SessionEvent::create_per_thread_pool ("GUI", 4096);
448 /* we like keyboards */
450 keyboard = new ArdourKeyboard(*this);
452 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
454 keyboard->set_state (*node, Stateful::loading_state_version);
457 UIConfiguration::instance().reset_dpi ();
459 TimeAxisViewItem::set_constant_heights ();
461 /* Set this up so that our window proxies can register actions */
463 ActionManager::init ();
465 /* The following must happen after ARDOUR::init() so that Config is set up */
467 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
470 key_editor.set_state (*ui_xml, 0);
471 session_option_editor.set_state (*ui_xml, 0);
472 speaker_config_window.set_state (*ui_xml, 0);
473 about.set_state (*ui_xml, 0);
474 add_route_dialog.set_state (*ui_xml, 0);
475 add_video_dialog.set_state (*ui_xml, 0);
476 route_params.set_state (*ui_xml, 0);
477 bundle_manager.set_state (*ui_xml, 0);
478 location_ui.set_state (*ui_xml, 0);
479 big_clock_window.set_state (*ui_xml, 0);
480 audio_port_matrix.set_state (*ui_xml, 0);
481 midi_port_matrix.set_state (*ui_xml, 0);
482 export_video_dialog.set_state (*ui_xml, 0);
483 lua_script_window.set_state (*ui_xml, 0);
484 idleometer.set_state (*ui_xml, 0);
487 /* Separate windows */
489 WM::Manager::instance().register_window (&key_editor);
490 WM::Manager::instance().register_window (&session_option_editor);
491 WM::Manager::instance().register_window (&speaker_config_window);
492 WM::Manager::instance().register_window (&about);
493 WM::Manager::instance().register_window (&add_route_dialog);
494 WM::Manager::instance().register_window (&add_video_dialog);
495 WM::Manager::instance().register_window (&route_params);
496 WM::Manager::instance().register_window (&audio_midi_setup);
497 WM::Manager::instance().register_window (&export_video_dialog);
498 WM::Manager::instance().register_window (&lua_script_window);
499 WM::Manager::instance().register_window (&bundle_manager);
500 WM::Manager::instance().register_window (&location_ui);
501 WM::Manager::instance().register_window (&big_clock_window);
502 WM::Manager::instance().register_window (&audio_port_matrix);
503 WM::Manager::instance().register_window (&midi_port_matrix);
504 WM::Manager::instance().register_window (&idleometer);
506 /* do not retain position for add route dialog */
507 add_route_dialog.set_state_mask (WindowProxy::Size);
509 /* Trigger setting up the color scheme and loading the GTK RC file */
511 UIConfiguration::instance().load_rc_file (false);
513 _process_thread = new ProcessThread ();
514 _process_thread->init ();
516 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
522 ARDOUR_UI::pre_release_dialog ()
524 ArdourDialog d (_("Pre-Release Warning"), true, false);
525 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
527 Label* label = manage (new Label);
528 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
529 There are still several issues and bugs to be worked on,\n\
530 as well as general workflow improvements, before this can be considered\n\
531 release software. So, a few guidelines:\n\
533 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
534 though it may be so, depending on your workflow.\n\
535 2) Please wait for a helpful writeup of new features.\n\
536 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
537 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
538 making sure to note the product version number as 5.0-pre.\n\
539 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
540 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
541 can get there directly from within the program via the Help->Chat menu option.\n\
543 Full information on all the above can be found on the support page at\n\
545 http://ardour.org/support\n\
546 "), PROGRAM_NAME, VERSIONSTRING));
548 d.get_vbox()->set_border_width (12);
549 d.get_vbox()->pack_start (*label, false, false, 12);
550 d.get_vbox()->show_all ();
555 GlobalPortMatrixWindow*
556 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
561 return new GlobalPortMatrixWindow (_session, type);
565 ARDOUR_UI::attach_to_engine ()
567 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
568 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
572 ARDOUR_UI::engine_stopped ()
574 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
575 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
576 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
577 update_sample_rate (0);
582 ARDOUR_UI::engine_running ()
584 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
585 if (first_time_engine_run) {
587 first_time_engine_run = false;
591 _session->reset_xrun_count ();
593 update_disk_space ();
595 update_xrun_count ();
596 update_sample_rate (AudioEngine::instance()->sample_rate());
597 update_timecode_format ();
598 update_peak_thread_work ();
599 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
600 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
604 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
606 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
607 /* we can't rely on the original string continuing to exist when we are called
608 again in the GUI thread, so make a copy and note that we need to
611 char *copy = strdup (reason);
612 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
616 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
617 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
619 update_sample_rate (0);
623 /* if the reason is a non-empty string, it means that the backend was shutdown
624 rather than just Ardour.
627 if (strlen (reason)) {
628 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
630 msgstr = string_compose (_("\
631 The audio backend has either been shutdown or it\n\
632 disconnected %1 because %1\n\
633 was not fast enough. Try to restart\n\
634 the audio backend and save the session."), PROGRAM_NAME);
637 MessageDialog msg (_main_window, msgstr);
638 pop_back_splash (msg);
642 free (const_cast<char*> (reason));
647 ARDOUR_UI::post_engine ()
649 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
651 #ifdef AUDIOUNIT_SUPPORT
653 if (AUPluginInfo::au_get_crashlog(au_msg)) {
654 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
655 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
656 info << au_msg << endmsg;
660 ARDOUR::init_post_engine ();
662 /* connect to important signals */
664 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
665 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
666 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
667 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
668 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
670 if (setup_windows ()) {
671 throw failed_constructor ();
674 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
675 XMLNode* n = Config->extra_xml (X_("UI"));
677 _status_bar_visibility.set_state (*n);
680 check_memory_locking();
682 /* this is the first point at which all the possible actions are
683 * available, because some of the available actions are dependent on
684 * aspects of the engine/backend.
687 if (ARDOUR_COMMAND_LINE::show_key_actions) {
690 vector<string> paths;
691 vector<string> labels;
692 vector<string> tooltips;
694 vector<Glib::RefPtr<Gtk::Action> > actions;
696 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
698 vector<string>::iterator k;
699 vector<string>::iterator p;
701 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
706 cout << *p << " => " << *k << endl;
710 halt_connection.disconnect ();
711 AudioEngine::instance()->stop ();
715 /* this being a GUI and all, we want peakfiles */
717 AudioFileSource::set_build_peakfiles (true);
718 AudioFileSource::set_build_missing_peakfiles (true);
720 /* set default clock modes */
722 primary_clock->set_mode (AudioClock::Timecode);
723 secondary_clock->set_mode (AudioClock::BBT);
725 /* start the time-of-day-clock */
728 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
729 update_wall_clock ();
730 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
735 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
736 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
737 Config->map_parameters (pc);
739 UIConfiguration::instance().map_parameters (pc);
743 ARDOUR_UI::~ARDOUR_UI ()
745 UIConfiguration::instance().save_state();
749 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
750 // don't bother at 'real' exit. the OS cleans up for us.
751 delete big_clock; big_clock = 0;
752 delete primary_clock; primary_clock = 0;
753 delete secondary_clock; secondary_clock = 0;
754 delete _process_thread; _process_thread = 0;
755 delete time_info_box; time_info_box = 0;
756 delete meterbridge; meterbridge = 0;
757 delete luawindow; luawindow = 0;
758 delete editor; editor = 0;
759 delete mixer; mixer = 0;
760 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
762 delete gui_object_state; gui_object_state = 0;
763 delete main_window_visibility;
764 FastMeter::flush_pattern_cache ();
765 PixFader::flush_pattern_cache ();
769 /* Small trick to flush main-thread event pool.
770 * Other thread-pools are destroyed at pthread_exit(),
771 * but tmain thread termination is too late to trigger Pool::~Pool()
773 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.
774 delete ev->event_pool();
779 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
781 if (Splash::instance()) {
782 Splash::instance()->pop_back_for (win);
787 ARDOUR_UI::configure_timeout ()
789 if (last_configure_time == 0) {
790 /* no configure events yet */
794 /* force a gap of 0.5 seconds since the last configure event
797 if (get_microseconds() - last_configure_time < 500000) {
800 have_configure_timeout = false;
801 save_ardour_state ();
807 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
809 if (have_configure_timeout) {
810 last_configure_time = get_microseconds();
812 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
813 have_configure_timeout = true;
820 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
822 XMLProperty const * prop;
824 if ((prop = node.property ("roll")) != 0) {
825 roll_controllable->set_id (prop->value());
827 if ((prop = node.property ("stop")) != 0) {
828 stop_controllable->set_id (prop->value());
830 if ((prop = node.property ("goto-start")) != 0) {
831 goto_start_controllable->set_id (prop->value());
833 if ((prop = node.property ("goto-end")) != 0) {
834 goto_end_controllable->set_id (prop->value());
836 if ((prop = node.property ("auto-loop")) != 0) {
837 auto_loop_controllable->set_id (prop->value());
839 if ((prop = node.property ("play-selection")) != 0) {
840 play_selection_controllable->set_id (prop->value());
842 if ((prop = node.property ("rec")) != 0) {
843 rec_controllable->set_id (prop->value());
845 if ((prop = node.property ("shuttle")) != 0) {
846 shuttle_box.controllable()->set_id (prop->value());
851 ARDOUR_UI::get_transport_controllable_state ()
853 XMLNode* node = new XMLNode(X_("TransportControllables"));
855 node->add_property (X_("roll"), roll_controllable->id().to_s());
856 node->add_property (X_("stop"), stop_controllable->id().to_s());
857 node->add_property (X_("goto_start"), goto_start_controllable->id().to_s());
858 node->add_property (X_("goto_end"), goto_end_controllable->id().to_s());
859 node->add_property (X_("auto_loop"), auto_loop_controllable->id().to_s());
860 node->add_property (X_("play_selection"), play_selection_controllable->id().to_s());
861 node->add_property (X_("rec"), rec_controllable->id().to_s());
862 node->add_property (X_("shuttle"), shuttle_box.controllable()->id().to_s());
868 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
871 _session->save_state (snapshot_name);
876 ARDOUR_UI::autosave_session ()
878 if (g_main_depth() > 1) {
879 /* inside a recursive main loop,
880 give up because we may not be able to
886 if (!Config->get_periodic_safety_backups()) {
891 _session->maybe_write_autosave();
898 ARDOUR_UI::session_dirty_changed ()
905 ARDOUR_UI::update_autosave ()
907 if (_session && _session->dirty()) {
908 if (_autosave_connection.connected()) {
909 _autosave_connection.disconnect();
912 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
913 Config->get_periodic_safety_backup_interval() * 1000);
916 if (_autosave_connection.connected()) {
917 _autosave_connection.disconnect();
923 ARDOUR_UI::check_announcements ()
926 string _annc_filename;
929 _annc_filename = PROGRAM_NAME "_announcements_osx_";
930 #elif defined PLATFORM_WINDOWS
931 _annc_filename = PROGRAM_NAME "_announcements_windows_";
933 _annc_filename = PROGRAM_NAME "_announcements_linux_";
935 _annc_filename.append (VERSIONSTRING);
937 _announce_string = "";
939 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
940 FILE* fin = g_fopen (path.c_str(), "rb");
942 while (!feof (fin)) {
945 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
948 _announce_string.append (tmp, len);
953 pingback (VERSIONSTRING, path);
958 _hide_splash (gpointer arg)
960 ((ARDOUR_UI*)arg)->hide_splash();
965 ARDOUR_UI::starting ()
967 Application* app = Application::instance ();
969 bool brand_new_user = ArdourStartup::required ();
971 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
972 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
974 if (ARDOUR_COMMAND_LINE::check_announcements) {
975 check_announcements ();
980 /* we need to create this early because it may need to set the
981 * audio backend end up.
985 audio_midi_setup.get (true);
987 std::cerr << "audio-midi engine setup failed."<< std::endl;
991 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
992 nsm = new NSM_Client;
993 if (!nsm->init (nsm_url)) {
994 /* the ardour executable may have different names:
996 * waf's obj.target for distro versions: eg ardour4, ardourvst4
997 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
998 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1000 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1002 const char *process_name = g_getenv ("ARDOUR_SELF");
1003 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1006 // wait for announce reply from nsm server
1007 for ( i = 0; i < 5000; ++i) {
1011 if (nsm->is_active()) {
1016 error << _("NSM server did not announce itself") << endmsg;
1019 // wait for open command from nsm server
1020 for ( i = 0; i < 5000; ++i) {
1022 Glib::usleep (1000);
1023 if (nsm->client_id ()) {
1029 error << _("NSM: no client ID provided") << endmsg;
1033 if (_session && nsm) {
1034 _session->set_nsm_state( nsm->is_active() );
1036 error << _("NSM: no session created") << endmsg;
1040 // nsm requires these actions disabled
1041 vector<string> action_names;
1042 action_names.push_back("SaveAs");
1043 action_names.push_back("Rename");
1044 action_names.push_back("New");
1045 action_names.push_back("Open");
1046 action_names.push_back("Recent");
1047 action_names.push_back("Close");
1049 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1050 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1052 act->set_sensitive (false);
1059 error << _("NSM: initialization failed") << endmsg;
1065 if (brand_new_user) {
1066 _initial_verbose_plugin_scan = true;
1071 _initial_verbose_plugin_scan = false;
1072 switch (s.response ()) {
1073 case Gtk::RESPONSE_OK:
1080 // TODO: maybe IFF brand_new_user
1081 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1082 std::string dspd (Config->get_default_session_parent_dir());
1083 Searchpath ds (ARDOUR::ardour_data_search_path());
1084 ds.add_subdirectory_to_paths ("sessions");
1085 vector<string> demos;
1086 find_files_matching_pattern (demos, ds, "*.tar.xz");
1088 ARDOUR::RecentSessions rs;
1089 ARDOUR::read_recent_sessions (rs);
1091 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1092 /* "demo-session" must be inside "demo-session.tar.xz"
1095 std::string name = basename_nosuffix (basename_nosuffix (*i));
1096 std::string path = Glib::build_filename (dspd, name);
1097 /* skip if session-dir already exists */
1098 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1101 /* skip sessions that are already in 'recent'.
1102 * eg. a new user changed <session-default-dir> shorly after installation
1104 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1105 if ((*r).first == name) {
1110 PBD::FileArchive ar (*i);
1111 if (0 == ar.inflate (dspd)) {
1112 store_recent_sessions (name, path);
1113 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1119 #ifdef NO_PLUGIN_STATE
1121 ARDOUR::RecentSessions rs;
1122 ARDOUR::read_recent_sessions (rs);
1124 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1126 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1128 /* already used Ardour, have sessions ... warn about plugin state */
1130 ArdourDialog d (_("Free/Demo Version Warning"), true);
1132 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1133 CheckButton c (_("Don't warn me about this again"));
1135 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"),
1136 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1137 _("It will not restore OR save any plugin settings"),
1138 _("If you load an existing session with plugin settings\n"
1139 "they will not be used and will be lost."),
1140 _("To get full access to updates without this limitation\n"
1141 "consider becoming a subscriber for a low cost every month.")));
1142 l.set_justify (JUSTIFY_CENTER);
1144 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1146 d.get_vbox()->pack_start (l, true, true);
1147 d.get_vbox()->pack_start (b, false, false, 12);
1148 d.get_vbox()->pack_start (c, false, false, 12);
1150 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1151 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1155 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1157 if (d.run () != RESPONSE_OK) {
1163 /* go get a session */
1165 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1167 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1168 std::cerr << "Cannot get session parameters."<< std::endl;
1175 WM::Manager::instance().show_visible ();
1177 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1178 * editor window, and we may want stuff to be hidden.
1180 _status_bar_visibility.update ();
1182 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1184 if (splash && splash->is_visible()) {
1185 // in 1 second, hide the splash screen
1186 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1189 /* all other dialogs are created conditionally */
1195 ARDOUR_UI::check_memory_locking ()
1197 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1198 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1202 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1204 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1206 struct rlimit limits;
1208 long pages, page_size;
1210 size_t pages_len=sizeof(pages);
1211 if ((page_size = getpagesize()) < 0 ||
1212 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1214 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1219 ram = (int64_t) pages * (int64_t) page_size;
1222 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1226 if (limits.rlim_cur != RLIM_INFINITY) {
1228 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1232 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1233 "This might cause %1 to run out of memory before your system "
1234 "runs out of memory. \n\n"
1235 "You can view the memory limit with 'ulimit -l', "
1236 "and it is normally controlled by %2"),
1239 X_("/etc/login.conf")
1241 X_(" /etc/security/limits.conf")
1245 msg.set_default_response (RESPONSE_OK);
1247 VBox* vbox = msg.get_vbox();
1249 CheckButton cb (_("Do not show this window again"));
1250 hbox.pack_start (cb, true, false);
1251 vbox->pack_start (hbox);
1256 pop_back_splash (msg);
1260 if (cb.get_active()) {
1261 XMLNode node (X_("no-memory-warning"));
1262 Config->add_instant_xml (node);
1267 #endif // !__APPLE__
1272 ARDOUR_UI::queue_finish ()
1274 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1278 ARDOUR_UI::idle_finish ()
1281 return false; /* do not call again */
1288 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1290 if (_session->dirty()) {
1291 vector<string> actions;
1292 actions.push_back (_("Don't quit"));
1293 actions.push_back (_("Just quit"));
1294 actions.push_back (_("Save and quit"));
1295 switch (ask_about_saving_session(actions)) {
1300 /* use the default name */
1301 if (save_state_canfail ("")) {
1302 /* failed - don't quit */
1303 MessageDialog msg (_main_window,
1304 string_compose (_("\
1305 %1 was unable to save your session.\n\n\
1306 If you still wish to quit, please use the\n\n\
1307 \"Just quit\" option."), PROGRAM_NAME));
1308 pop_back_splash(msg);
1318 second_connection.disconnect ();
1319 point_one_second_connection.disconnect ();
1320 point_zero_something_second_connection.disconnect();
1321 fps_connection.disconnect();
1324 delete ARDOUR_UI::instance()->video_timeline;
1325 ARDOUR_UI::instance()->video_timeline = NULL;
1326 stop_video_server();
1328 /* Save state before deleting the session, as that causes some
1329 windows to be destroyed before their visible state can be
1332 save_ardour_state ();
1334 if (key_editor.get (false)) {
1335 key_editor->disconnect ();
1338 close_all_dialogs ();
1341 _session->set_clean ();
1342 _session->remove_pending_capture_state ();
1347 halt_connection.disconnect ();
1348 AudioEngine::instance()->stop ();
1349 #ifdef WINDOWS_VST_SUPPORT
1350 fst_stop_threading();
1356 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1358 ArdourDialog window (_("Unsaved Session"));
1359 Gtk::HBox dhbox; // the hbox for the image and text
1360 Gtk::Label prompt_label;
1361 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1365 assert (actions.size() >= 3);
1367 window.add_button (actions[0], RESPONSE_REJECT);
1368 window.add_button (actions[1], RESPONSE_APPLY);
1369 window.add_button (actions[2], RESPONSE_ACCEPT);
1371 window.set_default_response (RESPONSE_ACCEPT);
1373 Gtk::Button noquit_button (msg);
1374 noquit_button.set_name ("EditorGTKButton");
1378 if (_session->snap_name() == _session->name()) {
1379 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?"),
1380 _session->snap_name());
1382 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?"),
1383 _session->snap_name());
1386 prompt_label.set_text (prompt);
1387 prompt_label.set_name (X_("PrompterLabel"));
1388 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1390 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1391 dhbox.set_homogeneous (false);
1392 dhbox.pack_start (*dimage, false, false, 5);
1393 dhbox.pack_start (prompt_label, true, false, 5);
1394 window.get_vbox()->pack_start (dhbox);
1396 window.set_name (_("Prompter"));
1397 window.set_modal (true);
1398 window.set_resizable (false);
1401 prompt_label.show();
1406 ResponseType r = (ResponseType) window.run();
1411 case RESPONSE_ACCEPT: // save and get out of here
1413 case RESPONSE_APPLY: // get out of here
1424 ARDOUR_UI::every_second ()
1427 update_xrun_count ();
1428 update_buffer_load ();
1429 update_disk_space ();
1430 update_timecode_format ();
1431 update_peak_thread_work ();
1433 if (nsm && nsm->is_active ()) {
1436 if (!_was_dirty && _session->dirty ()) {
1440 else if (_was_dirty && !_session->dirty ()){
1448 ARDOUR_UI::every_point_one_seconds ()
1450 // TODO get rid of this..
1451 // ShuttleControl is updated directly via TransportStateChange signal
1455 ARDOUR_UI::every_point_zero_something_seconds ()
1457 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1459 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1460 float mpeak = editor_meter->update_meters();
1461 if (mpeak > editor_meter_max_peak) {
1462 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1463 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1470 ARDOUR_UI::set_fps_timeout_connection ()
1472 unsigned int interval = 40;
1473 if (!_session) return;
1474 if (_session->timecode_frames_per_second() != 0) {
1475 /* ideally we'll use a select() to sleep and not accumulate
1476 * idle time to provide a regular periodic signal.
1477 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1478 * However, that'll require a dedicated thread and cross-thread
1479 * signals to the GUI Thread..
1481 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1482 * _session->frame_rate() / _session->nominal_frame_rate()
1483 / _session->timecode_frames_per_second()
1485 #ifdef PLATFORM_WINDOWS
1486 // the smallest windows scheduler time-slice is ~15ms.
1487 // periodic GUI timeouts shorter than that will cause
1488 // WaitForSingleObject to spinlock (100% of one CPU Core)
1489 // and gtk never enters idle mode.
1490 // also changing timeBeginPeriod(1) does not affect that in
1491 // any beneficial way, so we just limit the max rate for now.
1492 interval = std::max(30u, interval); // at most ~33Hz.
1494 interval = std::max(8u, interval); // at most 120Hz.
1497 fps_connection.disconnect();
1498 Timers::set_fps_interval (interval);
1502 ARDOUR_UI::update_sample_rate (framecnt_t)
1506 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1508 if (!AudioEngine::instance()->connected()) {
1510 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1514 framecnt_t rate = AudioEngine::instance()->sample_rate();
1517 /* no sample rate available */
1518 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1521 if (fmod (rate, 1000.0) != 0.0) {
1522 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1523 (float) rate / 1000.0f,
1524 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1526 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1528 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1532 sample_rate_label.set_markup (buf);
1536 ARDOUR_UI::update_format ()
1539 format_label.set_text ("");
1544 s << _("File:") << X_(" <span foreground=\"green\">");
1546 switch (_session->config.get_native_file_header_format ()) {
1578 switch (_session->config.get_native_file_data_format ()) {
1592 format_label.set_markup (s.str ());
1596 ARDOUR_UI::update_xrun_count ()
1600 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1601 should also be changed.
1605 const unsigned int x = _session->get_xrun_count ();
1607 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1609 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1612 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1614 xrun_label.set_markup (buf);
1615 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1619 ARDOUR_UI::update_cpu_load ()
1623 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1624 should also be changed.
1627 double const c = AudioEngine::instance()->get_dsp_load ();
1628 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1629 cpu_load_label.set_markup (buf);
1633 ARDOUR_UI::update_peak_thread_work ()
1636 const int c = SourceFactory::peak_work_queue_length ();
1638 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1639 peak_thread_work_label.set_markup (buf);
1641 peak_thread_work_label.set_markup (X_(""));
1646 ARDOUR_UI::update_buffer_load ()
1650 uint32_t const playback = _session ? _session->playback_load () : 100;
1651 uint32_t const capture = _session ? _session->capture_load () : 100;
1653 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1654 should also be changed.
1660 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1661 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1662 playback <= 5 ? X_("red") : X_("green"),
1664 capture <= 5 ? X_("red") : X_("green"),
1668 buffer_load_label.set_markup (buf);
1670 buffer_load_label.set_text ("");
1675 ARDOUR_UI::count_recenabled_streams (Route& route)
1677 Track* track = dynamic_cast<Track*>(&route);
1678 if (track && track->rec_enable_control()->get_value()) {
1679 rec_enabled_streams += track->n_inputs().n_total();
1684 ARDOUR_UI::update_disk_space()
1686 if (_session == 0) {
1690 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1692 framecnt_t fr = _session->frame_rate();
1695 /* skip update - no SR available */
1700 /* Available space is unknown */
1701 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1702 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1703 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1705 rec_enabled_streams = 0;
1706 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1708 framecnt_t frames = opt_frames.get_value_or (0);
1710 if (rec_enabled_streams) {
1711 frames /= rec_enabled_streams;
1718 hrs = frames / (fr * 3600);
1721 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1723 frames -= hrs * fr * 3600;
1724 mins = frames / (fr * 60);
1725 frames -= mins * fr * 60;
1728 bool const low = (hrs == 0 && mins <= 30);
1732 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1733 low ? X_("red") : X_("green"),
1739 disk_space_label.set_markup (buf);
1743 ARDOUR_UI::update_timecode_format ()
1749 TimecodeSlave* tcslave;
1750 SyncSource sync_src = Config->get_sync_source();
1752 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1753 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1758 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1759 matching ? X_("green") : X_("red"),
1760 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1762 snprintf (buf, sizeof (buf), "TC: n/a");
1765 timecode_format_label.set_markup (buf);
1769 ARDOUR_UI::update_wall_clock ()
1773 static int last_min = -1;
1776 tm_now = localtime (&now);
1777 if (last_min != tm_now->tm_min) {
1779 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1780 wall_clock_label.set_text (buf);
1781 last_min = tm_now->tm_min;
1788 ARDOUR_UI::open_recent_session ()
1790 bool can_return = (_session != 0);
1792 SessionDialog recent_session_dialog;
1796 ResponseType r = (ResponseType) recent_session_dialog.run ();
1799 case RESPONSE_ACCEPT:
1803 recent_session_dialog.hide();
1810 recent_session_dialog.hide();
1814 std::string path = recent_session_dialog.session_folder();
1815 std::string state = recent_session_dialog.session_name (should_be_new);
1817 if (should_be_new == true) {
1821 _session_is_new = false;
1823 if (load_session (path, state) == 0) {
1829 if (splash && splash->is_visible()) {
1830 // in 1 second, hide the splash screen
1831 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1836 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1838 if (!AudioEngine::instance()->connected()) {
1839 MessageDialog msg (parent, string_compose (
1840 _("%1 is not connected to any audio backend.\n"
1841 "You cannot open or close sessions in this condition"),
1843 pop_back_splash (msg);
1851 ARDOUR_UI::open_session ()
1853 if (!check_audioengine (_main_window)) {
1857 /* ardour sessions are folders */
1858 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1859 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1860 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1861 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1864 string session_parent_dir = Glib::path_get_dirname(_session->path());
1865 open_session_selector.set_current_folder(session_parent_dir);
1867 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1870 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1872 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1873 string default_session_folder = Config->get_default_session_parent_dir();
1874 open_session_selector.add_shortcut_folder (default_session_folder);
1876 catch (Glib::Error & e) {
1877 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1880 FileFilter session_filter;
1881 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1882 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1883 open_session_selector.add_filter (session_filter);
1885 FileFilter archive_filter;
1886 archive_filter.add_pattern (X_("*.tar.xz"));
1887 archive_filter.set_name (_("Session Archives"));
1889 open_session_selector.add_filter (archive_filter);
1891 open_session_selector.set_filter (session_filter);
1893 int response = open_session_selector.run();
1894 open_session_selector.hide ();
1896 if (response == Gtk::RESPONSE_CANCEL) {
1900 string session_path = open_session_selector.get_filename();
1904 if (session_path.length() > 0) {
1905 int rv = ARDOUR::inflate_session (session_path,
1906 Config->get_default_session_parent_dir(), path, name);
1908 _session_is_new = false;
1909 load_session (path, name);
1912 MessageDialog msg (_main_window,
1913 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1916 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1917 _session_is_new = isnew;
1918 load_session (path, name);
1924 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1930 _session->vca_manager().create_vca (n, name_template);
1934 ARDOUR_UI::session_add_mixed_track (
1935 const ChanCount& input,
1936 const ChanCount& output,
1937 RouteGroup* route_group,
1939 const string& name_template,
1941 PluginInfoPtr instrument,
1942 Plugin::PresetRecord* pset,
1943 ARDOUR::PresentationInfo::order_t order)
1945 if (_session == 0) {
1946 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1950 if (Profile->get_mixbus ()) {
1955 list<boost::shared_ptr<MidiTrack> > tracks;
1956 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1958 if (tracks.size() != how_many) {
1959 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1964 display_insufficient_ports_message ();
1970 ARDOUR_UI::session_add_midi_bus (
1971 RouteGroup* route_group,
1973 const string& name_template,
1975 PluginInfoPtr instrument,
1976 Plugin::PresetRecord* pset,
1977 ARDOUR::PresentationInfo::order_t order)
1979 if (_session == 0) {
1980 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1984 if (Profile->get_mixbus ()) {
1990 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
1991 if (routes.size() != how_many) {
1992 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1997 display_insufficient_ports_message ();
2003 ARDOUR_UI::session_add_midi_route (
2005 RouteGroup* route_group,
2007 const string& name_template,
2009 PluginInfoPtr instrument,
2010 Plugin::PresetRecord* pset,
2011 ARDOUR::PresentationInfo::order_t order)
2013 ChanCount one_midi_channel;
2014 one_midi_channel.set (DataType::MIDI, 1);
2017 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2019 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2024 ARDOUR_UI::session_add_audio_route (
2026 int32_t input_channels,
2027 int32_t output_channels,
2028 ARDOUR::TrackMode mode,
2029 RouteGroup* route_group,
2031 string const & name_template,
2033 ARDOUR::PresentationInfo::order_t order)
2035 list<boost::shared_ptr<AudioTrack> > tracks;
2038 if (_session == 0) {
2039 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2045 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2047 if (tracks.size() != how_many) {
2048 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2054 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2056 if (routes.size() != how_many) {
2057 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2064 display_insufficient_ports_message ();
2069 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2070 (*i)->set_strict_io (true);
2072 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2073 (*i)->set_strict_io (true);
2079 ARDOUR_UI::display_insufficient_ports_message ()
2081 MessageDialog msg (_main_window,
2082 string_compose (_("There are insufficient ports available\n\
2083 to create a new track or bus.\n\
2084 You should save %1, exit and\n\
2085 restart with more ports."), PROGRAM_NAME));
2086 pop_back_splash (msg);
2091 ARDOUR_UI::transport_goto_start ()
2094 _session->goto_start();
2096 /* force displayed area in editor to start no matter
2097 what "follow playhead" setting is.
2101 editor->center_screen (_session->current_start_frame ());
2107 ARDOUR_UI::transport_goto_zero ()
2110 _session->request_locate (0);
2112 /* force displayed area in editor to start no matter
2113 what "follow playhead" setting is.
2117 editor->reset_x_origin (0);
2123 ARDOUR_UI::transport_goto_wallclock ()
2125 if (_session && editor) {
2132 localtime_r (&now, &tmnow);
2134 framecnt_t frame_rate = _session->frame_rate();
2136 if (frame_rate == 0) {
2137 /* no frame rate available */
2141 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2142 frames += tmnow.tm_min * (60 * frame_rate);
2143 frames += tmnow.tm_sec * frame_rate;
2145 _session->request_locate (frames, _session->transport_rolling ());
2147 /* force displayed area in editor to start no matter
2148 what "follow playhead" setting is.
2152 editor->center_screen (frames);
2158 ARDOUR_UI::transport_goto_end ()
2161 framepos_t const frame = _session->current_end_frame();
2162 _session->request_locate (frame);
2164 /* force displayed area in editor to start no matter
2165 what "follow playhead" setting is.
2169 editor->center_screen (frame);
2175 ARDOUR_UI::transport_stop ()
2181 if (_session->is_auditioning()) {
2182 _session->cancel_audition ();
2186 _session->request_stop (false, true);
2189 /** Check if any tracks are record enabled. If none are, record enable all of them.
2190 * @return true if track record-enabled status was changed, false otherwise.
2193 ARDOUR_UI::trx_record_enable_all_tracks ()
2199 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2200 bool none_record_enabled = true;
2202 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2203 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2206 if (t->rec_enable_control()->get_value()) {
2207 none_record_enabled = false;
2212 if (none_record_enabled) {
2213 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2216 return none_record_enabled;
2220 ARDOUR_UI::transport_record (bool roll)
2223 switch (_session->record_status()) {
2224 case Session::Disabled:
2225 if (_session->ntracks() == 0) {
2226 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."));
2230 if (Profile->get_trx()) {
2231 roll = trx_record_enable_all_tracks ();
2233 _session->maybe_enable_record ();
2238 case Session::Recording:
2240 _session->request_stop();
2242 _session->disable_record (false, true);
2246 case Session::Enabled:
2247 _session->disable_record (false, true);
2253 ARDOUR_UI::transport_roll ()
2259 if (_session->is_auditioning()) {
2264 if (_session->config.get_external_sync()) {
2265 switch (Config->get_sync_source()) {
2269 /* transport controlled by the master */
2275 bool rolling = _session->transport_rolling();
2277 if (_session->get_play_loop()) {
2279 /* If loop playback is not a mode, then we should cancel
2280 it when this action is requested. If it is a mode
2281 we just leave it in place.
2284 if (!Config->get_loop_is_mode()) {
2285 /* XXX it is not possible to just leave seamless loop and keep
2286 playing at present (nov 4th 2009)
2288 if (!Config->get_seamless_loop()) {
2289 /* stop loop playback and stop rolling */
2290 _session->request_play_loop (false, true);
2291 } else if (rolling) {
2292 /* stop loop playback but keep rolling */
2293 _session->request_play_loop (false, false);
2297 } else if (_session->get_play_range () ) {
2298 /* stop playing a range if we currently are */
2299 _session->request_play_range (0, true);
2303 _session->request_transport_speed (1.0f);
2308 ARDOUR_UI::get_smart_mode() const
2310 return ( editor->get_smart_mode() );
2315 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2321 if (_session->is_auditioning()) {
2322 _session->cancel_audition ();
2326 if (_session->config.get_external_sync()) {
2327 switch (Config->get_sync_source()) {
2331 /* transport controlled by the master */
2336 bool rolling = _session->transport_rolling();
2337 bool affect_transport = true;
2339 if (rolling && roll_out_of_bounded_mode) {
2340 /* drop out of loop/range playback but leave transport rolling */
2341 if (_session->get_play_loop()) {
2342 if (_session->actively_recording()) {
2344 /* just stop using the loop, then actually stop
2347 _session->request_play_loop (false, affect_transport);
2350 if (Config->get_seamless_loop()) {
2351 /* the disk buffers contain copies of the loop - we can't
2352 just keep playing, so stop the transport. the user
2353 can restart as they wish.
2355 affect_transport = true;
2357 /* disk buffers are normal, so we can keep playing */
2358 affect_transport = false;
2360 _session->request_play_loop (false, affect_transport);
2362 } else if (_session->get_play_range ()) {
2363 affect_transport = false;
2364 _session->request_play_range (0, true);
2368 if (affect_transport) {
2370 _session->request_stop (with_abort, true);
2372 } else if (!with_abort) { /* with_abort == true means the
2373 * command was intended to stop
2374 * transport, not start.
2377 /* the only external sync condition we can be in here
2378 * would be Engine (JACK) sync, in which case we still
2382 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
2383 _session->request_play_range (&editor->get_selection().time, true);
2384 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2386 _session->request_transport_speed (1.0f);
2392 ARDOUR_UI::toggle_session_auto_loop ()
2398 Location * looploc = _session->locations()->auto_loop_location();
2404 if (_session->get_play_loop()) {
2406 /* looping enabled, our job is to disable it */
2408 _session->request_play_loop (false);
2412 /* looping not enabled, our job is to enable it.
2414 loop-is-NOT-mode: this action always starts the transport rolling.
2415 loop-IS-mode: this action simply sets the loop play mechanism, but
2416 does not start transport.
2418 if (Config->get_loop_is_mode()) {
2419 _session->request_play_loop (true, false);
2421 _session->request_play_loop (true, true);
2425 //show the loop markers
2426 looploc->set_hidden (false, this);
2430 ARDOUR_UI::transport_play_selection ()
2436 editor->play_selection ();
2440 ARDOUR_UI::transport_play_preroll ()
2445 editor->play_with_preroll ();
2449 ARDOUR_UI::transport_rec_preroll ()
2454 editor->rec_with_preroll ();
2458 ARDOUR_UI::transport_rec_count_in ()
2463 editor->rec_with_count_in ();
2467 ARDOUR_UI::transport_rewind (int option)
2469 float current_transport_speed;
2472 current_transport_speed = _session->transport_speed();
2474 if (current_transport_speed >= 0.0f) {
2477 _session->request_transport_speed (-1.0f);
2480 _session->request_transport_speed (-4.0f);
2483 _session->request_transport_speed (-0.5f);
2488 _session->request_transport_speed (current_transport_speed * 1.5f);
2494 ARDOUR_UI::transport_forward (int option)
2500 float current_transport_speed = _session->transport_speed();
2502 if (current_transport_speed <= 0.0f) {
2505 _session->request_transport_speed (1.0f);
2508 _session->request_transport_speed (4.0f);
2511 _session->request_transport_speed (0.5f);
2516 _session->request_transport_speed (current_transport_speed * 1.5f);
2521 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2527 boost::shared_ptr<Route> r;
2529 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2531 boost::shared_ptr<Track> t;
2533 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2534 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2540 ARDOUR_UI::map_transport_state ()
2543 auto_loop_button.unset_active_state ();
2544 play_selection_button.unset_active_state ();
2545 roll_button.unset_active_state ();
2546 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2547 layered_button.set_sensitive (false);
2551 shuttle_box.map_transport_state ();
2553 float sp = _session->transport_speed();
2559 if (_session->get_play_range()) {
2561 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2562 roll_button.unset_active_state ();
2563 auto_loop_button.unset_active_state ();
2565 } else if (_session->get_play_loop ()) {
2567 auto_loop_button.set_active (true);
2568 play_selection_button.set_active (false);
2569 if (Config->get_loop_is_mode()) {
2570 roll_button.set_active (true);
2572 roll_button.set_active (false);
2577 roll_button.set_active (true);
2578 play_selection_button.set_active (false);
2579 auto_loop_button.set_active (false);
2582 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2583 /* light up both roll and play-selection if they are joined */
2584 roll_button.set_active (true);
2585 play_selection_button.set_active (true);
2587 layered_button.set_sensitive (!_session->actively_recording ());
2589 stop_button.set_active (false);
2593 layered_button.set_sensitive (true);
2594 stop_button.set_active (true);
2595 roll_button.set_active (false);
2596 play_selection_button.set_active (false);
2597 if (Config->get_loop_is_mode ()) {
2598 auto_loop_button.set_active (_session->get_play_loop());
2600 auto_loop_button.set_active (false);
2602 update_disk_space ();
2607 ARDOUR_UI::blink_handler (bool blink_on)
2609 transport_rec_enable_blink (blink_on);
2610 sync_blink (blink_on);
2612 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2615 error_blink (blink_on);
2616 solo_blink (blink_on);
2617 audition_blink (blink_on);
2618 feedback_blink (blink_on);
2622 ARDOUR_UI::update_clocks ()
2624 if (!_session) return;
2626 if (editor && !editor->dragging_playhead()) {
2627 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2632 ARDOUR_UI::start_clocking ()
2634 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2635 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2637 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2642 ARDOUR_UI::stop_clocking ()
2644 clock_signal_connection.disconnect ();
2648 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2652 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2654 label->set_text (buf);
2655 bar->set_fraction (fraction);
2657 /* process events, redraws, etc. */
2659 while (gtk_events_pending()) {
2660 gtk_main_iteration ();
2663 return true; /* continue with save-as */
2667 ARDOUR_UI::save_session_as ()
2673 if (!save_as_dialog) {
2674 save_as_dialog = new SaveAsDialog;
2677 save_as_dialog->set_name (_session->name());
2679 int response = save_as_dialog->run ();
2681 save_as_dialog->hide ();
2684 case Gtk::RESPONSE_OK:
2693 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2694 sa.new_name = save_as_dialog->new_name ();
2695 sa.switch_to = save_as_dialog->switch_to();
2696 sa.copy_media = save_as_dialog->copy_media();
2697 sa.copy_external = save_as_dialog->copy_external();
2698 sa.include_media = save_as_dialog->include_media ();
2700 /* Only bother with a progress dialog if we're going to copy
2701 media into the save-as target. Without that choice, this
2702 will be very fast because we're only talking about a few kB's to
2703 perhaps a couple of MB's of data.
2706 ArdourDialog progress_dialog (_("Save As"), true);
2709 if (sa.include_media && sa.copy_media) {
2711 Gtk::Label* label = manage (new Gtk::Label());
2712 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2714 progress_dialog.get_vbox()->pack_start (*label);
2715 progress_dialog.get_vbox()->pack_start (*progress_bar);
2717 progress_bar->show ();
2719 /* this signal will be emitted from within this, the calling thread,
2720 * after every file is copied. It provides information on percentage
2721 * complete (in terms of total data to copy), the number of files
2722 * 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);
5298 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5300 using namespace Menu_Helpers;
5302 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5303 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5304 i->set_active (editor_meter->meter_type () == type);
5308 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5310 using namespace Gtk::Menu_Helpers;
5312 Gtk::Menu* m = manage (new Menu);
5313 MenuList& items = m->items ();
5315 RadioMenuItem::Group group;
5317 _suspend_editor_meter_callbacks = true;
5318 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5319 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5320 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5321 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5322 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5323 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5324 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5325 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5326 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5327 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5328 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5330 m->popup (ev->button, ev->time);
5331 _suspend_editor_meter_callbacks = false;
5335 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5337 if (ev->button == 3 && editor_meter) {
5338 popup_editor_meter_menu (ev);
5345 ARDOUR_UI::reset_peak_display ()
5347 if (!_session || !_session->master_out() || !editor_meter) return;
5348 editor_meter->clear_meters();
5349 editor_meter_max_peak = -INFINITY;
5350 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5354 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5356 if (!_session || !_session->master_out()) return;
5357 if (group == _session->master_out()->route_group()) {
5358 reset_peak_display ();
5363 ARDOUR_UI::reset_route_peak_display (Route* route)
5365 if (!_session || !_session->master_out()) return;
5366 if (_session->master_out().get() == route) {
5367 reset_peak_display ();
5372 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5374 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5375 audio_midi_setup->set_position (WIN_POS_CENTER);
5377 if (desired_sample_rate != 0) {
5378 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5379 audio_midi_setup->try_autostart ();
5380 if (ARDOUR::AudioEngine::instance()->running()) {
5387 int response = audio_midi_setup->run();
5388 printf("RESPONSE %d\n", response);
5390 case Gtk::RESPONSE_DELETE_EVENT:
5393 if (!AudioEngine::instance()->running()) {
5396 audio_midi_setup->hide ();
5404 ARDOUR_UI::transport_numpad_timeout ()
5406 _numpad_locate_happening = false;
5407 if (_numpad_timeout_connection.connected() )
5408 _numpad_timeout_connection.disconnect();
5413 ARDOUR_UI::transport_numpad_decimal ()
5415 _numpad_timeout_connection.disconnect();
5417 if (_numpad_locate_happening) {
5418 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5419 _numpad_locate_happening = false;
5421 _pending_locate_num = 0;
5422 _numpad_locate_happening = true;
5423 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5428 ARDOUR_UI::transport_numpad_event (int num)
5430 if ( _numpad_locate_happening ) {
5431 _pending_locate_num = _pending_locate_num*10 + num;
5434 case 0: toggle_roll(false, false); break;
5435 case 1: transport_rewind(1); break;
5436 case 2: transport_forward(1); break;
5437 case 3: transport_record(true); break;
5438 case 4: toggle_session_auto_loop(); break;
5439 case 5: transport_record(false); toggle_session_auto_loop(); break;
5440 case 6: toggle_punch(); break;
5441 case 7: toggle_click(); break;
5442 case 8: toggle_auto_return(); break;
5443 case 9: toggle_follow_edits(); break;
5449 ARDOUR_UI::set_flat_buttons ()
5451 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5455 ARDOUR_UI::audioengine_became_silent ()
5457 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5459 Gtk::MESSAGE_WARNING,
5463 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5465 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5466 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5467 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5468 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5469 Gtk::HBox pay_button_box;
5470 Gtk::HBox subscribe_button_box;
5472 pay_button_box.pack_start (pay_button, true, false);
5473 subscribe_button_box.pack_start (subscribe_button, true, false);
5475 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 */
5477 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5478 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5480 msg.get_vbox()->pack_start (pay_label);
5481 msg.get_vbox()->pack_start (pay_button_box);
5482 msg.get_vbox()->pack_start (subscribe_label);
5483 msg.get_vbox()->pack_start (subscribe_button_box);
5485 msg.get_vbox()->show_all ();
5487 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5488 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5489 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5494 case Gtk::RESPONSE_YES:
5495 AudioEngine::instance()->reset_silence_countdown ();
5498 case Gtk::RESPONSE_NO:
5500 save_state_canfail ("");
5504 case Gtk::RESPONSE_CANCEL:
5506 /* don't reset, save session and exit */
5512 ARDOUR_UI::hide_application ()
5514 Application::instance ()-> hide ();
5518 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5520 /* icons, titles, WM stuff */
5522 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5524 if (window_icons.empty()) {
5525 Glib::RefPtr<Gdk::Pixbuf> icon;
5526 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5527 window_icons.push_back (icon);
5529 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5530 window_icons.push_back (icon);
5532 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5533 window_icons.push_back (icon);
5535 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5536 window_icons.push_back (icon);
5540 if (!window_icons.empty()) {
5541 window.set_default_icon_list (window_icons);
5544 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5546 if (!name.empty()) {
5550 window.set_title (title.get_string());
5551 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5553 window.set_flags (CAN_FOCUS);
5554 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5556 /* This is a hack to ensure that GTK-accelerators continue to
5557 * work. Once we switch over to entirely native bindings, this will be
5558 * unnecessary and should be removed
5560 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5562 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5563 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5564 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5565 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5569 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5571 Gtkmm2ext::Bindings* bindings = 0;
5572 Gtk::Window* window = 0;
5574 /* until we get ardour bindings working, we are not handling key
5578 if (ev->type != GDK_KEY_PRESS) {
5582 if (event_window == &_main_window) {
5584 window = event_window;
5586 /* find current tab contents */
5588 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5590 /* see if it uses the ardour binding system */
5593 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5596 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5600 window = event_window;
5602 /* see if window uses ardour binding system */
5604 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5607 /* An empty binding set is treated as if it doesn't exist */
5609 if (bindings && bindings->empty()) {
5613 return key_press_focus_accelerator_handler (*window, ev, bindings);
5616 static Gtkmm2ext::Bindings*
5617 get_bindings_from_widget_heirarchy (GtkWidget** w)
5622 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5625 *w = gtk_widget_get_parent (*w);
5628 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5632 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5634 GtkWindow* win = window.gobj();
5635 GtkWidget* focus = gtk_window_get_focus (win);
5636 GtkWidget* binding_widget = focus;
5637 bool special_handling_of_unmodified_accelerators = false;
5638 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5642 /* some widget has keyboard focus */
5644 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5646 /* A particular kind of focusable widget currently has keyboard
5647 * focus. All unmodified key events should go to that widget
5648 * first and not be used as an accelerator by default
5651 special_handling_of_unmodified_accelerators = true;
5655 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5656 if (focus_bindings) {
5657 bindings = focus_bindings;
5658 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5663 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",
5666 Gtkmm2ext::show_gdk_event_state (ev->state),
5667 special_handling_of_unmodified_accelerators,
5668 Keyboard::some_magic_widget_has_focus(),
5670 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5671 ((ev->state & mask) ? "yes" : "no"),
5672 window.get_title()));
5674 /* This exists to allow us to override the way GTK handles
5675 key events. The normal sequence is:
5677 a) event is delivered to a GtkWindow
5678 b) accelerators/mnemonics are activated
5679 c) if (b) didn't handle the event, propagate to
5680 the focus widget and/or focus chain
5682 The problem with this is that if the accelerators include
5683 keys without modifiers, such as the space bar or the
5684 letter "e", then pressing the key while typing into
5685 a text entry widget results in the accelerator being
5686 activated, instead of the desired letter appearing
5689 There is no good way of fixing this, but this
5690 represents a compromise. The idea is that
5691 key events involving modifiers (not Shift)
5692 get routed into the activation pathway first, then
5693 get propagated to the focus widget if necessary.
5695 If the key event doesn't involve modifiers,
5696 we deliver to the focus widget first, thus allowing
5697 it to get "normal text" without interference
5700 Of course, this can also be problematic: if there
5701 is a widget with focus, then it will swallow
5702 all "normal text" accelerators.
5706 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5708 /* no special handling or there are modifiers in effect: accelerate first */
5710 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5711 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5712 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5714 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5715 KeyboardKey k (ev->state, ev->keyval);
5719 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5721 if (bindings->activate (k, Bindings::Press)) {
5722 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5726 if (binding_widget) {
5727 binding_widget = gtk_widget_get_parent (binding_widget);
5728 if (binding_widget) {
5729 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5738 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5740 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5741 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5745 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5747 if (gtk_window_propagate_key_event (win, ev)) {
5748 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5754 /* no modifiers, propagate first */
5756 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5758 if (gtk_window_propagate_key_event (win, ev)) {
5759 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5763 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5764 KeyboardKey k (ev->state, ev->keyval);
5768 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5771 if (bindings->activate (k, Bindings::Press)) {
5772 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5776 if (binding_widget) {
5777 binding_widget = gtk_widget_get_parent (binding_widget);
5778 if (binding_widget) {
5779 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5788 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5790 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5791 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5796 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5801 ARDOUR_UI::load_bindings ()
5803 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5804 error << _("Global keybindings are missing") << endmsg;
5809 ARDOUR_UI::cancel_solo ()
5812 _session->cancel_all_solo ();
5817 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5819 /* this resets focus to the first focusable parent of the given widget,
5820 * or, if there is no focusable parent, cancels focus in the toplevel
5821 * window that the given widget is packed into (if there is one).
5828 Gtk::Widget* top = w->get_toplevel();
5830 if (!top || !top->is_toplevel()) {
5834 w = w->get_parent ();
5838 if (w->is_toplevel()) {
5839 /* Setting the focus widget to a Gtk::Window causes all
5840 * subsequent calls to ::has_focus() on the nominal
5841 * focus widget in that window to return
5842 * false. Workaround: never set focus to the toplevel
5848 if (w->get_can_focus ()) {
5849 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5850 win->set_focus (*w);
5853 w = w->get_parent ();
5856 if (top == &_main_window) {
5860 /* no focusable parent found, cancel focus in top level window.
5861 C++ API cannot be used for this. Thanks, references.
5864 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);