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/types_convert.h"
65 #include "pbd/file_utils.h"
66 #include "pbd/localtime_r.h"
67 #include "pbd/pthread_utils.h"
68 #include "pbd/replace_all.h"
69 #include "pbd/scoped_file_descriptor.h"
70 #include "pbd/xml++.h"
72 #include "gtkmm2ext/application.h"
73 #include "gtkmm2ext/bindings.h"
74 #include "gtkmm2ext/gtk_ui.h"
75 #include "gtkmm2ext/utils.h"
76 #include "gtkmm2ext/click_box.h"
77 #include "gtkmm2ext/fastmeter.h"
78 #include "gtkmm2ext/popup.h"
79 #include "gtkmm2ext/window_title.h"
81 #include "ardour/ardour.h"
82 #include "ardour/audio_backend.h"
83 #include "ardour/audio_track.h"
84 #include "ardour/audioengine.h"
85 #include "ardour/audiofilesource.h"
86 #include "ardour/automation_watch.h"
87 #include "ardour/diskstream.h"
88 #include "ardour/filename_extensions.h"
89 #include "ardour/filesystem_paths.h"
90 #include "ardour/ltc_file_reader.h"
91 #include "ardour/midi_track.h"
92 #include "ardour/port.h"
93 #include "ardour/plugin_manager.h"
94 #include "ardour/process_thread.h"
95 #include "ardour/profile.h"
96 #include "ardour/recent_sessions.h"
97 #include "ardour/record_enable_control.h"
98 #include "ardour/revision.h"
99 #include "ardour/session_directory.h"
100 #include "ardour/session_route.h"
101 #include "ardour/session_state_utils.h"
102 #include "ardour/session_utils.h"
103 #include "ardour/source_factory.h"
104 #include "ardour/slave.h"
105 #include "ardour/system_exec.h"
106 #include "ardour/track.h"
107 #include "ardour/vca_manager.h"
108 #include "ardour/utils.h"
110 #include "LuaBridge/LuaBridge.h"
112 #ifdef WINDOWS_VST_SUPPORT
115 #ifdef AUDIOUNIT_SUPPORT
116 #include "ardour/audio_unit.h"
119 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
124 #include "timecode/time.h"
126 typedef uint64_t microseconds_t;
130 #include "enums_convert.h"
132 #include "add_route_dialog.h"
133 #include "ambiguous_file_dialog.h"
134 #include "ardour_ui.h"
135 #include "audio_clock.h"
136 #include "audio_region_view.h"
137 #include "big_clock_window.h"
138 #include "bundle_manager.h"
139 #include "duplicate_routes_dialog.h"
141 #include "engine_dialog.h"
142 #include "export_video_dialog.h"
143 #include "export_video_infobox.h"
144 #include "gain_meter.h"
145 #include "global_port_matrix.h"
146 #include "gui_object.h"
147 #include "gui_thread.h"
148 #include "idleometer.h"
149 #include "keyboard.h"
150 #include "keyeditor.h"
151 #include "location_ui.h"
152 #include "lua_script_manager.h"
153 #include "luawindow.h"
154 #include "main_clock.h"
155 #include "missing_file_dialog.h"
156 #include "missing_plugin_dialog.h"
157 #include "mixer_ui.h"
158 #include "meterbridge.h"
159 #include "meter_patterns.h"
160 #include "mouse_cursors.h"
163 #include "pingback.h"
164 #include "processor_box.h"
165 #include "prompter.h"
166 #include "public_editor.h"
167 #include "rc_option_editor.h"
168 #include "route_time_axis.h"
169 #include "route_params_ui.h"
170 #include "save_as_dialog.h"
171 #include "script_selector.h"
172 #include "session_archive_dialog.h"
173 #include "session_dialog.h"
174 #include "session_metadata_dialog.h"
175 #include "session_option_editor.h"
176 #include "speaker_dialog.h"
179 #include "time_axis_view_item.h"
180 #include "time_info_box.h"
183 #include "utils_videotl.h"
184 #include "video_server_dialog.h"
185 #include "add_video_dialog.h"
186 #include "transcode_video_dialog.h"
188 #include "pbd/i18n.h"
190 using namespace ARDOUR;
191 using namespace ARDOUR_UI_UTILS;
193 using namespace Gtkmm2ext;
196 using namespace Editing;
198 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
200 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
201 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
204 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
206 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
207 "Would you like these files to be copied and used for %1 %2.x?\n\n"
208 "(This will require you to restart %1.)"),
209 PROGRAM_NAME, PROGRAM_VERSION, version),
210 false, /* no markup */
213 true /* modal, though it hardly matters since it is the only window */
216 msg.set_default_response (Gtk::RESPONSE_YES);
219 return (msg.run() == Gtk::RESPONSE_YES);
223 libxml_generic_error_func (void* /* parsing_context*/,
231 vsnprintf (buf, sizeof (buf), msg, ap);
232 error << buf << endmsg;
237 libxml_structured_error_func (void* /* parsing_context*/,
245 replace_all (msg, "\n", "");
248 if (err->file && err->line) {
249 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
252 error << ':' << err->int2;
257 error << X_("XML error: ") << msg << endmsg;
263 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
264 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
265 , session_loaded (false)
266 , gui_object_state (new GUIObjectState)
267 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
268 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
269 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
271 , global_actions (X_("global"))
272 , ignore_dual_punch (false)
273 , main_window_visibility (0)
278 , _mixer_on_top (false)
279 , _initial_verbose_plugin_scan (false)
280 , first_time_engine_run (true)
281 , secondary_clock_spacer (0)
282 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
283 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
284 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
285 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
286 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
287 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
288 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
289 , auto_input_button (ArdourButton::led_default_elements)
291 , auto_return_button (ArdourButton::led_default_elements)
292 , follow_edits_button (ArdourButton::led_default_elements)
293 , auditioning_alert_button (_("Audition"))
294 , solo_alert_button (_("Solo"))
295 , feedback_alert_button (_("Feedback"))
296 , error_alert_button ( ArdourButton::just_led_default_elements )
298 , editor_meter_peak_display()
299 , _suspend_editor_meter_callbacks (false)
300 , _numpad_locate_happening (false)
301 , _session_is_new (false)
302 , last_key_press_time (0)
306 , rc_option_editor (0)
307 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
308 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
309 , about (X_("about"), _("About"))
310 , location_ui (X_("locations"), S_("Ranges|Locations"))
311 , route_params (X_("inspector"), _("Tracks and Busses"))
312 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
313 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
314 , lua_script_window (X_("script-manager"), _("Script Manager"))
315 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
316 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
317 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
318 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
319 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
320 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
321 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
322 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
323 , video_server_process (0)
325 , have_configure_timeout (false)
326 , last_configure_time (0)
328 , have_disk_speed_dialog_displayed (false)
329 , _status_bar_visibility (X_("status-bar"))
330 , _feedback_exists (false)
331 , _log_not_acknowledged (LogLevelNone)
332 , duplicate_routes_dialog (0)
333 , editor_visibility_button (S_("Window|Editor"))
334 , mixer_visibility_button (S_("Window|Mixer"))
335 , prefs_visibility_button (S_("Window|Preferences"))
337 Gtkmm2ext::init (localedir);
339 UIConfiguration::instance().post_gui_init ();
341 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
343 /* "touch" the been-here-before path now that config has been migrated */
344 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
346 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
348 /* configuration was modified, exit immediately */
353 if (string (VERSIONSTRING).find (".pre") != string::npos) {
354 /* check this is not being run from ./ardev etc. */
355 if (!running_from_source_tree ()) {
356 pre_release_dialog ();
360 if (theArdourUI == 0) {
364 /* track main window visibility */
366 main_window_visibility = new VisibilityTracker (_main_window);
368 /* stop libxml from spewing to stdout/stderr */
370 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
371 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
373 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
374 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
375 UIConfiguration::instance().map_parameters (pc);
377 roll_button.set_controllable (roll_controllable);
378 stop_button.set_controllable (stop_controllable);
379 goto_start_button.set_controllable (goto_start_controllable);
380 goto_end_button.set_controllable (goto_end_controllable);
381 auto_loop_button.set_controllable (auto_loop_controllable);
382 play_selection_button.set_controllable (play_selection_controllable);
383 rec_button.set_controllable (rec_controllable);
385 roll_button.set_name ("transport button");
386 stop_button.set_name ("transport button");
387 goto_start_button.set_name ("transport button");
388 goto_end_button.set_name ("transport button");
389 auto_loop_button.set_name ("transport button");
390 play_selection_button.set_name ("transport button");
391 rec_button.set_name ("transport recenable button");
392 midi_panic_button.set_name ("transport button");
394 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
395 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
397 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
399 /* handle dialog requests */
401 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
403 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
405 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
407 /* handle Audio/MIDI setup when session requires it */
409 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
411 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
413 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
415 /* handle sr mismatch with a dialog - cross-thread from engine */
416 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
418 /* handle requests to quit (coming from JACK session) */
420 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
422 /* tell the user about feedback */
424 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
425 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
427 /* handle requests to deal with missing files */
429 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
431 /* and ambiguous files */
433 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
435 /* also plugin scan messages */
436 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
437 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
439 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
441 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
444 /* lets get this party started */
446 setup_gtk_ardour_enums ();
449 SessionEvent::create_per_thread_pool ("GUI", 4096);
451 /* we like keyboards */
453 keyboard = new ArdourKeyboard(*this);
455 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
457 keyboard->set_state (*node, Stateful::loading_state_version);
460 UIConfiguration::instance().reset_dpi ();
462 TimeAxisViewItem::set_constant_heights ();
464 /* Set this up so that our window proxies can register actions */
466 ActionManager::init ();
468 /* The following must happen after ARDOUR::init() so that Config is set up */
470 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
473 key_editor.set_state (*ui_xml, 0);
474 session_option_editor.set_state (*ui_xml, 0);
475 speaker_config_window.set_state (*ui_xml, 0);
476 about.set_state (*ui_xml, 0);
477 add_route_dialog.set_state (*ui_xml, 0);
478 add_video_dialog.set_state (*ui_xml, 0);
479 route_params.set_state (*ui_xml, 0);
480 bundle_manager.set_state (*ui_xml, 0);
481 location_ui.set_state (*ui_xml, 0);
482 big_clock_window.set_state (*ui_xml, 0);
483 audio_port_matrix.set_state (*ui_xml, 0);
484 midi_port_matrix.set_state (*ui_xml, 0);
485 export_video_dialog.set_state (*ui_xml, 0);
486 lua_script_window.set_state (*ui_xml, 0);
487 idleometer.set_state (*ui_xml, 0);
490 /* Separate windows */
492 WM::Manager::instance().register_window (&key_editor);
493 WM::Manager::instance().register_window (&session_option_editor);
494 WM::Manager::instance().register_window (&speaker_config_window);
495 WM::Manager::instance().register_window (&about);
496 WM::Manager::instance().register_window (&add_route_dialog);
497 WM::Manager::instance().register_window (&add_video_dialog);
498 WM::Manager::instance().register_window (&route_params);
499 WM::Manager::instance().register_window (&audio_midi_setup);
500 WM::Manager::instance().register_window (&export_video_dialog);
501 WM::Manager::instance().register_window (&lua_script_window);
502 WM::Manager::instance().register_window (&bundle_manager);
503 WM::Manager::instance().register_window (&location_ui);
504 WM::Manager::instance().register_window (&big_clock_window);
505 WM::Manager::instance().register_window (&audio_port_matrix);
506 WM::Manager::instance().register_window (&midi_port_matrix);
507 WM::Manager::instance().register_window (&idleometer);
509 /* do not retain position for add route dialog */
510 add_route_dialog.set_state_mask (WindowProxy::Size);
512 /* Trigger setting up the color scheme and loading the GTK RC file */
514 UIConfiguration::instance().load_rc_file (false);
516 _process_thread = new ProcessThread ();
517 _process_thread->init ();
519 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
525 ARDOUR_UI::pre_release_dialog ()
527 ArdourDialog d (_("Pre-Release Warning"), true, false);
528 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
530 Label* label = manage (new Label);
531 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
532 There are still several issues and bugs to be worked on,\n\
533 as well as general workflow improvements, before this can be considered\n\
534 release software. So, a few guidelines:\n\
536 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
537 though it may be so, depending on your workflow.\n\
538 2) Please wait for a helpful writeup of new features.\n\
539 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
540 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
541 making sure to note the product version number as 5.0-pre.\n\
542 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
543 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
544 can get there directly from within the program via the Help->Chat menu option.\n\
546 Full information on all the above can be found on the support page at\n\
548 http://ardour.org/support\n\
549 "), PROGRAM_NAME, VERSIONSTRING));
551 d.get_vbox()->set_border_width (12);
552 d.get_vbox()->pack_start (*label, false, false, 12);
553 d.get_vbox()->show_all ();
558 GlobalPortMatrixWindow*
559 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
564 return new GlobalPortMatrixWindow (_session, type);
568 ARDOUR_UI::attach_to_engine ()
570 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
571 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
575 ARDOUR_UI::engine_stopped ()
577 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
578 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
579 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
580 update_sample_rate (0);
585 ARDOUR_UI::engine_running ()
587 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
588 if (first_time_engine_run) {
590 first_time_engine_run = false;
594 _session->reset_xrun_count ();
596 update_disk_space ();
598 update_xrun_count ();
599 update_sample_rate (AudioEngine::instance()->sample_rate());
600 update_timecode_format ();
601 update_peak_thread_work ();
602 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
603 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
607 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
609 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
610 /* we can't rely on the original string continuing to exist when we are called
611 again in the GUI thread, so make a copy and note that we need to
614 char *copy = strdup (reason);
615 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
619 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
620 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
622 update_sample_rate (0);
626 /* if the reason is a non-empty string, it means that the backend was shutdown
627 rather than just Ardour.
630 if (strlen (reason)) {
631 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
633 msgstr = string_compose (_("\
634 The audio backend has either been shutdown or it\n\
635 disconnected %1 because %1\n\
636 was not fast enough. Try to restart\n\
637 the audio backend and save the session."), PROGRAM_NAME);
640 MessageDialog msg (_main_window, msgstr);
641 pop_back_splash (msg);
645 free (const_cast<char*> (reason));
650 ARDOUR_UI::post_engine ()
652 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
654 #ifdef AUDIOUNIT_SUPPORT
656 if (AUPluginInfo::au_get_crashlog(au_msg)) {
657 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
658 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
659 info << au_msg << endmsg;
663 ARDOUR::init_post_engine ();
665 /* connect to important signals */
667 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
668 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
669 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
670 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
671 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
673 if (setup_windows ()) {
674 throw failed_constructor ();
677 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
678 XMLNode* n = Config->extra_xml (X_("UI"));
680 _status_bar_visibility.set_state (*n);
683 check_memory_locking();
685 /* this is the first point at which all the possible actions are
686 * available, because some of the available actions are dependent on
687 * aspects of the engine/backend.
690 if (ARDOUR_COMMAND_LINE::show_key_actions) {
692 Bindings::save_all_bindings_as_html (sstr);
694 if (sstr.str().empty()) {
701 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
703 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
709 #ifdef PLATFORM_WINDOWS
715 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
716 #ifndef PLATFORM_WINDOWS
719 g_unlink (file_name);
721 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
727 #ifndef PLATFORM_WINDOWS
731 PBD::open_uri (string_compose ("file:///%1", file_name));
733 halt_connection.disconnect ();
734 AudioEngine::instance()->stop ();
739 if (ARDOUR_COMMAND_LINE::show_actions) {
742 vector<string> paths;
743 vector<string> labels;
744 vector<string> tooltips;
746 vector<Glib::RefPtr<Gtk::Action> > actions;
747 string ver_in = revision;
748 string ver = ver_in.substr(0, ver_in.find("-"));
751 output << "\n<h2>Menu actions</h2>" << endl;
752 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
753 output << " surfaces or scripts.\n</p>\n" << endl;
754 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
755 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
756 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
757 output << "<table class=\"dl\">\n <thead>" << endl;
758 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
759 output << " </thead>\n <tbody>" << endl;
761 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
763 vector<string>::iterator p;
764 vector<string>::iterator l;
766 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
767 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
768 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
770 output << " </tbody>\n </table>" << endl;
772 // output this mess to a browser for easiest X-platform use
773 // it is not pretty HTML, but it works and it's main purpose
774 // is to create raw html to fit in Ardour's manual with no editing
779 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
781 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
787 #ifdef PLATFORM_WINDOWS
793 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
794 #ifndef PLATFORM_WINDOWS
797 g_unlink (file_name);
799 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
805 #ifndef PLATFORM_WINDOWS
809 PBD::open_uri (string_compose ("file:///%1", file_name));
811 halt_connection.disconnect ();
812 AudioEngine::instance()->stop ();
816 /* this being a GUI and all, we want peakfiles */
818 AudioFileSource::set_build_peakfiles (true);
819 AudioFileSource::set_build_missing_peakfiles (true);
821 /* set default clock modes */
823 primary_clock->set_mode (AudioClock::Timecode);
824 secondary_clock->set_mode (AudioClock::BBT);
826 /* start the time-of-day-clock */
829 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
830 update_wall_clock ();
831 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
836 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
837 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
838 Config->map_parameters (pc);
840 UIConfiguration::instance().map_parameters (pc);
844 ARDOUR_UI::~ARDOUR_UI ()
846 UIConfiguration::instance().save_state();
850 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
851 // don't bother at 'real' exit. the OS cleans up for us.
852 delete big_clock; big_clock = 0;
853 delete primary_clock; primary_clock = 0;
854 delete secondary_clock; secondary_clock = 0;
855 delete _process_thread; _process_thread = 0;
856 delete time_info_box; time_info_box = 0;
857 delete meterbridge; meterbridge = 0;
858 delete luawindow; luawindow = 0;
859 delete editor; editor = 0;
860 delete mixer; mixer = 0;
861 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
863 delete gui_object_state; gui_object_state = 0;
864 delete main_window_visibility;
865 FastMeter::flush_pattern_cache ();
866 PixFader::flush_pattern_cache ();
870 /* Small trick to flush main-thread event pool.
871 * Other thread-pools are destroyed at pthread_exit(),
872 * but tmain thread termination is too late to trigger Pool::~Pool()
874 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.
875 delete ev->event_pool();
880 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
882 if (Splash::instance()) {
883 Splash::instance()->pop_back_for (win);
888 ARDOUR_UI::configure_timeout ()
890 if (last_configure_time == 0) {
891 /* no configure events yet */
895 /* force a gap of 0.5 seconds since the last configure event
898 if (get_microseconds() - last_configure_time < 500000) {
901 have_configure_timeout = false;
902 save_ardour_state ();
908 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
910 if (have_configure_timeout) {
911 last_configure_time = get_microseconds();
913 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
914 have_configure_timeout = true;
921 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
925 if (node.get_property ("roll", str)){
926 roll_controllable->set_id (str);
928 if (node.get_property ("stop", str)) {
929 stop_controllable->set_id (str);
931 if (node.get_property ("goto-start", str)) {
932 goto_start_controllable->set_id (str);
934 if (node.get_property ("goto-end", str)) {
935 goto_end_controllable->set_id (str);
937 if (node.get_property ("auto-loop", str)) {
938 auto_loop_controllable->set_id (str);
940 if (node.get_property ("play-selection", str)) {
941 play_selection_controllable->set_id (str);
943 if (node.get_property ("rec", str)) {
944 rec_controllable->set_id (str);
946 if (node.get_property ("shuttle", str)) {
947 shuttle_box.controllable()->set_id (str);
952 ARDOUR_UI::get_transport_controllable_state ()
954 XMLNode* node = new XMLNode(X_("TransportControllables"));
956 node->set_property (X_("roll"), roll_controllable->id());
957 node->set_property (X_("stop"), stop_controllable->id());
958 node->set_property (X_("goto-start"), goto_start_controllable->id());
959 node->set_property (X_("goto-end"), goto_end_controllable->id());
960 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
961 node->set_property (X_("play-selection"), play_selection_controllable->id());
962 node->set_property (X_("rec"), rec_controllable->id());
963 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
969 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
972 _session->save_state (snapshot_name);
977 ARDOUR_UI::autosave_session ()
979 if (g_main_depth() > 1) {
980 /* inside a recursive main loop,
981 give up because we may not be able to
987 if (!Config->get_periodic_safety_backups()) {
992 _session->maybe_write_autosave();
999 ARDOUR_UI::session_dirty_changed ()
1006 ARDOUR_UI::update_autosave ()
1008 if (_session && _session->dirty()) {
1009 if (_autosave_connection.connected()) {
1010 _autosave_connection.disconnect();
1013 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1014 Config->get_periodic_safety_backup_interval() * 1000);
1017 if (_autosave_connection.connected()) {
1018 _autosave_connection.disconnect();
1024 ARDOUR_UI::check_announcements ()
1027 string _annc_filename;
1030 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1031 #elif defined PLATFORM_WINDOWS
1032 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1034 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1036 _annc_filename.append (VERSIONSTRING);
1038 _announce_string = "";
1040 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1041 FILE* fin = g_fopen (path.c_str(), "rb");
1043 while (!feof (fin)) {
1046 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1049 _announce_string.append (tmp, len);
1054 pingback (VERSIONSTRING, path);
1059 _hide_splash (gpointer arg)
1061 ((ARDOUR_UI*)arg)->hide_splash();
1066 ARDOUR_UI::starting ()
1068 Application* app = Application::instance ();
1069 const char *nsm_url;
1070 bool brand_new_user = ArdourStartup::required ();
1072 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1073 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1075 if (ARDOUR_COMMAND_LINE::check_announcements) {
1076 check_announcements ();
1081 /* we need to create this early because it may need to set the
1082 * audio backend end up.
1086 audio_midi_setup.get (true);
1088 std::cerr << "audio-midi engine setup failed."<< std::endl;
1092 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1093 nsm = new NSM_Client;
1094 if (!nsm->init (nsm_url)) {
1095 /* the ardour executable may have different names:
1097 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1098 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1099 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1101 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1103 const char *process_name = g_getenv ("ARDOUR_SELF");
1104 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1107 // wait for announce reply from nsm server
1108 for ( i = 0; i < 5000; ++i) {
1112 if (nsm->is_active()) {
1117 error << _("NSM server did not announce itself") << endmsg;
1120 // wait for open command from nsm server
1121 for ( i = 0; i < 5000; ++i) {
1123 Glib::usleep (1000);
1124 if (nsm->client_id ()) {
1130 error << _("NSM: no client ID provided") << endmsg;
1134 if (_session && nsm) {
1135 _session->set_nsm_state( nsm->is_active() );
1137 error << _("NSM: no session created") << endmsg;
1141 // nsm requires these actions disabled
1142 vector<string> action_names;
1143 action_names.push_back("SaveAs");
1144 action_names.push_back("Rename");
1145 action_names.push_back("New");
1146 action_names.push_back("Open");
1147 action_names.push_back("Recent");
1148 action_names.push_back("Close");
1150 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1151 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1153 act->set_sensitive (false);
1160 error << _("NSM: initialization failed") << endmsg;
1166 if (brand_new_user) {
1167 _initial_verbose_plugin_scan = true;
1172 _initial_verbose_plugin_scan = false;
1173 switch (s.response ()) {
1174 case Gtk::RESPONSE_OK:
1181 // TODO: maybe IFF brand_new_user
1182 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1183 std::string dspd (Config->get_default_session_parent_dir());
1184 Searchpath ds (ARDOUR::ardour_data_search_path());
1185 ds.add_subdirectory_to_paths ("sessions");
1186 vector<string> demos;
1187 find_files_matching_pattern (demos, ds, "*.tar.xz");
1189 ARDOUR::RecentSessions rs;
1190 ARDOUR::read_recent_sessions (rs);
1192 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1193 /* "demo-session" must be inside "demo-session.tar.xz"
1196 std::string name = basename_nosuffix (basename_nosuffix (*i));
1197 std::string path = Glib::build_filename (dspd, name);
1198 /* skip if session-dir already exists */
1199 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1202 /* skip sessions that are already in 'recent'.
1203 * eg. a new user changed <session-default-dir> shorly after installation
1205 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1206 if ((*r).first == name) {
1211 PBD::FileArchive ar (*i);
1212 if (0 == ar.inflate (dspd)) {
1213 store_recent_sessions (name, path);
1214 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1220 #ifdef NO_PLUGIN_STATE
1222 ARDOUR::RecentSessions rs;
1223 ARDOUR::read_recent_sessions (rs);
1225 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1227 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1229 /* already used Ardour, have sessions ... warn about plugin state */
1231 ArdourDialog d (_("Free/Demo Version Warning"), true);
1233 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1234 CheckButton c (_("Don't warn me about this again"));
1236 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"),
1237 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1238 _("It will not restore OR save any plugin settings"),
1239 _("If you load an existing session with plugin settings\n"
1240 "they will not be used and will be lost."),
1241 _("To get full access to updates without this limitation\n"
1242 "consider becoming a subscriber for a low cost every month.")));
1243 l.set_justify (JUSTIFY_CENTER);
1245 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1247 d.get_vbox()->pack_start (l, true, true);
1248 d.get_vbox()->pack_start (b, false, false, 12);
1249 d.get_vbox()->pack_start (c, false, false, 12);
1251 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1252 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1256 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1258 if (d.run () != RESPONSE_OK) {
1264 /* go get a session */
1266 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1268 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1269 std::cerr << "Cannot get session parameters."<< std::endl;
1276 WM::Manager::instance().show_visible ();
1278 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1279 * editor window, and we may want stuff to be hidden.
1281 _status_bar_visibility.update ();
1283 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1286 // in 1 second, hide the splash screen
1287 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1290 /* all other dialogs are created conditionally */
1296 ARDOUR_UI::check_memory_locking ()
1298 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1299 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1303 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1305 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1307 struct rlimit limits;
1309 long pages, page_size;
1311 size_t pages_len=sizeof(pages);
1312 if ((page_size = getpagesize()) < 0 ||
1313 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1315 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1320 ram = (int64_t) pages * (int64_t) page_size;
1323 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1327 if (limits.rlim_cur != RLIM_INFINITY) {
1329 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1333 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1334 "This might cause %1 to run out of memory before your system "
1335 "runs out of memory. \n\n"
1336 "You can view the memory limit with 'ulimit -l', "
1337 "and it is normally controlled by %2"),
1340 X_("/etc/login.conf")
1342 X_(" /etc/security/limits.conf")
1346 msg.set_default_response (RESPONSE_OK);
1348 VBox* vbox = msg.get_vbox();
1350 CheckButton cb (_("Do not show this window again"));
1351 hbox.pack_start (cb, true, false);
1352 vbox->pack_start (hbox);
1357 pop_back_splash (msg);
1361 if (cb.get_active()) {
1362 XMLNode node (X_("no-memory-warning"));
1363 Config->add_instant_xml (node);
1368 #endif // !__APPLE__
1373 ARDOUR_UI::queue_finish ()
1375 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1379 ARDOUR_UI::idle_finish ()
1382 return false; /* do not call again */
1389 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1391 if (_session->dirty()) {
1392 vector<string> actions;
1393 actions.push_back (_("Don't quit"));
1394 actions.push_back (_("Just quit"));
1395 actions.push_back (_("Save and quit"));
1396 switch (ask_about_saving_session(actions)) {
1401 /* use the default name */
1402 if (save_state_canfail ("")) {
1403 /* failed - don't quit */
1404 MessageDialog msg (_main_window,
1405 string_compose (_("\
1406 %1 was unable to save your session.\n\n\
1407 If you still wish to quit, please use the\n\n\
1408 \"Just quit\" option."), PROGRAM_NAME));
1409 pop_back_splash(msg);
1419 second_connection.disconnect ();
1420 point_one_second_connection.disconnect ();
1421 point_zero_something_second_connection.disconnect();
1422 fps_connection.disconnect();
1425 delete ARDOUR_UI::instance()->video_timeline;
1426 ARDOUR_UI::instance()->video_timeline = NULL;
1427 stop_video_server();
1429 /* Save state before deleting the session, as that causes some
1430 windows to be destroyed before their visible state can be
1433 save_ardour_state ();
1435 if (key_editor.get (false)) {
1436 key_editor->disconnect ();
1439 close_all_dialogs ();
1442 _session->set_clean ();
1443 _session->remove_pending_capture_state ();
1448 halt_connection.disconnect ();
1449 AudioEngine::instance()->stop ();
1450 #ifdef WINDOWS_VST_SUPPORT
1451 fst_stop_threading();
1457 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1459 ArdourDialog window (_("Unsaved Session"));
1460 Gtk::HBox dhbox; // the hbox for the image and text
1461 Gtk::Label prompt_label;
1462 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1466 assert (actions.size() >= 3);
1468 window.add_button (actions[0], RESPONSE_REJECT);
1469 window.add_button (actions[1], RESPONSE_APPLY);
1470 window.add_button (actions[2], RESPONSE_ACCEPT);
1472 window.set_default_response (RESPONSE_ACCEPT);
1474 Gtk::Button noquit_button (msg);
1475 noquit_button.set_name ("EditorGTKButton");
1479 if (_session->snap_name() == _session->name()) {
1480 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?"),
1481 _session->snap_name());
1483 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?"),
1484 _session->snap_name());
1487 prompt_label.set_text (prompt);
1488 prompt_label.set_name (X_("PrompterLabel"));
1489 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1491 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1492 dhbox.set_homogeneous (false);
1493 dhbox.pack_start (*dimage, false, false, 5);
1494 dhbox.pack_start (prompt_label, true, false, 5);
1495 window.get_vbox()->pack_start (dhbox);
1497 window.set_name (_("Prompter"));
1498 window.set_modal (true);
1499 window.set_resizable (false);
1502 prompt_label.show();
1507 ResponseType r = (ResponseType) window.run();
1512 case RESPONSE_ACCEPT: // save and get out of here
1514 case RESPONSE_APPLY: // get out of here
1525 ARDOUR_UI::every_second ()
1528 update_xrun_count ();
1529 update_buffer_load ();
1530 update_disk_space ();
1531 update_timecode_format ();
1532 update_peak_thread_work ();
1534 if (nsm && nsm->is_active ()) {
1537 if (!_was_dirty && _session->dirty ()) {
1541 else if (_was_dirty && !_session->dirty ()){
1549 ARDOUR_UI::every_point_one_seconds ()
1551 // TODO get rid of this..
1552 // ShuttleControl is updated directly via TransportStateChange signal
1556 ARDOUR_UI::every_point_zero_something_seconds ()
1558 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1560 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1561 float mpeak = editor_meter->update_meters();
1562 if (mpeak > editor_meter_max_peak) {
1563 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1564 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1571 ARDOUR_UI::set_fps_timeout_connection ()
1573 unsigned int interval = 40;
1574 if (!_session) return;
1575 if (_session->timecode_frames_per_second() != 0) {
1576 /* ideally we'll use a select() to sleep and not accumulate
1577 * idle time to provide a regular periodic signal.
1578 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1579 * However, that'll require a dedicated thread and cross-thread
1580 * signals to the GUI Thread..
1582 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1583 * _session->frame_rate() / _session->nominal_frame_rate()
1584 / _session->timecode_frames_per_second()
1586 #ifdef PLATFORM_WINDOWS
1587 // the smallest windows scheduler time-slice is ~15ms.
1588 // periodic GUI timeouts shorter than that will cause
1589 // WaitForSingleObject to spinlock (100% of one CPU Core)
1590 // and gtk never enters idle mode.
1591 // also changing timeBeginPeriod(1) does not affect that in
1592 // any beneficial way, so we just limit the max rate for now.
1593 interval = std::max(30u, interval); // at most ~33Hz.
1595 interval = std::max(8u, interval); // at most 120Hz.
1598 fps_connection.disconnect();
1599 Timers::set_fps_interval (interval);
1603 ARDOUR_UI::update_sample_rate (framecnt_t)
1607 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1609 if (!AudioEngine::instance()->connected()) {
1611 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1615 framecnt_t rate = AudioEngine::instance()->sample_rate();
1618 /* no sample rate available */
1619 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1622 if (fmod (rate, 1000.0) != 0.0) {
1623 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1624 (float) rate / 1000.0f,
1625 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1627 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1629 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1633 sample_rate_label.set_markup (buf);
1637 ARDOUR_UI::update_format ()
1640 format_label.set_text ("");
1645 s << _("File:") << X_(" <span foreground=\"green\">");
1647 switch (_session->config.get_native_file_header_format ()) {
1679 switch (_session->config.get_native_file_data_format ()) {
1693 format_label.set_markup (s.str ());
1697 ARDOUR_UI::update_xrun_count ()
1701 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1702 should also be changed.
1706 const unsigned int x = _session->get_xrun_count ();
1708 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1710 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1713 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1715 xrun_label.set_markup (buf);
1716 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1720 ARDOUR_UI::update_cpu_load ()
1724 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1725 should also be changed.
1728 double const c = AudioEngine::instance()->get_dsp_load ();
1729 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1730 cpu_load_label.set_markup (buf);
1734 ARDOUR_UI::update_peak_thread_work ()
1737 const int c = SourceFactory::peak_work_queue_length ();
1739 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1740 peak_thread_work_label.set_markup (buf);
1742 peak_thread_work_label.set_markup (X_(""));
1747 ARDOUR_UI::update_buffer_load ()
1751 uint32_t const playback = _session ? _session->playback_load () : 100;
1752 uint32_t const capture = _session ? _session->capture_load () : 100;
1754 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1755 should also be changed.
1761 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1762 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1763 playback <= 5 ? X_("red") : X_("green"),
1765 capture <= 5 ? X_("red") : X_("green"),
1769 buffer_load_label.set_markup (buf);
1771 buffer_load_label.set_text ("");
1776 ARDOUR_UI::count_recenabled_streams (Route& route)
1778 Track* track = dynamic_cast<Track*>(&route);
1779 if (track && track->rec_enable_control()->get_value()) {
1780 rec_enabled_streams += track->n_inputs().n_total();
1785 ARDOUR_UI::update_disk_space()
1787 if (_session == 0) {
1791 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1793 framecnt_t fr = _session->frame_rate();
1796 /* skip update - no SR available */
1801 /* Available space is unknown */
1802 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1803 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1804 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1806 rec_enabled_streams = 0;
1807 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1809 framecnt_t frames = opt_frames.get_value_or (0);
1811 if (rec_enabled_streams) {
1812 frames /= rec_enabled_streams;
1819 hrs = frames / (fr * 3600);
1822 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1824 frames -= hrs * fr * 3600;
1825 mins = frames / (fr * 60);
1826 frames -= mins * fr * 60;
1829 bool const low = (hrs == 0 && mins <= 30);
1833 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1834 low ? X_("red") : X_("green"),
1840 disk_space_label.set_markup (buf);
1844 ARDOUR_UI::update_timecode_format ()
1850 TimecodeSlave* tcslave;
1851 SyncSource sync_src = Config->get_sync_source();
1853 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1854 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1859 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1860 matching ? X_("green") : X_("red"),
1861 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1863 snprintf (buf, sizeof (buf), "TC: n/a");
1866 timecode_format_label.set_markup (buf);
1870 ARDOUR_UI::update_wall_clock ()
1874 static int last_min = -1;
1877 tm_now = localtime (&now);
1878 if (last_min != tm_now->tm_min) {
1880 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1881 wall_clock_label.set_text (buf);
1882 last_min = tm_now->tm_min;
1889 ARDOUR_UI::open_recent_session ()
1891 bool can_return = (_session != 0);
1893 SessionDialog recent_session_dialog;
1897 ResponseType r = (ResponseType) recent_session_dialog.run ();
1900 case RESPONSE_ACCEPT:
1904 recent_session_dialog.hide();
1911 recent_session_dialog.hide();
1915 std::string path = recent_session_dialog.session_folder();
1916 std::string state = recent_session_dialog.session_name (should_be_new);
1918 if (should_be_new == true) {
1922 _session_is_new = false;
1924 if (load_session (path, state) == 0) {
1931 // in 1 second, hide the splash screen
1932 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1937 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1939 if (!AudioEngine::instance()->connected()) {
1940 MessageDialog msg (parent, string_compose (
1941 _("%1 is not connected to any audio backend.\n"
1942 "You cannot open or close sessions in this condition"),
1944 pop_back_splash (msg);
1952 ARDOUR_UI::open_session ()
1954 if (!check_audioengine (_main_window)) {
1958 /* ardour sessions are folders */
1959 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1960 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1961 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1962 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1965 string session_parent_dir = Glib::path_get_dirname(_session->path());
1966 open_session_selector.set_current_folder(session_parent_dir);
1968 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1971 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1973 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1974 string default_session_folder = Config->get_default_session_parent_dir();
1975 open_session_selector.add_shortcut_folder (default_session_folder);
1977 catch (Glib::Error & e) {
1978 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1981 FileFilter session_filter;
1982 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1983 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1984 open_session_selector.add_filter (session_filter);
1986 FileFilter archive_filter;
1987 archive_filter.add_pattern (X_("*.tar.xz"));
1988 archive_filter.set_name (_("Session Archives"));
1990 open_session_selector.add_filter (archive_filter);
1992 open_session_selector.set_filter (session_filter);
1994 int response = open_session_selector.run();
1995 open_session_selector.hide ();
1997 if (response == Gtk::RESPONSE_CANCEL) {
2001 string session_path = open_session_selector.get_filename();
2005 if (session_path.length() > 0) {
2006 int rv = ARDOUR::inflate_session (session_path,
2007 Config->get_default_session_parent_dir(), path, name);
2009 _session_is_new = false;
2010 load_session (path, name);
2013 MessageDialog msg (_main_window,
2014 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2017 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2018 _session_is_new = isnew;
2019 load_session (path, name);
2025 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
2031 _session->vca_manager().create_vca (n, name_template);
2035 ARDOUR_UI::session_add_mixed_track (
2036 const ChanCount& input,
2037 const ChanCount& output,
2038 RouteGroup* route_group,
2040 const string& name_template,
2042 PluginInfoPtr instrument,
2043 Plugin::PresetRecord* pset,
2044 ARDOUR::PresentationInfo::order_t order)
2046 if (_session == 0) {
2047 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2051 if (Profile->get_mixbus ()) {
2056 list<boost::shared_ptr<MidiTrack> > tracks;
2057 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2059 if (tracks.size() != how_many) {
2060 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2065 display_insufficient_ports_message ();
2071 ARDOUR_UI::session_add_midi_bus (
2072 RouteGroup* route_group,
2074 const string& name_template,
2076 PluginInfoPtr instrument,
2077 Plugin::PresetRecord* pset,
2078 ARDOUR::PresentationInfo::order_t order)
2080 if (_session == 0) {
2081 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2085 if (Profile->get_mixbus ()) {
2091 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2092 if (routes.size() != how_many) {
2093 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2098 display_insufficient_ports_message ();
2104 ARDOUR_UI::session_add_midi_route (
2106 RouteGroup* route_group,
2108 const string& name_template,
2110 PluginInfoPtr instrument,
2111 Plugin::PresetRecord* pset,
2112 ARDOUR::PresentationInfo::order_t order)
2114 ChanCount one_midi_channel;
2115 one_midi_channel.set (DataType::MIDI, 1);
2118 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2120 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2125 ARDOUR_UI::session_add_audio_route (
2127 int32_t input_channels,
2128 int32_t output_channels,
2129 ARDOUR::TrackMode mode,
2130 RouteGroup* route_group,
2132 string const & name_template,
2134 ARDOUR::PresentationInfo::order_t order)
2136 list<boost::shared_ptr<AudioTrack> > tracks;
2139 if (_session == 0) {
2140 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2146 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2148 if (tracks.size() != how_many) {
2149 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2155 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2157 if (routes.size() != how_many) {
2158 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2165 display_insufficient_ports_message ();
2170 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2171 (*i)->set_strict_io (true);
2173 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2174 (*i)->set_strict_io (true);
2180 ARDOUR_UI::display_insufficient_ports_message ()
2182 MessageDialog msg (_main_window,
2183 string_compose (_("There are insufficient ports available\n\
2184 to create a new track or bus.\n\
2185 You should save %1, exit and\n\
2186 restart with more ports."), PROGRAM_NAME));
2187 pop_back_splash (msg);
2192 ARDOUR_UI::transport_goto_start ()
2195 _session->goto_start();
2197 /* force displayed area in editor to start no matter
2198 what "follow playhead" setting is.
2202 editor->center_screen (_session->current_start_frame ());
2208 ARDOUR_UI::transport_goto_zero ()
2211 _session->request_locate (0);
2213 /* force displayed area in editor to start no matter
2214 what "follow playhead" setting is.
2218 editor->reset_x_origin (0);
2224 ARDOUR_UI::transport_goto_wallclock ()
2226 if (_session && editor) {
2233 localtime_r (&now, &tmnow);
2235 framecnt_t frame_rate = _session->frame_rate();
2237 if (frame_rate == 0) {
2238 /* no frame rate available */
2242 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2243 frames += tmnow.tm_min * (60 * frame_rate);
2244 frames += tmnow.tm_sec * frame_rate;
2246 _session->request_locate (frames, _session->transport_rolling ());
2248 /* force displayed area in editor to start no matter
2249 what "follow playhead" setting is.
2253 editor->center_screen (frames);
2259 ARDOUR_UI::transport_goto_end ()
2262 framepos_t const frame = _session->current_end_frame();
2263 _session->request_locate (frame);
2265 /* force displayed area in editor to start no matter
2266 what "follow playhead" setting is.
2270 editor->center_screen (frame);
2276 ARDOUR_UI::transport_stop ()
2282 if (_session->is_auditioning()) {
2283 _session->cancel_audition ();
2287 _session->request_stop (false, true);
2290 /** Check if any tracks are record enabled. If none are, record enable all of them.
2291 * @return true if track record-enabled status was changed, false otherwise.
2294 ARDOUR_UI::trx_record_enable_all_tracks ()
2300 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2301 bool none_record_enabled = true;
2303 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2304 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2307 if (t->rec_enable_control()->get_value()) {
2308 none_record_enabled = false;
2313 if (none_record_enabled) {
2314 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2317 return none_record_enabled;
2321 ARDOUR_UI::transport_record (bool roll)
2324 switch (_session->record_status()) {
2325 case Session::Disabled:
2326 if (_session->ntracks() == 0) {
2327 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."));
2331 if (Profile->get_trx()) {
2332 roll = trx_record_enable_all_tracks ();
2334 _session->maybe_enable_record ();
2339 case Session::Recording:
2341 _session->request_stop();
2343 _session->disable_record (false, true);
2347 case Session::Enabled:
2348 _session->disable_record (false, true);
2354 ARDOUR_UI::transport_roll ()
2360 if (_session->is_auditioning()) {
2365 if (_session->config.get_external_sync()) {
2366 switch (Config->get_sync_source()) {
2370 /* transport controlled by the master */
2376 bool rolling = _session->transport_rolling();
2378 if (_session->get_play_loop()) {
2380 /* If loop playback is not a mode, then we should cancel
2381 it when this action is requested. If it is a mode
2382 we just leave it in place.
2385 if (!Config->get_loop_is_mode()) {
2386 /* XXX it is not possible to just leave seamless loop and keep
2387 playing at present (nov 4th 2009)
2389 if (!Config->get_seamless_loop()) {
2390 /* stop loop playback and stop rolling */
2391 _session->request_play_loop (false, true);
2392 } else if (rolling) {
2393 /* stop loop playback but keep rolling */
2394 _session->request_play_loop (false, false);
2398 } else if (_session->get_play_range () ) {
2399 /* stop playing a range if we currently are */
2400 _session->request_play_range (0, true);
2404 _session->request_transport_speed (1.0f);
2409 ARDOUR_UI::get_smart_mode() const
2411 return ( editor->get_smart_mode() );
2416 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2422 if (_session->is_auditioning()) {
2423 _session->cancel_audition ();
2427 if (_session->config.get_external_sync()) {
2428 switch (Config->get_sync_source()) {
2432 /* transport controlled by the master */
2437 bool rolling = _session->transport_rolling();
2438 bool affect_transport = true;
2440 if (rolling && roll_out_of_bounded_mode) {
2441 /* drop out of loop/range playback but leave transport rolling */
2442 if (_session->get_play_loop()) {
2443 if (_session->actively_recording()) {
2445 /* just stop using the loop, then actually stop
2448 _session->request_play_loop (false, affect_transport);
2451 if (Config->get_seamless_loop()) {
2452 /* the disk buffers contain copies of the loop - we can't
2453 just keep playing, so stop the transport. the user
2454 can restart as they wish.
2456 affect_transport = true;
2458 /* disk buffers are normal, so we can keep playing */
2459 affect_transport = false;
2461 _session->request_play_loop (false, affect_transport);
2463 } else if (_session->get_play_range ()) {
2464 affect_transport = false;
2465 _session->request_play_range (0, true);
2469 if (affect_transport) {
2471 _session->request_stop (with_abort, true);
2473 } else if (!with_abort) { /* with_abort == true means the
2474 * command was intended to stop
2475 * transport, not start.
2478 /* the only external sync condition we can be in here
2479 * would be Engine (JACK) sync, in which case we still
2483 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
2484 _session->request_play_range (&editor->get_selection().time, true);
2485 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2487 _session->request_transport_speed (1.0f);
2493 ARDOUR_UI::toggle_session_auto_loop ()
2499 Location * looploc = _session->locations()->auto_loop_location();
2505 if (_session->get_play_loop()) {
2507 /* looping enabled, our job is to disable it */
2509 _session->request_play_loop (false);
2513 /* looping not enabled, our job is to enable it.
2515 loop-is-NOT-mode: this action always starts the transport rolling.
2516 loop-IS-mode: this action simply sets the loop play mechanism, but
2517 does not start transport.
2519 if (Config->get_loop_is_mode()) {
2520 _session->request_play_loop (true, false);
2522 _session->request_play_loop (true, true);
2526 //show the loop markers
2527 looploc->set_hidden (false, this);
2531 ARDOUR_UI::transport_play_selection ()
2537 editor->play_selection ();
2541 ARDOUR_UI::transport_play_preroll ()
2546 editor->play_with_preroll ();
2550 ARDOUR_UI::transport_rec_preroll ()
2555 editor->rec_with_preroll ();
2559 ARDOUR_UI::transport_rec_count_in ()
2564 editor->rec_with_count_in ();
2568 ARDOUR_UI::transport_rewind (int option)
2570 float current_transport_speed;
2573 current_transport_speed = _session->transport_speed();
2575 if (current_transport_speed >= 0.0f) {
2578 _session->request_transport_speed (-1.0f);
2581 _session->request_transport_speed (-4.0f);
2584 _session->request_transport_speed (-0.5f);
2589 _session->request_transport_speed (current_transport_speed * 1.5f);
2595 ARDOUR_UI::transport_forward (int option)
2601 float current_transport_speed = _session->transport_speed();
2603 if (current_transport_speed <= 0.0f) {
2606 _session->request_transport_speed (1.0f);
2609 _session->request_transport_speed (4.0f);
2612 _session->request_transport_speed (0.5f);
2617 _session->request_transport_speed (current_transport_speed * 1.5f);
2622 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2628 boost::shared_ptr<Route> r;
2630 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2632 boost::shared_ptr<Track> t;
2634 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2635 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2641 ARDOUR_UI::map_transport_state ()
2644 auto_loop_button.unset_active_state ();
2645 play_selection_button.unset_active_state ();
2646 roll_button.unset_active_state ();
2647 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2648 layered_button.set_sensitive (false);
2652 shuttle_box.map_transport_state ();
2654 float sp = _session->transport_speed();
2660 if (_session->get_play_range()) {
2662 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2663 roll_button.unset_active_state ();
2664 auto_loop_button.unset_active_state ();
2666 } else if (_session->get_play_loop ()) {
2668 auto_loop_button.set_active (true);
2669 play_selection_button.set_active (false);
2670 if (Config->get_loop_is_mode()) {
2671 roll_button.set_active (true);
2673 roll_button.set_active (false);
2678 roll_button.set_active (true);
2679 play_selection_button.set_active (false);
2680 auto_loop_button.set_active (false);
2683 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2684 /* light up both roll and play-selection if they are joined */
2685 roll_button.set_active (true);
2686 play_selection_button.set_active (true);
2688 layered_button.set_sensitive (!_session->actively_recording ());
2690 stop_button.set_active (false);
2694 layered_button.set_sensitive (true);
2695 stop_button.set_active (true);
2696 roll_button.set_active (false);
2697 play_selection_button.set_active (false);
2698 if (Config->get_loop_is_mode ()) {
2699 auto_loop_button.set_active (_session->get_play_loop());
2701 auto_loop_button.set_active (false);
2703 update_disk_space ();
2708 ARDOUR_UI::blink_handler (bool blink_on)
2710 transport_rec_enable_blink (blink_on);
2711 sync_blink (blink_on);
2713 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2716 error_blink (blink_on);
2717 solo_blink (blink_on);
2718 audition_blink (blink_on);
2719 feedback_blink (blink_on);
2723 ARDOUR_UI::update_clocks ()
2725 if (!_session) return;
2727 if (editor && !editor->dragging_playhead()) {
2728 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2733 ARDOUR_UI::start_clocking ()
2735 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2736 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2738 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2743 ARDOUR_UI::stop_clocking ()
2745 clock_signal_connection.disconnect ();
2749 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2753 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2755 label->set_text (buf);
2756 bar->set_fraction (fraction);
2758 /* process events, redraws, etc. */
2760 while (gtk_events_pending()) {
2761 gtk_main_iteration ();
2764 return true; /* continue with save-as */
2768 ARDOUR_UI::save_session_as ()
2774 if (!save_as_dialog) {
2775 save_as_dialog = new SaveAsDialog;
2778 save_as_dialog->set_name (_session->name());
2780 int response = save_as_dialog->run ();
2782 save_as_dialog->hide ();
2785 case Gtk::RESPONSE_OK:
2794 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2795 sa.new_name = save_as_dialog->new_name ();
2796 sa.switch_to = save_as_dialog->switch_to();
2797 sa.copy_media = save_as_dialog->copy_media();
2798 sa.copy_external = save_as_dialog->copy_external();
2799 sa.include_media = save_as_dialog->include_media ();
2801 /* Only bother with a progress dialog if we're going to copy
2802 media into the save-as target. Without that choice, this
2803 will be very fast because we're only talking about a few kB's to
2804 perhaps a couple of MB's of data.
2807 ArdourDialog progress_dialog (_("Save As"), true);
2810 if (sa.include_media && sa.copy_media) {
2812 Gtk::Label* label = manage (new Gtk::Label());
2813 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2815 progress_dialog.get_vbox()->pack_start (*label);
2816 progress_dialog.get_vbox()->pack_start (*progress_bar);
2818 progress_bar->show ();
2820 /* this signal will be emitted from within this, the calling thread,
2821 * after every file is copied. It provides information on percentage
2822 * complete (in terms of total data to copy), the number of files
2823 * copied so far, and the total number to copy.
2826 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2828 progress_dialog.show_all ();
2829 progress_dialog.present ();
2832 if (_session->save_as (sa)) {
2834 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2838 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2839 * the trick is this: if the new session was copy with media included,
2840 * then Session::save_as() will have already done a neat trick to avoid
2841 * us having to unload and load the new state. But if the media was not
2842 * included, then this is required (it avoids us having to otherwise
2843 * drop all references to media (sources).
2846 if (!sa.include_media && sa.switch_to) {
2847 unload_session (false);
2848 load_session (sa.final_session_folder_name, sa.new_name);
2854 ARDOUR_UI::archive_session ()
2862 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2864 SessionArchiveDialog sad;
2865 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2866 int response = sad.run ();
2868 if (response != Gtk::RESPONSE_OK) {
2873 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2874 MessageDialog msg (_("Session Archiving failed."));
2880 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2884 struct tm local_time;
2887 localtime_r (&n, &local_time);
2888 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2890 save_state (timebuf, switch_to_it);
2895 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2899 prompter.get_result (snapname);
2901 bool do_save = (snapname.length() != 0);
2904 char illegal = Session::session_name_is_legal(snapname);
2906 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2907 "snapshot names may not contain a '%1' character"), illegal));
2913 vector<std::string> p;
2914 get_state_files_in_directory (_session->session_directory().root_path(), p);
2915 vector<string> n = get_file_names_no_extension (p);
2917 if (find (n.begin(), n.end(), snapname) != n.end()) {
2919 do_save = overwrite_file_dialog (prompter,
2920 _("Confirm Snapshot Overwrite"),
2921 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2925 save_state (snapname, switch_to_it);
2935 /** Ask the user for the name of a new snapshot and then take it.
2939 ARDOUR_UI::snapshot_session (bool switch_to_it)
2941 ArdourPrompter prompter (true);
2943 prompter.set_name ("Prompter");
2944 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2946 prompter.set_title (_("Snapshot and switch"));
2947 prompter.set_prompt (_("New session name"));
2949 prompter.set_title (_("Take Snapshot"));
2950 prompter.set_prompt (_("Name of new snapshot"));
2954 prompter.set_initial_text (_session->snap_name());
2956 Glib::DateTime tm (g_date_time_new_now_local ());
2957 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2960 bool finished = false;
2962 switch (prompter.run()) {
2963 case RESPONSE_ACCEPT:
2965 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2976 /** Ask the user for a new session name and then rename the session to it.
2980 ARDOUR_UI::rename_session ()
2986 ArdourPrompter prompter (true);
2989 prompter.set_name ("Prompter");
2990 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2991 prompter.set_title (_("Rename Session"));
2992 prompter.set_prompt (_("New session name"));
2995 switch (prompter.run()) {
2996 case RESPONSE_ACCEPT:
2998 prompter.get_result (name);
3000 bool do_rename = (name.length() != 0);
3003 char illegal = Session::session_name_is_legal (name);
3006 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3007 "session names may not contain a '%1' character"), illegal));
3012 switch (_session->rename (name)) {
3014 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3015 msg.set_position (WIN_POS_MOUSE);
3023 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3024 msg.set_position (WIN_POS_MOUSE);
3040 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3042 if (!_session || _session->deletion_in_progress()) {
3046 XMLNode* node = new XMLNode (X_("UI"));
3048 WM::Manager::instance().add_state (*node);
3050 node->add_child_nocopy (gui_object_state->get_state());
3052 _session->add_extra_xml (*node);
3054 if (export_video_dialog) {
3055 _session->add_extra_xml (export_video_dialog->get_state());
3058 save_state_canfail (name, switch_to_it);
3062 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3067 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3072 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3077 ARDOUR_UI::primary_clock_value_changed ()
3080 _session->request_locate (primary_clock->current_time ());
3085 ARDOUR_UI::big_clock_value_changed ()
3088 _session->request_locate (big_clock->current_time ());
3093 ARDOUR_UI::secondary_clock_value_changed ()
3096 _session->request_locate (secondary_clock->current_time ());
3101 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3103 if (_session == 0) {
3107 if (_session->step_editing()) {
3111 Session::RecordState const r = _session->record_status ();
3112 bool const h = _session->have_rec_enabled_track ();
3114 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3116 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3118 rec_button.set_active_state (Gtkmm2ext::Off);
3120 } else if (r == Session::Recording && h) {
3121 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3123 rec_button.unset_active_state ();
3128 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3132 prompter.get_result (name);
3134 if (name.length()) {
3135 int failed = _session->save_template (name);
3137 if (failed == -2) { /* file already exists. */
3138 bool overwrite = overwrite_file_dialog (prompter,
3139 _("Confirm Template Overwrite"),
3140 _("A template already exists with that name. Do you want to overwrite it?"));
3143 _session->save_template (name, true);
3155 ARDOUR_UI::save_template ()
3157 ArdourPrompter prompter (true);
3159 if (!check_audioengine (_main_window)) {
3163 prompter.set_name (X_("Prompter"));
3164 prompter.set_title (_("Save Template"));
3165 prompter.set_prompt (_("Name for template:"));
3166 prompter.set_initial_text(_session->name() + _("-template"));
3167 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3169 bool finished = false;
3171 switch (prompter.run()) {
3172 case RESPONSE_ACCEPT:
3173 finished = process_save_template_prompter (prompter);
3184 ARDOUR_UI::edit_metadata ()
3186 SessionMetadataEditor dialog;
3187 dialog.set_session (_session);
3188 dialog.grab_focus ();
3193 ARDOUR_UI::import_metadata ()
3195 SessionMetadataImporter dialog;
3196 dialog.set_session (_session);
3201 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3203 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3205 MessageDialog msg (str,
3207 Gtk::MESSAGE_WARNING,
3208 Gtk::BUTTONS_YES_NO,
3212 msg.set_name (X_("OpenExistingDialog"));
3213 msg.set_title (_("Open Existing Session"));
3214 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3215 msg.set_position (Gtk::WIN_POS_CENTER);
3216 pop_back_splash (msg);
3218 switch (msg.run()) {
3227 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3229 BusProfile bus_profile;
3233 bus_profile.master_out_channels = 2;
3234 bus_profile.input_ac = AutoConnectPhysical;
3235 bus_profile.output_ac = AutoConnectMaster;
3236 bus_profile.requested_physical_in = 0; // use all available
3237 bus_profile.requested_physical_out = 0; // use all available
3241 /* get settings from advanced section of NSD */
3243 if (sd.create_master_bus()) {
3244 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3246 bus_profile.master_out_channels = 0;
3249 if (sd.connect_inputs()) {
3250 bus_profile.input_ac = AutoConnectPhysical;
3252 bus_profile.input_ac = AutoConnectOption (0);
3255 bus_profile.output_ac = AutoConnectOption (0);
3257 if (sd.connect_outputs ()) {
3258 if (sd.connect_outs_to_master()) {
3259 bus_profile.output_ac = AutoConnectMaster;
3260 } else if (sd.connect_outs_to_physical()) {
3261 bus_profile.output_ac = AutoConnectPhysical;
3265 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3266 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3269 if (build_session (session_path, session_name, bus_profile)) {
3277 ARDOUR_UI::load_from_application_api (const std::string& path)
3279 /* OS X El Capitan (and probably later) now somehow passes the command
3280 line arguments to an app via the openFile delegate protocol. Ardour
3281 already does its own command line processing, and having both
3282 pathways active causes crashes. So, if the command line was already
3283 set, do nothing here.
3286 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3290 ARDOUR_COMMAND_LINE::session_name = path;
3292 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3294 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3296 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3297 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3298 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3299 * -> SessionDialog is not displayed
3302 if (_session_dialog) {
3303 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3304 std::string session_path = path;
3305 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3306 session_path = Glib::path_get_dirname (session_path);
3308 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3309 _session_dialog->set_provided_session (session_name, session_path);
3310 _session_dialog->response (RESPONSE_NONE);
3311 _session_dialog->hide();
3316 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3317 /* /path/to/foo => /path/to/foo, foo */
3318 rv = load_session (path, basename_nosuffix (path));
3320 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3321 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3324 // if load_session fails -> pop up SessionDialog.
3326 ARDOUR_COMMAND_LINE::session_name = "";
3328 if (get_session_parameters (true, false)) {
3334 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3336 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3338 string session_name;
3339 string session_path;
3340 string template_name;
3342 bool likely_new = false;
3343 bool cancel_not_quit;
3345 /* deal with any existing DIRTY session now, rather than later. don't
3346 * treat a non-dirty session this way, so that it stays visible
3347 * as we bring up the new session dialog.
3350 if (_session && ARDOUR_UI::instance()->video_timeline) {
3351 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3354 /* if there is already a session, relabel the button
3355 on the SessionDialog so that we don't Quit directly
3357 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3359 if (_session && _session->dirty()) {
3360 if (unload_session (false)) {
3361 /* unload cancelled by user */
3364 ARDOUR_COMMAND_LINE::session_name = "";
3367 if (!load_template.empty()) {
3368 should_be_new = true;
3369 template_name = load_template;
3372 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3373 session_path = ARDOUR_COMMAND_LINE::session_name;
3375 if (!session_path.empty()) {
3376 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3377 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3378 /* session/snapshot file, change path to be dir */
3379 session_path = Glib::path_get_dirname (session_path);
3384 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3386 _session_dialog = &session_dialog;
3389 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3391 /* if they named a specific statefile, use it, otherwise they are
3392 just giving a session folder, and we want to use it as is
3393 to find the session.
3396 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3398 if (suffix != string::npos) {
3399 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3400 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3401 session_name = Glib::path_get_basename (session_name);
3403 session_path = ARDOUR_COMMAND_LINE::session_name;
3404 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3409 session_dialog.clear_given ();
3412 if (should_be_new || session_name.empty()) {
3413 /* need the dialog to get info from user */
3415 cerr << "run dialog\n";
3417 switch (session_dialog.run()) {
3418 case RESPONSE_ACCEPT:
3421 /* this is used for async * app->ShouldLoad(). */
3422 continue; // while loop
3425 if (quit_on_cancel) {
3426 // JE - Currently (July 2014) this section can only get reached if the
3427 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3428 // point does NOT indicate an abnormal termination). Therefore, let's
3429 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3431 pthread_cancel_all ();
3439 session_dialog.hide ();
3442 /* if we run the startup dialog again, offer more than just "new session" */
3444 should_be_new = false;
3446 session_name = session_dialog.session_name (likely_new);
3447 session_path = session_dialog.session_folder ();
3454 int rv = ARDOUR::inflate_session (session_name,
3455 Config->get_default_session_parent_dir(), session_path, session_name);
3457 MessageDialog msg (session_dialog,
3458 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3463 session_dialog.set_provided_session (session_name, session_path);
3467 // XXX check archive, inflate
3468 string::size_type suffix = session_name.find (statefile_suffix);
3470 if (suffix != string::npos) {
3471 session_name = session_name.substr (0, suffix);
3474 /* this shouldn't happen, but we catch it just in case it does */
3476 if (session_name.empty()) {
3480 if (session_dialog.use_session_template()) {
3481 template_name = session_dialog.session_template_name();
3482 _session_is_new = true;
3485 if (session_name[0] == G_DIR_SEPARATOR ||
3486 #ifdef PLATFORM_WINDOWS
3487 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3489 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3490 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3495 /* absolute path or cwd-relative path specified for session name: infer session folder
3496 from what was given.
3499 session_path = Glib::path_get_dirname (session_name);
3500 session_name = Glib::path_get_basename (session_name);
3504 session_path = session_dialog.session_folder();
3506 char illegal = Session::session_name_is_legal (session_name);
3509 MessageDialog msg (session_dialog,
3510 string_compose (_("To ensure compatibility with various systems\n"
3511 "session names may not contain a '%1' character"),
3514 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3519 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3522 if (likely_new && !nsm) {
3524 std::string existing = Glib::build_filename (session_path, session_name);
3526 if (!ask_about_loading_existing_session (existing)) {
3527 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3532 _session_is_new = false;
3537 pop_back_splash (session_dialog);
3538 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3540 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3544 char illegal = Session::session_name_is_legal(session_name);
3547 pop_back_splash (session_dialog);
3548 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3549 "session names may not contain a '%1' character"), illegal));
3551 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3555 _session_is_new = true;
3558 if (likely_new && template_name.empty()) {
3560 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3564 ret = load_session (session_path, session_name, template_name);
3567 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3571 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3572 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3576 /* clear this to avoid endless attempts to load the
3580 ARDOUR_COMMAND_LINE::session_name = "";
3584 _session_dialog = NULL;
3590 ARDOUR_UI::close_session()
3592 if (!check_audioengine (_main_window)) {
3596 if (unload_session (true)) {
3600 ARDOUR_COMMAND_LINE::session_name = "";
3602 if (get_session_parameters (true, false)) {
3605 if (splash && splash->is_visible()) {
3606 // in 1 second, hide the splash screen
3607 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3611 /** @param snap_name Snapshot name (without .ardour suffix).
3612 * @return -2 if the load failed because we are not connected to the AudioEngine.
3615 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3617 Session *new_session;
3622 unload_status = unload_session ();
3624 if (unload_status < 0) {
3626 } else if (unload_status > 0) {
3632 session_loaded = false;
3634 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3637 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3640 /* this one is special */
3642 catch (AudioEngine::PortRegistrationFailure& err) {
3644 MessageDialog msg (err.what(),
3647 Gtk::BUTTONS_CLOSE);
3649 msg.set_title (_("Port Registration Error"));
3650 msg.set_secondary_text (_("Click the Close button to try again."));
3651 msg.set_position (Gtk::WIN_POS_CENTER);
3652 pop_back_splash (msg);
3655 int response = msg.run ();
3660 case RESPONSE_CANCEL:
3667 catch (SessionException e) {
3668 MessageDialog msg (string_compose(
3669 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3670 path, snap_name, e.what()),
3675 msg.set_title (_("Loading Error"));
3676 msg.set_position (Gtk::WIN_POS_CENTER);
3677 pop_back_splash (msg);
3689 MessageDialog msg (string_compose(
3690 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3696 msg.set_title (_("Loading Error"));
3697 msg.set_position (Gtk::WIN_POS_CENTER);
3698 pop_back_splash (msg);
3710 list<string> const u = new_session->unknown_processors ();
3712 MissingPluginDialog d (_session, u);
3717 if (!new_session->writable()) {
3718 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3723 msg.set_title (_("Read-only Session"));
3724 msg.set_position (Gtk::WIN_POS_CENTER);
3725 pop_back_splash (msg);
3732 /* Now the session been created, add the transport controls */
3733 new_session->add_controllable(roll_controllable);
3734 new_session->add_controllable(stop_controllable);
3735 new_session->add_controllable(goto_start_controllable);
3736 new_session->add_controllable(goto_end_controllable);
3737 new_session->add_controllable(auto_loop_controllable);
3738 new_session->add_controllable(play_selection_controllable);
3739 new_session->add_controllable(rec_controllable);
3741 set_session (new_session);
3743 session_loaded = true;
3746 _session->set_clean ();
3749 #ifdef WINDOWS_VST_SUPPORT
3750 fst_stop_threading();
3754 Timers::TimerSuspender t;
3758 #ifdef WINDOWS_VST_SUPPORT
3759 fst_start_threading();
3768 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3770 Session *new_session;
3773 session_loaded = false;
3774 x = unload_session ();
3782 _session_is_new = true;
3785 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3788 catch (SessionException e) {
3789 cerr << "Here are the errors associated with this failed session:\n";
3791 cerr << "---------\n";
3792 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3793 msg.set_title (_("Loading Error"));
3794 msg.set_position (Gtk::WIN_POS_CENTER);
3795 pop_back_splash (msg);
3800 cerr << "Here are the errors associated with this failed session:\n";
3802 cerr << "---------\n";
3803 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3804 msg.set_title (_("Loading Error"));
3805 msg.set_position (Gtk::WIN_POS_CENTER);
3806 pop_back_splash (msg);
3811 /* Give the new session the default GUI state, if such things exist */
3814 n = Config->instant_xml (X_("Editor"));
3816 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3817 new_session->add_instant_xml (*n, false);
3819 n = Config->instant_xml (X_("Mixer"));
3821 new_session->add_instant_xml (*n, false);
3824 n = Config->instant_xml (X_("Preferences"));
3826 new_session->add_instant_xml (*n, false);
3829 /* Put the playhead at 0 and scroll fully left */
3830 n = new_session->instant_xml (X_("Editor"));
3832 n->set_property (X_("playhead"), X_("0"));
3833 n->set_property (X_("left-frame"), X_("0"));
3836 set_session (new_session);
3838 session_loaded = true;
3840 new_session->save_state(new_session->name());
3846 ARDOUR_UI::launch_chat ()
3848 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3850 dialog.set_title (_("About the Chat"));
3851 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."));
3853 switch (dialog.run()) {
3856 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3857 #elif defined PLATFORM_WINDOWS
3858 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3860 open_uri("http://webchat.freenode.net/?channels=ardour");
3869 ARDOUR_UI::launch_manual ()
3871 PBD::open_uri (Config->get_tutorial_manual_url());
3875 ARDOUR_UI::launch_reference ()
3877 PBD::open_uri (Config->get_reference_manual_url());
3881 ARDOUR_UI::launch_tracker ()
3883 PBD::open_uri ("http://tracker.ardour.org");
3887 ARDOUR_UI::launch_subscribe ()
3889 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3893 ARDOUR_UI::launch_cheat_sheet ()
3896 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3898 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3903 ARDOUR_UI::launch_website ()
3905 PBD::open_uri ("http://ardour.org");
3909 ARDOUR_UI::launch_website_dev ()
3911 PBD::open_uri ("http://ardour.org/development.html");
3915 ARDOUR_UI::launch_forums ()
3917 PBD::open_uri ("https://community.ardour.org/forums");
3921 ARDOUR_UI::launch_howto_report ()
3923 PBD::open_uri ("http://ardour.org/reporting_bugs");
3927 ARDOUR_UI::loading_message (const std::string& msg)
3929 if (ARDOUR_COMMAND_LINE::no_splash) {
3937 splash->message (msg);
3941 ARDOUR_UI::show_splash ()
3945 splash = new Splash;
3955 ARDOUR_UI::hide_splash ()
3962 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3966 removed = rep.paths.size();
3969 MessageDialog msgd (_main_window,
3970 _("No files were ready for clean-up"),
3974 msgd.set_title (_("Clean-up"));
3975 msgd.set_secondary_text (_("If this seems suprising, \n\
3976 check for any existing snapshots.\n\
3977 These may still include regions that\n\
3978 require some unused files to continue to exist."));
3984 ArdourDialog results (_("Clean-up"), true, false);
3986 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3987 CleanupResultsModelColumns() {
3991 Gtk::TreeModelColumn<std::string> visible_name;
3992 Gtk::TreeModelColumn<std::string> fullpath;
3996 CleanupResultsModelColumns results_columns;
3997 Glib::RefPtr<Gtk::ListStore> results_model;
3998 Gtk::TreeView results_display;
4000 results_model = ListStore::create (results_columns);
4001 results_display.set_model (results_model);
4002 results_display.append_column (list_title, results_columns.visible_name);
4004 results_display.set_name ("CleanupResultsList");
4005 results_display.set_headers_visible (true);
4006 results_display.set_headers_clickable (false);
4007 results_display.set_reorderable (false);
4009 Gtk::ScrolledWindow list_scroller;
4012 Gtk::HBox dhbox; // the hbox for the image and text
4013 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4014 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4016 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4018 const string dead_directory = _session->session_directory().dead_path();
4021 %1 - number of files removed
4022 %2 - location of "dead"
4023 %3 - size of files affected
4024 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4027 const char* bprefix;
4028 double space_adjusted = 0;
4030 if (rep.space < 1000) {
4032 space_adjusted = rep.space;
4033 } else if (rep.space < 1000000) {
4034 bprefix = _("kilo");
4035 space_adjusted = floorf((float)rep.space / 1000.0);
4036 } else if (rep.space < 1000000 * 1000) {
4037 bprefix = _("mega");
4038 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4040 bprefix = _("giga");
4041 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4045 txt.set_markup (string_compose (P_("\
4046 The following file was deleted from %2,\n\
4047 releasing %3 %4bytes of disk space", "\
4048 The following %1 files were deleted from %2,\n\
4049 releasing %3 %4bytes of disk space", removed),
4050 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4052 txt.set_markup (string_compose (P_("\
4053 The following file was not in use and \n\
4054 has been moved to: %2\n\n\
4055 After a restart of %5\n\n\
4056 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4057 will release an additional %3 %4bytes of disk space.\n", "\
4058 The following %1 files were not in use and \n\
4059 have been moved to: %2\n\n\
4060 After a restart of %5\n\n\
4061 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4062 will release an additional %3 %4bytes of disk space.\n", removed),
4063 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4066 dhbox.pack_start (*dimage, true, false, 5);
4067 dhbox.pack_start (txt, true, false, 5);
4069 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4070 TreeModel::Row row = *(results_model->append());
4071 row[results_columns.visible_name] = *i;
4072 row[results_columns.fullpath] = *i;
4075 list_scroller.add (results_display);
4076 list_scroller.set_size_request (-1, 150);
4077 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4079 dvbox.pack_start (dhbox, true, false, 5);
4080 dvbox.pack_start (list_scroller, true, false, 5);
4081 ddhbox.pack_start (dvbox, true, false, 5);
4083 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4084 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4085 results.set_default_response (RESPONSE_CLOSE);
4086 results.set_position (Gtk::WIN_POS_MOUSE);
4088 results_display.show();
4089 list_scroller.show();
4096 //results.get_vbox()->show();
4097 results.set_resizable (false);
4104 ARDOUR_UI::cleanup ()
4106 if (_session == 0) {
4107 /* shouldn't happen: menu item is insensitive */
4112 MessageDialog checker (_("Are you sure you want to clean-up?"),
4114 Gtk::MESSAGE_QUESTION,
4117 checker.set_title (_("Clean-up"));
4119 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4120 ALL undo/redo information will be lost if you clean-up.\n\
4121 Clean-up will move all unused files to a \"dead\" location."));
4123 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4124 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4125 checker.set_default_response (RESPONSE_CANCEL);
4127 checker.set_name (_("CleanupDialog"));
4128 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4129 checker.set_position (Gtk::WIN_POS_MOUSE);
4131 switch (checker.run()) {
4132 case RESPONSE_ACCEPT:
4138 ARDOUR::CleanupReport rep;
4140 editor->prepare_for_cleanup ();
4142 /* do not allow flush until a session is reloaded */
4144 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4146 act->set_sensitive (false);
4149 if (_session->cleanup_sources (rep)) {
4150 editor->finish_cleanup ();
4154 editor->finish_cleanup ();
4157 display_cleanup_results (rep, _("Cleaned Files"), false);
4161 ARDOUR_UI::flush_trash ()
4163 if (_session == 0) {
4164 /* shouldn't happen: menu item is insensitive */
4168 ARDOUR::CleanupReport rep;
4170 if (_session->cleanup_trash_sources (rep)) {
4174 display_cleanup_results (rep, _("deleted file"), true);
4178 ARDOUR_UI::cleanup_peakfiles ()
4180 if (_session == 0) {
4181 /* shouldn't happen: menu item is insensitive */
4185 if (! _session->can_cleanup_peakfiles ()) {
4189 // get all region-views in this session
4191 TrackViewList empty;
4193 editor->get_regions_after(rs, (framepos_t) 0, empty);
4194 std::list<RegionView*> views = rs.by_layer();
4196 // remove displayed audio-region-views waveforms
4197 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4198 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4199 if (!arv) { continue ; }
4200 arv->delete_waves();
4203 // cleanup peak files:
4204 // - stop pending peakfile threads
4205 // - close peakfiles if any
4206 // - remove peak dir in session
4207 // - setup peakfiles (background thread)
4208 _session->cleanup_peakfiles ();
4210 // re-add waves to ARV
4211 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4212 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4213 if (!arv) { continue ; }
4214 arv->create_waves();
4218 PresentationInfo::order_t
4219 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4221 if (editor->get_selection().tracks.empty()) {
4222 return PresentationInfo::max_order;
4225 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4228 we want the new routes to have their order keys set starting from
4229 the highest order key in the selection + 1 (if available).
4232 if (place == RouteDialogs::AfterSelection) {
4233 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4235 order_hint = rtav->route()->presentation_info().order();
4238 } else if (place == RouteDialogs::BeforeSelection) {
4239 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4241 order_hint = rtav->route()->presentation_info().order();
4243 } else if (place == RouteDialogs::First) {
4246 /* leave order_hint at max_order */
4253 ARDOUR_UI::start_duplicate_routes ()
4255 if (!duplicate_routes_dialog) {
4256 duplicate_routes_dialog = new DuplicateRouteDialog;
4259 if (duplicate_routes_dialog->restart (_session)) {
4263 duplicate_routes_dialog->present ();
4267 ARDOUR_UI::add_route ()
4269 if (!add_route_dialog.get (false)) {
4270 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4277 if (add_route_dialog->is_visible()) {
4278 /* we're already doing this */
4282 add_route_dialog->set_position (WIN_POS_MOUSE);
4283 add_route_dialog->present();
4287 ARDOUR_UI::add_route_dialog_response (int r)
4292 case AddRouteDialog::Add:
4294 case AddRouteDialog::AddAndClose:
4295 add_route_dialog->ArdourDialog::on_response (r);
4298 add_route_dialog->ArdourDialog::on_response (r);
4302 if ((count = add_route_dialog->count()) <= 0) {
4306 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4307 string template_path = add_route_dialog->track_template();
4308 DisplaySuspender ds;
4310 if (!template_path.empty()) {
4311 if (add_route_dialog->name_template_is_default()) {
4312 _session->new_route_from_template (count, order, template_path, string());
4314 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4319 ChanCount input_chan= add_route_dialog->channels ();
4320 ChanCount output_chan;
4321 string name_template = add_route_dialog->name_template ();
4322 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4323 RouteGroup* route_group = add_route_dialog->route_group ();
4324 AutoConnectOption oac = Config->get_output_auto_connect();
4325 bool strict_io = add_route_dialog->use_strict_io ();
4327 if (oac & AutoConnectMaster) {
4328 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4329 output_chan.set (DataType::MIDI, 0);
4331 output_chan = input_chan;
4334 /* XXX do something with name template */
4336 Session::ProcessorChangeBlocker pcb (_session);
4338 switch (add_route_dialog->type_wanted()) {
4339 case AddRouteDialog::AudioTrack:
4340 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4342 case AddRouteDialog::MidiTrack:
4343 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4345 case AddRouteDialog::MixedTrack:
4346 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4348 case AddRouteDialog::AudioBus:
4349 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4351 case AddRouteDialog::MidiBus:
4352 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4354 case AddRouteDialog::VCAMaster:
4355 session_add_vca (name_template, count);
4361 ARDOUR_UI::stop_video_server (bool ask_confirm)
4363 if (!video_server_process && ask_confirm) {
4364 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4366 if (video_server_process) {
4368 ArdourDialog confirm (_("Stop Video-Server"), true);
4369 Label m (_("Do you really want to stop the Video Server?"));
4370 confirm.get_vbox()->pack_start (m, true, true);
4371 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4372 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4373 confirm.show_all ();
4374 if (confirm.run() == RESPONSE_CANCEL) {
4378 delete video_server_process;
4379 video_server_process =0;
4384 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4386 ARDOUR_UI::start_video_server( float_window, true);
4390 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4396 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4397 if (video_server_process) {
4398 popup_error(_("The Video Server is already started."));
4400 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4406 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4408 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4410 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4412 video_server_dialog->set_transient_for (*float_window);
4415 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4416 video_server_dialog->hide();
4418 ResponseType r = (ResponseType) video_server_dialog->run ();
4419 video_server_dialog->hide();
4420 if (r != RESPONSE_ACCEPT) { return false; }
4421 if (video_server_dialog->show_again()) {
4422 Config->set_show_video_server_dialog(false);
4426 std::string icsd_exec = video_server_dialog->get_exec_path();
4427 std::string icsd_docroot = video_server_dialog->get_docroot();
4428 #ifndef PLATFORM_WINDOWS
4429 if (icsd_docroot.empty()) {
4430 icsd_docroot = VideoUtils::video_get_docroot (Config);
4435 #ifdef PLATFORM_WINDOWS
4436 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4437 /* OK, allow all drive letters */
4440 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4441 warning << _("Specified docroot is not an existing directory.") << endmsg;
4444 #ifndef PLATFORM_WINDOWS
4445 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4446 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4447 warning << _("Given Video Server is not an executable file.") << endmsg;
4451 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4452 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4453 warning << _("Given Video Server is not an executable file.") << endmsg;
4459 argp=(char**) calloc(9,sizeof(char*));
4460 argp[0] = strdup(icsd_exec.c_str());
4461 argp[1] = strdup("-P");
4462 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4463 argp[3] = strdup("-p");
4464 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4465 argp[5] = strdup("-C");
4466 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4467 argp[7] = strdup(icsd_docroot.c_str());
4469 stop_video_server();
4471 #ifdef PLATFORM_WINDOWS
4472 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4473 /* OK, allow all drive letters */
4476 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4477 Config->set_video_advanced_setup(false);
4479 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4480 Config->set_video_server_url(url_str);
4481 Config->set_video_server_docroot(icsd_docroot);
4482 Config->set_video_advanced_setup(true);
4485 if (video_server_process) {
4486 delete video_server_process;
4489 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4490 if (video_server_process->start()) {
4491 warning << _("Cannot launch the video-server") << endmsg;
4494 int timeout = 120; // 6 sec
4495 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4496 Glib::usleep (50000);
4498 if (--timeout <= 0 || !video_server_process->is_running()) break;
4501 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4503 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4504 delete video_server_process;
4505 video_server_process = 0;
4513 ARDOUR_UI::add_video (Gtk::Window* float_window)
4519 if (!start_video_server(float_window, false)) {
4520 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4525 add_video_dialog->set_transient_for (*float_window);
4528 if (add_video_dialog->is_visible()) {
4529 /* we're already doing this */
4533 ResponseType r = (ResponseType) add_video_dialog->run ();
4534 add_video_dialog->hide();
4535 if (r != RESPONSE_ACCEPT) { return; }
4537 bool local_file, orig_local_file;
4538 std::string path = add_video_dialog->file_name(local_file);
4540 std::string orig_path = path;
4541 orig_local_file = local_file;
4543 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4545 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4546 warning << string_compose(_("could not open %1"), path) << endmsg;
4549 if (!local_file && path.length() == 0) {
4550 warning << _("no video-file selected") << endmsg;
4554 std::string audio_from_video;
4555 bool detect_ltc = false;
4557 switch (add_video_dialog->import_option()) {
4558 case VTL_IMPORT_TRANSCODE:
4560 TranscodeVideoDialog *transcode_video_dialog;
4561 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4562 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4563 transcode_video_dialog->hide();
4564 if (r != RESPONSE_ACCEPT) {
4565 delete transcode_video_dialog;
4569 audio_from_video = transcode_video_dialog->get_audiofile();
4571 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4574 else if (!audio_from_video.empty()) {
4575 editor->embed_audio_from_video(
4577 video_timeline->get_offset(),
4578 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4581 switch (transcode_video_dialog->import_option()) {
4582 case VTL_IMPORT_TRANSCODED:
4583 path = transcode_video_dialog->get_filename();
4586 case VTL_IMPORT_REFERENCE:
4589 delete transcode_video_dialog;
4592 delete transcode_video_dialog;
4596 case VTL_IMPORT_NONE:
4600 /* strip _session->session_directory().video_path() from video file if possible */
4601 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4602 path=path.substr(_session->session_directory().video_path().size());
4603 if (path.at(0) == G_DIR_SEPARATOR) {
4604 path=path.substr(1);
4608 video_timeline->set_update_session_fps(auto_set_session_fps);
4610 if (video_timeline->video_file_info(path, local_file)) {
4611 XMLNode* node = new XMLNode(X_("Videotimeline"));
4612 node->set_property (X_("Filename"), path);
4613 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4614 node->set_property (X_("LocalFile"), local_file);
4615 if (orig_local_file) {
4616 node->set_property (X_("OriginalVideoFile"), orig_path);
4618 node->remove_property (X_("OriginalVideoFile"));
4620 _session->add_extra_xml (*node);
4621 _session->set_dirty ();
4623 if (!audio_from_video.empty() && detect_ltc) {
4624 std::vector<LTCFileReader::LTCMap> ltc_seq;
4627 /* TODO ask user about TV standard (LTC alignment if any) */
4628 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4629 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4631 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4633 /* TODO seek near end of file, and read LTC until end.
4634 * if it fails to find any LTC frames, scan complete file
4636 * calculate drift of LTC compared to video-duration,
4637 * ask user for reference (timecode from start/mid/end)
4640 // LTCFileReader will have written error messages
4643 ::g_unlink(audio_from_video.c_str());
4645 if (ltc_seq.size() == 0) {
4646 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4648 /* the very first TC in the file is somteimes not aligned properly */
4649 int i = ltc_seq.size() -1;
4650 ARDOUR::frameoffset_t video_start_offset =
4651 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4652 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4653 video_timeline->set_offset(video_start_offset);
4657 _session->maybe_update_session_range(
4658 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4659 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4662 if (add_video_dialog->launch_xjadeo() && local_file) {
4663 editor->set_xjadeo_sensitive(true);
4664 editor->toggle_xjadeo_proc(1);
4666 editor->toggle_xjadeo_proc(0);
4668 editor->toggle_ruler_video(true);
4673 ARDOUR_UI::remove_video ()
4675 video_timeline->close_session();
4676 editor->toggle_ruler_video(false);
4679 video_timeline->set_offset_locked(false);
4680 video_timeline->set_offset(0);
4682 /* delete session state */
4683 XMLNode* node = new XMLNode(X_("Videotimeline"));
4684 _session->add_extra_xml(*node);
4685 node = new XMLNode(X_("Videomonitor"));
4686 _session->add_extra_xml(*node);
4687 node = new XMLNode(X_("Videoexport"));
4688 _session->add_extra_xml(*node);
4689 stop_video_server();
4693 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4695 if (localcacheonly) {
4696 video_timeline->vmon_update();
4698 video_timeline->flush_cache();
4700 editor->queue_visual_videotimeline_update();
4704 ARDOUR_UI::export_video (bool range)
4706 if (ARDOUR::Config->get_show_video_export_info()) {
4707 ExportVideoInfobox infobox (_session);
4708 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4709 if (infobox.show_again()) {
4710 ARDOUR::Config->set_show_video_export_info(false);
4713 case GTK_RESPONSE_YES:
4714 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4720 export_video_dialog->set_session (_session);
4721 export_video_dialog->apply_state(editor->get_selection().time, range);
4722 export_video_dialog->run ();
4723 export_video_dialog->hide ();
4727 ARDOUR_UI::preferences_settings () const
4732 node = _session->instant_xml(X_("Preferences"));
4734 node = Config->instant_xml(X_("Preferences"));
4738 node = new XMLNode (X_("Preferences"));
4745 ARDOUR_UI::mixer_settings () const
4750 node = _session->instant_xml(X_("Mixer"));
4752 node = Config->instant_xml(X_("Mixer"));
4756 node = new XMLNode (X_("Mixer"));
4763 ARDOUR_UI::main_window_settings () const
4768 node = _session->instant_xml(X_("Main"));
4770 node = Config->instant_xml(X_("Main"));
4774 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4775 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4780 node = new XMLNode (X_("Main"));
4787 ARDOUR_UI::editor_settings () const
4792 node = _session->instant_xml(X_("Editor"));
4794 node = Config->instant_xml(X_("Editor"));
4798 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4799 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4804 node = new XMLNode (X_("Editor"));
4811 ARDOUR_UI::keyboard_settings () const
4815 node = Config->extra_xml(X_("Keyboard"));
4818 node = new XMLNode (X_("Keyboard"));
4825 ARDOUR_UI::create_xrun_marker (framepos_t where)
4828 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4829 _session->locations()->add (location);
4834 ARDOUR_UI::halt_on_xrun_message ()
4836 cerr << "HALT on xrun\n";
4837 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4842 ARDOUR_UI::xrun_handler (framepos_t where)
4848 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4850 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4851 create_xrun_marker(where);
4854 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4855 halt_on_xrun_message ();
4860 ARDOUR_UI::disk_overrun_handler ()
4862 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4864 if (!have_disk_speed_dialog_displayed) {
4865 have_disk_speed_dialog_displayed = true;
4866 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4867 The disk system on your computer\n\
4868 was not able to keep up with %1.\n\
4870 Specifically, it failed to write data to disk\n\
4871 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4872 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4878 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4879 static MessageDialog *scan_dlg = NULL;
4880 static ProgressBar *scan_pbar = NULL;
4881 static HBox *scan_tbox = NULL;
4882 static Gtk::Button *scan_timeout_button;
4885 ARDOUR_UI::cancel_plugin_scan ()
4887 PluginManager::instance().cancel_plugin_scan();
4891 ARDOUR_UI::cancel_plugin_timeout ()
4893 PluginManager::instance().cancel_plugin_timeout();
4894 scan_timeout_button->set_sensitive (false);
4898 ARDOUR_UI::plugin_scan_timeout (int timeout)
4900 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4904 scan_pbar->set_sensitive (false);
4905 scan_timeout_button->set_sensitive (true);
4906 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4909 scan_pbar->set_sensitive (false);
4910 scan_timeout_button->set_sensitive (false);
4916 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4918 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4922 const bool cancelled = PluginManager::instance().cancelled();
4923 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4924 if (cancelled && scan_dlg->is_mapped()) {
4929 if (cancelled || !can_cancel) {
4934 static Gtk::Button *cancel_button;
4936 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4937 VBox* vbox = scan_dlg->get_vbox();
4938 vbox->set_size_request(400,-1);
4939 scan_dlg->set_title (_("Scanning for plugins"));
4941 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4942 cancel_button->set_name ("EditorGTKButton");
4943 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4944 cancel_button->show();
4946 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4948 scan_tbox = manage( new HBox() );
4950 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4951 scan_timeout_button->set_name ("EditorGTKButton");
4952 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4953 scan_timeout_button->show();
4955 scan_pbar = manage(new ProgressBar());
4956 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4957 scan_pbar->set_text(_("Scan Timeout"));
4960 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4961 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4963 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4966 assert(scan_dlg && scan_tbox && cancel_button);
4968 if (type == X_("closeme")) {
4972 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4975 if (!can_cancel || !cancelled) {
4976 scan_timeout_button->set_sensitive(false);
4978 cancel_button->set_sensitive(can_cancel && !cancelled);
4984 ARDOUR_UI::gui_idle_handler ()
4987 /* due to idle calls, gtk_events_pending() may always return true */
4988 while (gtk_events_pending() && --timeout) {
4989 gtk_main_iteration ();
4994 ARDOUR_UI::disk_underrun_handler ()
4996 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4998 if (!have_disk_speed_dialog_displayed) {
4999 have_disk_speed_dialog_displayed = true;
5000 MessageDialog* msg = new MessageDialog (
5001 _main_window, string_compose (_("The disk system on your computer\n\
5002 was not able to keep up with %1.\n\
5004 Specifically, it failed to read data from disk\n\
5005 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5006 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5012 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5014 have_disk_speed_dialog_displayed = false;
5019 ARDOUR_UI::session_dialog (std::string msg)
5021 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5025 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5032 ARDOUR_UI::pending_state_dialog ()
5034 HBox* hbox = manage (new HBox());
5035 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5036 ArdourDialog dialog (_("Crash Recovery"), true);
5037 Label message (string_compose (_("\
5038 This session appears to have been in the\n\
5039 middle of recording when %1 or\n\
5040 the computer was shutdown.\n\
5042 %1 can recover any captured audio for\n\
5043 you, or it can ignore it. Please decide\n\
5044 what you would like to do.\n"), PROGRAM_NAME));
5045 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5046 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5047 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5048 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5049 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5050 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5051 dialog.set_default_response (RESPONSE_ACCEPT);
5052 dialog.set_position (WIN_POS_CENTER);
5057 switch (dialog.run ()) {
5058 case RESPONSE_ACCEPT:
5066 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5068 HBox* hbox = new HBox();
5069 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5070 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5071 Label message (string_compose (_("\
5072 This session was created with a sample rate of %1 Hz, but\n\
5073 %2 is currently running at %3 Hz. If you load this session,\n\
5074 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5076 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5077 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5078 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5079 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5080 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5081 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5082 dialog.set_default_response (RESPONSE_ACCEPT);
5083 dialog.set_position (WIN_POS_CENTER);
5088 switch (dialog.run()) {
5089 case RESPONSE_ACCEPT:
5099 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5101 MessageDialog msg (string_compose (_("\
5102 This session was created with a sample rate of %1 Hz, but\n\
5103 %2 is currently running at %3 Hz.\n\
5104 Audio will be recorded and played at the wrong sample rate.\n\
5105 Re-Configure the Audio Engine in\n\
5106 Menu > Window > Audio/Midi Setup"),
5107 desired, PROGRAM_NAME, actual),
5109 Gtk::MESSAGE_WARNING);
5114 ARDOUR_UI::use_config ()
5116 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5118 set_transport_controllable_state (*node);
5123 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5125 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5126 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5128 primary_clock->set (pos);
5131 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5132 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5134 secondary_clock->set (pos);
5137 if (big_clock_window) {
5138 big_clock->set (pos);
5140 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5144 ARDOUR_UI::step_edit_status_change (bool yn)
5146 // XXX should really store pre-step edit status of things
5147 // we make insensitive
5150 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5151 rec_button.set_sensitive (false);
5153 rec_button.unset_active_state ();;
5154 rec_button.set_sensitive (true);
5159 ARDOUR_UI::record_state_changed ()
5161 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5164 /* why bother - the clock isn't visible */
5168 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5170 if (big_clock_window) {
5171 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5172 big_clock->set_active (true);
5174 big_clock->set_active (false);
5181 ARDOUR_UI::first_idle ()
5184 _session->allow_auto_play (true);
5188 editor->first_idle();
5191 Keyboard::set_can_save_keybindings (true);
5196 ARDOUR_UI::store_clock_modes ()
5198 XMLNode* node = new XMLNode(X_("ClockModes"));
5200 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5201 XMLNode* child = new XMLNode (X_("Clock"));
5203 child->set_property (X_("name"), (*x)->name());
5204 child->set_property (X_("mode"), (*x)->mode());
5205 child->set_property (X_("on"), (*x)->on());
5207 node->add_child_nocopy (*child);
5210 _session->add_extra_xml (*node);
5211 _session->set_dirty ();
5214 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5215 : Controllable (name), ui (u), type(tp)
5221 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5224 /* do nothing: these are radio-style actions */
5228 const char *action = 0;
5232 action = X_("Roll");
5235 action = X_("Stop");
5238 action = X_("GotoStart");
5241 action = X_("GotoEnd");
5244 action = X_("Loop");
5247 action = X_("PlaySelection");
5250 action = X_("Record");
5260 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5268 ARDOUR_UI::TransportControllable::get_value (void) const
5295 ARDOUR_UI::setup_profile ()
5297 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5298 Profile->set_small_screen ();
5301 if (g_getenv ("TRX")) {
5302 Profile->set_trx ();
5305 if (g_getenv ("MIXBUS")) {
5306 Profile->set_mixbus ();
5311 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5313 MissingFileDialog dialog (s, str, type);
5318 int result = dialog.run ();
5325 return 1; // quit entire session load
5328 result = dialog.get_action ();
5334 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5336 AmbiguousFileDialog dialog (file, hits);
5343 return dialog.get_which ();
5346 /** Allocate our thread-local buffers */
5348 ARDOUR_UI::get_process_buffers ()
5350 _process_thread->get_buffers ();
5353 /** Drop our thread-local buffers */
5355 ARDOUR_UI::drop_process_buffers ()
5357 _process_thread->drop_buffers ();
5361 ARDOUR_UI::feedback_detected ()
5363 _feedback_exists = true;
5367 ARDOUR_UI::successful_graph_sort ()
5369 _feedback_exists = false;
5373 ARDOUR_UI::midi_panic ()
5376 _session->midi_panic();
5381 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5383 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5384 const char* end_big = "</span>";
5385 const char* start_mono = "<tt>";
5386 const char* end_mono = "</tt>";
5388 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5389 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5390 "From now on, use the backup copy with older versions of %3"),
5391 xml_path, backup_path, PROGRAM_NAME,
5393 start_mono, end_mono), true);
5399 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5401 using namespace Menu_Helpers;
5403 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5404 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5405 i->set_active (editor_meter->meter_type () == type);
5409 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5411 using namespace Gtk::Menu_Helpers;
5413 Gtk::Menu* m = manage (new Menu);
5414 MenuList& items = m->items ();
5416 RadioMenuItem::Group group;
5418 _suspend_editor_meter_callbacks = true;
5419 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5420 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5421 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5422 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5423 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5424 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5425 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5426 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5427 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5428 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5429 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5431 m->popup (ev->button, ev->time);
5432 _suspend_editor_meter_callbacks = false;
5436 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5438 if (ev->button == 3 && editor_meter) {
5439 popup_editor_meter_menu (ev);
5446 ARDOUR_UI::reset_peak_display ()
5448 if (!_session || !_session->master_out() || !editor_meter) return;
5449 editor_meter->clear_meters();
5450 editor_meter_max_peak = -INFINITY;
5451 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5455 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5457 if (!_session || !_session->master_out()) return;
5458 if (group == _session->master_out()->route_group()) {
5459 reset_peak_display ();
5464 ARDOUR_UI::reset_route_peak_display (Route* route)
5466 if (!_session || !_session->master_out()) return;
5467 if (_session->master_out().get() == route) {
5468 reset_peak_display ();
5473 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5475 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5476 audio_midi_setup->set_position (WIN_POS_CENTER);
5478 if (desired_sample_rate != 0) {
5479 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5480 audio_midi_setup->try_autostart ();
5481 if (ARDOUR::AudioEngine::instance()->running()) {
5488 int response = audio_midi_setup->run();
5490 case Gtk::RESPONSE_DELETE_EVENT:
5491 // after latency callibration engine may run,
5492 // Running() signal was emitted, but dialog will not
5493 // have emitted a response. The user needs to close
5494 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5495 if (!AudioEngine::instance()->running()) {
5500 if (!AudioEngine::instance()->running()) {
5503 audio_midi_setup->hide ();
5511 ARDOUR_UI::transport_numpad_timeout ()
5513 _numpad_locate_happening = false;
5514 if (_numpad_timeout_connection.connected() )
5515 _numpad_timeout_connection.disconnect();
5520 ARDOUR_UI::transport_numpad_decimal ()
5522 _numpad_timeout_connection.disconnect();
5524 if (_numpad_locate_happening) {
5525 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5526 _numpad_locate_happening = false;
5528 _pending_locate_num = 0;
5529 _numpad_locate_happening = true;
5530 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5535 ARDOUR_UI::transport_numpad_event (int num)
5537 if ( _numpad_locate_happening ) {
5538 _pending_locate_num = _pending_locate_num*10 + num;
5541 case 0: toggle_roll(false, false); break;
5542 case 1: transport_rewind(1); break;
5543 case 2: transport_forward(1); break;
5544 case 3: transport_record(true); break;
5545 case 4: toggle_session_auto_loop(); break;
5546 case 5: transport_record(false); toggle_session_auto_loop(); break;
5547 case 6: toggle_punch(); break;
5548 case 7: toggle_click(); break;
5549 case 8: toggle_auto_return(); break;
5550 case 9: toggle_follow_edits(); break;
5556 ARDOUR_UI::set_flat_buttons ()
5558 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5562 ARDOUR_UI::audioengine_became_silent ()
5564 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5566 Gtk::MESSAGE_WARNING,
5570 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5572 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5573 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5574 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5575 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5576 Gtk::HBox pay_button_box;
5577 Gtk::HBox subscribe_button_box;
5579 pay_button_box.pack_start (pay_button, true, false);
5580 subscribe_button_box.pack_start (subscribe_button, true, false);
5582 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 */
5584 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5585 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5587 msg.get_vbox()->pack_start (pay_label);
5588 msg.get_vbox()->pack_start (pay_button_box);
5589 msg.get_vbox()->pack_start (subscribe_label);
5590 msg.get_vbox()->pack_start (subscribe_button_box);
5592 msg.get_vbox()->show_all ();
5594 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5595 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5596 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5601 case Gtk::RESPONSE_YES:
5602 AudioEngine::instance()->reset_silence_countdown ();
5605 case Gtk::RESPONSE_NO:
5607 save_state_canfail ("");
5611 case Gtk::RESPONSE_CANCEL:
5613 /* don't reset, save session and exit */
5619 ARDOUR_UI::hide_application ()
5621 Application::instance ()-> hide ();
5625 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5627 /* icons, titles, WM stuff */
5629 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5631 if (window_icons.empty()) {
5632 Glib::RefPtr<Gdk::Pixbuf> icon;
5633 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5634 window_icons.push_back (icon);
5636 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5637 window_icons.push_back (icon);
5639 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5640 window_icons.push_back (icon);
5642 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5643 window_icons.push_back (icon);
5647 if (!window_icons.empty()) {
5648 window.set_default_icon_list (window_icons);
5651 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5653 if (!name.empty()) {
5657 window.set_title (title.get_string());
5658 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5660 window.set_flags (CAN_FOCUS);
5661 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5663 /* This is a hack to ensure that GTK-accelerators continue to
5664 * work. Once we switch over to entirely native bindings, this will be
5665 * unnecessary and should be removed
5667 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5669 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5670 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5671 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5672 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5676 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5678 Gtkmm2ext::Bindings* bindings = 0;
5679 Gtk::Window* window = 0;
5681 /* until we get ardour bindings working, we are not handling key
5685 if (ev->type != GDK_KEY_PRESS) {
5689 if (event_window == &_main_window) {
5691 window = event_window;
5693 /* find current tab contents */
5695 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5697 /* see if it uses the ardour binding system */
5700 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5703 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5707 window = event_window;
5709 /* see if window uses ardour binding system */
5711 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5714 /* An empty binding set is treated as if it doesn't exist */
5716 if (bindings && bindings->empty()) {
5720 return key_press_focus_accelerator_handler (*window, ev, bindings);
5723 static Gtkmm2ext::Bindings*
5724 get_bindings_from_widget_heirarchy (GtkWidget** w)
5729 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5732 *w = gtk_widget_get_parent (*w);
5735 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5739 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5741 GtkWindow* win = window.gobj();
5742 GtkWidget* focus = gtk_window_get_focus (win);
5743 GtkWidget* binding_widget = focus;
5744 bool special_handling_of_unmodified_accelerators = false;
5745 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5749 /* some widget has keyboard focus */
5751 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5753 /* A particular kind of focusable widget currently has keyboard
5754 * focus. All unmodified key events should go to that widget
5755 * first and not be used as an accelerator by default
5758 special_handling_of_unmodified_accelerators = true;
5762 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5763 if (focus_bindings) {
5764 bindings = focus_bindings;
5765 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5770 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",
5773 Gtkmm2ext::show_gdk_event_state (ev->state),
5774 special_handling_of_unmodified_accelerators,
5775 Keyboard::some_magic_widget_has_focus(),
5777 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5778 ((ev->state & mask) ? "yes" : "no"),
5779 window.get_title()));
5781 /* This exists to allow us to override the way GTK handles
5782 key events. The normal sequence is:
5784 a) event is delivered to a GtkWindow
5785 b) accelerators/mnemonics are activated
5786 c) if (b) didn't handle the event, propagate to
5787 the focus widget and/or focus chain
5789 The problem with this is that if the accelerators include
5790 keys without modifiers, such as the space bar or the
5791 letter "e", then pressing the key while typing into
5792 a text entry widget results in the accelerator being
5793 activated, instead of the desired letter appearing
5796 There is no good way of fixing this, but this
5797 represents a compromise. The idea is that
5798 key events involving modifiers (not Shift)
5799 get routed into the activation pathway first, then
5800 get propagated to the focus widget if necessary.
5802 If the key event doesn't involve modifiers,
5803 we deliver to the focus widget first, thus allowing
5804 it to get "normal text" without interference
5807 Of course, this can also be problematic: if there
5808 is a widget with focus, then it will swallow
5809 all "normal text" accelerators.
5813 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5815 /* no special handling or there are modifiers in effect: accelerate first */
5817 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5818 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5819 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5821 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5822 KeyboardKey k (ev->state, ev->keyval);
5826 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5828 if (bindings->activate (k, Bindings::Press)) {
5829 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5833 if (binding_widget) {
5834 binding_widget = gtk_widget_get_parent (binding_widget);
5835 if (binding_widget) {
5836 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5845 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5847 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5848 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5852 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5854 if (gtk_window_propagate_key_event (win, ev)) {
5855 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5861 /* no modifiers, propagate first */
5863 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5865 if (gtk_window_propagate_key_event (win, ev)) {
5866 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5870 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5871 KeyboardKey k (ev->state, ev->keyval);
5875 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5878 if (bindings->activate (k, Bindings::Press)) {
5879 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5883 if (binding_widget) {
5884 binding_widget = gtk_widget_get_parent (binding_widget);
5885 if (binding_widget) {
5886 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5895 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5897 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5898 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5903 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5908 ARDOUR_UI::load_bindings ()
5910 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5911 error << _("Global keybindings are missing") << endmsg;
5916 ARDOUR_UI::cancel_solo ()
5919 _session->cancel_all_solo ();
5924 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5926 /* this resets focus to the first focusable parent of the given widget,
5927 * or, if there is no focusable parent, cancels focus in the toplevel
5928 * window that the given widget is packed into (if there is one).
5935 Gtk::Widget* top = w->get_toplevel();
5937 if (!top || !top->is_toplevel()) {
5941 w = w->get_parent ();
5945 if (w->is_toplevel()) {
5946 /* Setting the focus widget to a Gtk::Window causes all
5947 * subsequent calls to ::has_focus() on the nominal
5948 * focus widget in that window to return
5949 * false. Workaround: never set focus to the toplevel
5955 if (w->get_can_focus ()) {
5956 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5957 win->set_focus (*w);
5960 w = w->get_parent ();
5963 if (top == &_main_window) {
5967 /* no focusable parent found, cancel focus in top level window.
5968 C++ API cannot be used for this. Thanks, references.
5971 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);