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/unwind.h"
66 #include "pbd/file_utils.h"
67 #include "pbd/localtime_r.h"
68 #include "pbd/pthread_utils.h"
69 #include "pbd/replace_all.h"
70 #include "pbd/scoped_file_descriptor.h"
71 #include "pbd/xml++.h"
73 #include "gtkmm2ext/application.h"
74 #include "gtkmm2ext/bindings.h"
75 #include "gtkmm2ext/gtk_ui.h"
76 #include "gtkmm2ext/utils.h"
77 #include "gtkmm2ext/click_box.h"
78 #include "gtkmm2ext/fastmeter.h"
79 #include "gtkmm2ext/popup.h"
80 #include "gtkmm2ext/window_title.h"
82 #include "ardour/ardour.h"
83 #include "ardour/audio_backend.h"
84 #include "ardour/audio_track.h"
85 #include "ardour/audioengine.h"
86 #include "ardour/audiofilesource.h"
87 #include "ardour/automation_watch.h"
88 #include "ardour/diskstream.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/filesystem_paths.h"
91 #include "ardour/ltc_file_reader.h"
92 #include "ardour/midi_track.h"
93 #include "ardour/port.h"
94 #include "ardour/plugin_manager.h"
95 #include "ardour/process_thread.h"
96 #include "ardour/profile.h"
97 #include "ardour/recent_sessions.h"
98 #include "ardour/record_enable_control.h"
99 #include "ardour/revision.h"
100 #include "ardour/session_directory.h"
101 #include "ardour/session_route.h"
102 #include "ardour/session_state_utils.h"
103 #include "ardour/session_utils.h"
104 #include "ardour/source_factory.h"
105 #include "ardour/slave.h"
106 #include "ardour/system_exec.h"
107 #include "ardour/track.h"
108 #include "ardour/vca_manager.h"
109 #include "ardour/utils.h"
111 #include "LuaBridge/LuaBridge.h"
113 #ifdef WINDOWS_VST_SUPPORT
116 #ifdef AUDIOUNIT_SUPPORT
117 #include "ardour/audio_unit.h"
120 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
125 #include "timecode/time.h"
127 typedef uint64_t microseconds_t;
131 #include "enums_convert.h"
133 #include "add_route_dialog.h"
134 #include "ambiguous_file_dialog.h"
135 #include "ardour_ui.h"
136 #include "audio_clock.h"
137 #include "audio_region_view.h"
138 #include "big_clock_window.h"
139 #include "bundle_manager.h"
140 #include "duplicate_routes_dialog.h"
142 #include "engine_dialog.h"
143 #include "export_video_dialog.h"
144 #include "export_video_infobox.h"
145 #include "gain_meter.h"
146 #include "global_port_matrix.h"
147 #include "gui_object.h"
148 #include "gui_thread.h"
149 #include "idleometer.h"
150 #include "keyboard.h"
151 #include "keyeditor.h"
152 #include "location_ui.h"
153 #include "lua_script_manager.h"
154 #include "luawindow.h"
155 #include "main_clock.h"
156 #include "missing_file_dialog.h"
157 #include "missing_plugin_dialog.h"
158 #include "mixer_ui.h"
159 #include "meterbridge.h"
160 #include "meter_patterns.h"
161 #include "mouse_cursors.h"
164 #include "pingback.h"
165 #include "processor_box.h"
166 #include "prompter.h"
167 #include "public_editor.h"
168 #include "rc_option_editor.h"
169 #include "route_time_axis.h"
170 #include "route_params_ui.h"
171 #include "save_as_dialog.h"
172 #include "script_selector.h"
173 #include "session_archive_dialog.h"
174 #include "session_dialog.h"
175 #include "session_metadata_dialog.h"
176 #include "session_option_editor.h"
177 #include "speaker_dialog.h"
180 #include "template_dialog.h"
181 #include "time_axis_view_item.h"
182 #include "time_info_box.h"
185 #include "utils_videotl.h"
186 #include "video_server_dialog.h"
187 #include "add_video_dialog.h"
188 #include "transcode_video_dialog.h"
190 #include "pbd/i18n.h"
192 using namespace ARDOUR;
193 using namespace ARDOUR_UI_UTILS;
195 using namespace Gtkmm2ext;
198 using namespace Editing;
200 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
202 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
203 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
206 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
208 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
209 "Would you like these files to be copied and used for %1 %2.x?\n\n"
210 "(This will require you to restart %1.)"),
211 PROGRAM_NAME, PROGRAM_VERSION, version),
212 false, /* no markup */
215 true /* modal, though it hardly matters since it is the only window */
218 msg.set_default_response (Gtk::RESPONSE_YES);
221 return (msg.run() == Gtk::RESPONSE_YES);
225 libxml_generic_error_func (void* /* parsing_context*/,
233 vsnprintf (buf, sizeof (buf), msg, ap);
234 error << buf << endmsg;
239 libxml_structured_error_func (void* /* parsing_context*/,
247 replace_all (msg, "\n", "");
250 if (err->file && err->line) {
251 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
254 error << ':' << err->int2;
259 error << X_("XML error: ") << msg << endmsg;
265 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
266 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
267 , session_loaded (false)
268 , session_load_in_progress (false)
269 , gui_object_state (new GUIObjectState)
270 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
271 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
272 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
274 , global_actions (X_("global"))
275 , ignore_dual_punch (false)
276 , main_window_visibility (0)
281 , _mixer_on_top (false)
282 , _initial_verbose_plugin_scan (false)
283 , first_time_engine_run (true)
284 , secondary_clock_spacer (0)
285 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
286 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
287 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
288 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
289 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
290 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
291 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
292 , auto_input_button (ArdourButton::led_default_elements)
294 , auto_return_button (ArdourButton::led_default_elements)
295 , follow_edits_button (ArdourButton::led_default_elements)
296 , auditioning_alert_button (_("Audition"))
297 , solo_alert_button (_("Solo"))
298 , feedback_alert_button (_("Feedback"))
299 , error_alert_button ( ArdourButton::just_led_default_elements )
301 , editor_meter_peak_display()
302 , _suspend_editor_meter_callbacks (false)
303 , _numpad_locate_happening (false)
304 , _session_is_new (false)
305 , last_key_press_time (0)
309 , rc_option_editor (0)
310 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
311 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
312 , about (X_("about"), _("About"))
313 , location_ui (X_("locations"), S_("Ranges|Locations"))
314 , route_params (X_("inspector"), _("Tracks and Busses"))
315 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
316 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
317 , lua_script_window (X_("script-manager"), _("Script Manager"))
318 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
319 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
320 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
321 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
322 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
323 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
324 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
325 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
326 , video_server_process (0)
328 , have_configure_timeout (false)
329 , last_configure_time (0)
331 , have_disk_speed_dialog_displayed (false)
332 , _status_bar_visibility (X_("status-bar"))
333 , _feedback_exists (false)
334 , _log_not_acknowledged (LogLevelNone)
335 , duplicate_routes_dialog (0)
336 , editor_visibility_button (S_("Window|Editor"))
337 , mixer_visibility_button (S_("Window|Mixer"))
338 , prefs_visibility_button (S_("Window|Preferences"))
340 Gtkmm2ext::init (localedir);
342 UIConfiguration::instance().post_gui_init ();
344 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
346 /* "touch" the been-here-before path now that config has been migrated */
347 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
349 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
351 /* configuration was modified, exit immediately */
356 if (string (VERSIONSTRING).find (".pre") != string::npos) {
357 /* check this is not being run from ./ardev etc. */
358 if (!running_from_source_tree ()) {
359 pre_release_dialog ();
363 if (theArdourUI == 0) {
367 /* track main window visibility */
369 main_window_visibility = new VisibilityTracker (_main_window);
371 /* stop libxml from spewing to stdout/stderr */
373 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
374 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
376 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
377 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
378 UIConfiguration::instance().map_parameters (pc);
380 roll_button.set_controllable (roll_controllable);
381 stop_button.set_controllable (stop_controllable);
382 goto_start_button.set_controllable (goto_start_controllable);
383 goto_end_button.set_controllable (goto_end_controllable);
384 auto_loop_button.set_controllable (auto_loop_controllable);
385 play_selection_button.set_controllable (play_selection_controllable);
386 rec_button.set_controllable (rec_controllable);
388 roll_button.set_name ("transport button");
389 stop_button.set_name ("transport button");
390 goto_start_button.set_name ("transport button");
391 goto_end_button.set_name ("transport button");
392 auto_loop_button.set_name ("transport button");
393 play_selection_button.set_name ("transport button");
394 rec_button.set_name ("transport recenable button");
395 midi_panic_button.set_name ("transport button");
397 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
398 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
400 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
402 /* handle dialog requests */
404 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
406 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
408 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
410 /* handle Audio/MIDI setup when session requires it */
412 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
414 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
416 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
418 /* handle sr mismatch with a dialog - cross-thread from engine */
419 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
421 /* handle requests to quit (coming from JACK session) */
423 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
425 /* tell the user about feedback */
427 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
428 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
430 /* handle requests to deal with missing files */
432 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
434 /* and ambiguous files */
436 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
438 /* also plugin scan messages */
439 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
440 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
442 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
444 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
447 /* lets get this party started */
449 setup_gtk_ardour_enums ();
452 SessionEvent::create_per_thread_pool ("GUI", 4096);
454 /* we like keyboards */
456 keyboard = new ArdourKeyboard(*this);
458 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
460 keyboard->set_state (*node, Stateful::loading_state_version);
463 UIConfiguration::instance().reset_dpi ();
465 TimeAxisViewItem::set_constant_heights ();
467 /* Set this up so that our window proxies can register actions */
469 ActionManager::init ();
471 /* The following must happen after ARDOUR::init() so that Config is set up */
473 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
476 key_editor.set_state (*ui_xml, 0);
477 session_option_editor.set_state (*ui_xml, 0);
478 speaker_config_window.set_state (*ui_xml, 0);
479 about.set_state (*ui_xml, 0);
480 add_route_dialog.set_state (*ui_xml, 0);
481 add_video_dialog.set_state (*ui_xml, 0);
482 route_params.set_state (*ui_xml, 0);
483 bundle_manager.set_state (*ui_xml, 0);
484 location_ui.set_state (*ui_xml, 0);
485 big_clock_window.set_state (*ui_xml, 0);
486 audio_port_matrix.set_state (*ui_xml, 0);
487 midi_port_matrix.set_state (*ui_xml, 0);
488 export_video_dialog.set_state (*ui_xml, 0);
489 lua_script_window.set_state (*ui_xml, 0);
490 idleometer.set_state (*ui_xml, 0);
493 /* Separate windows */
495 WM::Manager::instance().register_window (&key_editor);
496 WM::Manager::instance().register_window (&session_option_editor);
497 WM::Manager::instance().register_window (&speaker_config_window);
498 WM::Manager::instance().register_window (&about);
499 WM::Manager::instance().register_window (&add_route_dialog);
500 WM::Manager::instance().register_window (&add_video_dialog);
501 WM::Manager::instance().register_window (&route_params);
502 WM::Manager::instance().register_window (&audio_midi_setup);
503 WM::Manager::instance().register_window (&export_video_dialog);
504 WM::Manager::instance().register_window (&lua_script_window);
505 WM::Manager::instance().register_window (&bundle_manager);
506 WM::Manager::instance().register_window (&location_ui);
507 WM::Manager::instance().register_window (&big_clock_window);
508 WM::Manager::instance().register_window (&audio_port_matrix);
509 WM::Manager::instance().register_window (&midi_port_matrix);
510 WM::Manager::instance().register_window (&idleometer);
512 /* do not retain position for add route dialog */
513 add_route_dialog.set_state_mask (WindowProxy::Size);
515 /* Trigger setting up the color scheme and loading the GTK RC file */
517 UIConfiguration::instance().load_rc_file (false);
519 _process_thread = new ProcessThread ();
520 _process_thread->init ();
522 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
528 ARDOUR_UI::pre_release_dialog ()
530 ArdourDialog d (_("Pre-Release Warning"), true, false);
531 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
533 Label* label = manage (new Label);
534 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
535 There are still several issues and bugs to be worked on,\n\
536 as well as general workflow improvements, before this can be considered\n\
537 release software. So, a few guidelines:\n\
539 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
540 though it may be so, depending on your workflow.\n\
541 2) Please wait for a helpful writeup of new features.\n\
542 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
543 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
544 making sure to note the product version number as 5.0-pre.\n\
545 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
546 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
547 can get there directly from within the program via the Help->Chat menu option.\n\
549 Full information on all the above can be found on the support page at\n\
551 http://ardour.org/support\n\
552 "), PROGRAM_NAME, VERSIONSTRING));
554 d.get_vbox()->set_border_width (12);
555 d.get_vbox()->pack_start (*label, false, false, 12);
556 d.get_vbox()->show_all ();
561 GlobalPortMatrixWindow*
562 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
567 return new GlobalPortMatrixWindow (_session, type);
571 ARDOUR_UI::attach_to_engine ()
573 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
574 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
578 ARDOUR_UI::engine_stopped ()
580 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
581 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
582 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
583 update_sample_rate (0);
588 ARDOUR_UI::engine_running ()
590 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
591 if (first_time_engine_run) {
593 first_time_engine_run = false;
597 _session->reset_xrun_count ();
599 update_disk_space ();
601 update_xrun_count ();
602 update_sample_rate (AudioEngine::instance()->sample_rate());
603 update_timecode_format ();
604 update_peak_thread_work ();
605 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
606 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
610 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
612 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
613 /* we can't rely on the original string continuing to exist when we are called
614 again in the GUI thread, so make a copy and note that we need to
617 char *copy = strdup (reason);
618 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
622 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
623 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
625 update_sample_rate (0);
629 /* if the reason is a non-empty string, it means that the backend was shutdown
630 rather than just Ardour.
633 if (strlen (reason)) {
634 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
636 msgstr = string_compose (_("\
637 The audio backend has either been shutdown or it\n\
638 disconnected %1 because %1\n\
639 was not fast enough. Try to restart\n\
640 the audio backend and save the session."), PROGRAM_NAME);
643 MessageDialog msg (_main_window, msgstr);
644 pop_back_splash (msg);
648 free (const_cast<char*> (reason));
653 ARDOUR_UI::post_engine ()
655 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
657 #ifdef AUDIOUNIT_SUPPORT
659 if (AUPluginInfo::au_get_crashlog(au_msg)) {
660 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
661 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
662 info << au_msg << endmsg;
666 ARDOUR::init_post_engine ();
668 /* connect to important signals */
670 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
671 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
672 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
673 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
674 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
676 if (setup_windows ()) {
677 throw failed_constructor ();
680 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
681 XMLNode* n = Config->extra_xml (X_("UI"));
683 _status_bar_visibility.set_state (*n);
686 check_memory_locking();
688 /* this is the first point at which all the possible actions are
689 * available, because some of the available actions are dependent on
690 * aspects of the engine/backend.
693 if (ARDOUR_COMMAND_LINE::show_key_actions) {
695 Bindings::save_all_bindings_as_html (sstr);
697 if (sstr.str().empty()) {
704 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
706 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
712 #ifdef PLATFORM_WINDOWS
718 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
719 #ifndef PLATFORM_WINDOWS
722 g_unlink (file_name);
724 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
730 #ifndef PLATFORM_WINDOWS
734 PBD::open_uri (string_compose ("file:///%1", file_name));
736 halt_connection.disconnect ();
737 AudioEngine::instance()->stop ();
742 if (ARDOUR_COMMAND_LINE::show_actions) {
745 vector<string> paths;
746 vector<string> labels;
747 vector<string> tooltips;
749 vector<Glib::RefPtr<Gtk::Action> > actions;
750 string ver_in = revision;
751 string ver = ver_in.substr(0, ver_in.find("-"));
754 output << "\n<h2>Menu actions</h2>" << endl;
755 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
756 output << " surfaces or scripts.\n</p>\n" << endl;
757 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
758 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
759 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
760 output << "<table class=\"dl\">\n <thead>" << endl;
761 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
762 output << " </thead>\n <tbody>" << endl;
764 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
766 vector<string>::iterator p;
767 vector<string>::iterator l;
769 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
770 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
771 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
773 output << " </tbody>\n </table>" << endl;
775 // output this mess to a browser for easiest X-platform use
776 // it is not pretty HTML, but it works and it's main purpose
777 // is to create raw html to fit in Ardour's manual with no editing
782 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
784 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
790 #ifdef PLATFORM_WINDOWS
796 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
797 #ifndef PLATFORM_WINDOWS
800 g_unlink (file_name);
802 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
808 #ifndef PLATFORM_WINDOWS
812 PBD::open_uri (string_compose ("file:///%1", file_name));
814 halt_connection.disconnect ();
815 AudioEngine::instance()->stop ();
819 /* this being a GUI and all, we want peakfiles */
821 AudioFileSource::set_build_peakfiles (true);
822 AudioFileSource::set_build_missing_peakfiles (true);
824 /* set default clock modes */
826 primary_clock->set_mode (AudioClock::Timecode);
827 secondary_clock->set_mode (AudioClock::BBT);
829 /* start the time-of-day-clock */
832 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
833 update_wall_clock ();
834 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
839 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
840 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
841 Config->map_parameters (pc);
843 UIConfiguration::instance().map_parameters (pc);
847 ARDOUR_UI::~ARDOUR_UI ()
849 UIConfiguration::instance().save_state();
853 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
854 // don't bother at 'real' exit. the OS cleans up for us.
855 delete big_clock; big_clock = 0;
856 delete primary_clock; primary_clock = 0;
857 delete secondary_clock; secondary_clock = 0;
858 delete _process_thread; _process_thread = 0;
859 delete time_info_box; time_info_box = 0;
860 delete meterbridge; meterbridge = 0;
861 delete luawindow; luawindow = 0;
862 delete editor; editor = 0;
863 delete mixer; mixer = 0;
864 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
866 delete gui_object_state; gui_object_state = 0;
867 delete main_window_visibility;
868 FastMeter::flush_pattern_cache ();
869 PixFader::flush_pattern_cache ();
873 /* Small trick to flush main-thread event pool.
874 * Other thread-pools are destroyed at pthread_exit(),
875 * but tmain thread termination is too late to trigger Pool::~Pool()
877 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.
878 delete ev->event_pool();
883 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
885 if (Splash::instance()) {
886 Splash::instance()->pop_back_for (win);
891 ARDOUR_UI::configure_timeout ()
893 if (last_configure_time == 0) {
894 /* no configure events yet */
898 /* force a gap of 0.5 seconds since the last configure event
901 if (get_microseconds() - last_configure_time < 500000) {
904 have_configure_timeout = false;
905 save_ardour_state ();
911 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
913 if (have_configure_timeout) {
914 last_configure_time = get_microseconds();
916 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
917 have_configure_timeout = true;
924 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
928 if (node.get_property ("roll", str)){
929 roll_controllable->set_id (str);
931 if (node.get_property ("stop", str)) {
932 stop_controllable->set_id (str);
934 if (node.get_property ("goto-start", str)) {
935 goto_start_controllable->set_id (str);
937 if (node.get_property ("goto-end", str)) {
938 goto_end_controllable->set_id (str);
940 if (node.get_property ("auto-loop", str)) {
941 auto_loop_controllable->set_id (str);
943 if (node.get_property ("play-selection", str)) {
944 play_selection_controllable->set_id (str);
946 if (node.get_property ("rec", str)) {
947 rec_controllable->set_id (str);
949 if (node.get_property ("shuttle", str)) {
950 shuttle_box.controllable()->set_id (str);
955 ARDOUR_UI::get_transport_controllable_state ()
957 XMLNode* node = new XMLNode(X_("TransportControllables"));
959 node->set_property (X_("roll"), roll_controllable->id());
960 node->set_property (X_("stop"), stop_controllable->id());
961 node->set_property (X_("goto-start"), goto_start_controllable->id());
962 node->set_property (X_("goto-end"), goto_end_controllable->id());
963 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
964 node->set_property (X_("play-selection"), play_selection_controllable->id());
965 node->set_property (X_("rec"), rec_controllable->id());
966 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
972 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
975 _session->save_state (snapshot_name);
980 ARDOUR_UI::autosave_session ()
982 if (g_main_depth() > 1) {
983 /* inside a recursive main loop,
984 give up because we may not be able to
990 if (!Config->get_periodic_safety_backups()) {
995 _session->maybe_write_autosave();
1002 ARDOUR_UI::session_dirty_changed ()
1009 ARDOUR_UI::update_autosave ()
1011 if (_session && _session->dirty()) {
1012 if (_autosave_connection.connected()) {
1013 _autosave_connection.disconnect();
1016 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1017 Config->get_periodic_safety_backup_interval() * 1000);
1020 if (_autosave_connection.connected()) {
1021 _autosave_connection.disconnect();
1027 ARDOUR_UI::check_announcements ()
1030 string _annc_filename;
1033 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1034 #elif defined PLATFORM_WINDOWS
1035 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1037 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1039 _annc_filename.append (VERSIONSTRING);
1041 _announce_string = "";
1043 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1044 FILE* fin = g_fopen (path.c_str(), "rb");
1046 while (!feof (fin)) {
1049 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1052 _announce_string.append (tmp, len);
1057 pingback (VERSIONSTRING, path);
1062 _hide_splash (gpointer arg)
1064 ((ARDOUR_UI*)arg)->hide_splash();
1069 ARDOUR_UI::starting ()
1071 Application* app = Application::instance ();
1072 const char *nsm_url;
1073 bool brand_new_user = ArdourStartup::required ();
1075 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1076 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1078 if (ARDOUR_COMMAND_LINE::check_announcements) {
1079 check_announcements ();
1084 /* we need to create this early because it may need to set the
1085 * audio backend end up.
1089 audio_midi_setup.get (true);
1091 std::cerr << "audio-midi engine setup failed."<< std::endl;
1095 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1096 nsm = new NSM_Client;
1097 if (!nsm->init (nsm_url)) {
1098 /* the ardour executable may have different names:
1100 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1101 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1102 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1104 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1106 const char *process_name = g_getenv ("ARDOUR_SELF");
1107 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1110 // wait for announce reply from nsm server
1111 for ( i = 0; i < 5000; ++i) {
1115 if (nsm->is_active()) {
1120 error << _("NSM server did not announce itself") << endmsg;
1123 // wait for open command from nsm server
1124 for ( i = 0; i < 5000; ++i) {
1126 Glib::usleep (1000);
1127 if (nsm->client_id ()) {
1133 error << _("NSM: no client ID provided") << endmsg;
1137 if (_session && nsm) {
1138 _session->set_nsm_state( nsm->is_active() );
1140 error << _("NSM: no session created") << endmsg;
1144 // nsm requires these actions disabled
1145 vector<string> action_names;
1146 action_names.push_back("SaveAs");
1147 action_names.push_back("Rename");
1148 action_names.push_back("New");
1149 action_names.push_back("Open");
1150 action_names.push_back("Recent");
1151 action_names.push_back("Close");
1153 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1154 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1156 act->set_sensitive (false);
1163 error << _("NSM: initialization failed") << endmsg;
1169 if (brand_new_user) {
1170 _initial_verbose_plugin_scan = true;
1175 _initial_verbose_plugin_scan = false;
1176 switch (s.response ()) {
1177 case Gtk::RESPONSE_OK:
1184 // TODO: maybe IFF brand_new_user
1185 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1186 std::string dspd (Config->get_default_session_parent_dir());
1187 Searchpath ds (ARDOUR::ardour_data_search_path());
1188 ds.add_subdirectory_to_paths ("sessions");
1189 vector<string> demos;
1190 find_files_matching_pattern (demos, ds, "*.tar.xz");
1192 ARDOUR::RecentSessions rs;
1193 ARDOUR::read_recent_sessions (rs);
1195 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1196 /* "demo-session" must be inside "demo-session.tar.xz"
1199 std::string name = basename_nosuffix (basename_nosuffix (*i));
1200 std::string path = Glib::build_filename (dspd, name);
1201 /* skip if session-dir already exists */
1202 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1205 /* skip sessions that are already in 'recent'.
1206 * eg. a new user changed <session-default-dir> shorly after installation
1208 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1209 if ((*r).first == name) {
1214 PBD::FileArchive ar (*i);
1215 if (0 == ar.inflate (dspd)) {
1216 store_recent_sessions (name, path);
1217 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1223 #ifdef NO_PLUGIN_STATE
1225 ARDOUR::RecentSessions rs;
1226 ARDOUR::read_recent_sessions (rs);
1228 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1230 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1232 /* already used Ardour, have sessions ... warn about plugin state */
1234 ArdourDialog d (_("Free/Demo Version Warning"), true);
1236 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1237 CheckButton c (_("Don't warn me about this again"));
1239 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"),
1240 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1241 _("It will not restore OR save any plugin settings"),
1242 _("If you load an existing session with plugin settings\n"
1243 "they will not be used and will be lost."),
1244 _("To get full access to updates without this limitation\n"
1245 "consider becoming a subscriber for a low cost every month.")));
1246 l.set_justify (JUSTIFY_CENTER);
1248 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1250 d.get_vbox()->pack_start (l, true, true);
1251 d.get_vbox()->pack_start (b, false, false, 12);
1252 d.get_vbox()->pack_start (c, false, false, 12);
1254 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1255 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1259 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1261 if (d.run () != RESPONSE_OK) {
1267 /* go get a session */
1269 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1271 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1272 std::cerr << "Cannot get session parameters."<< std::endl;
1279 WM::Manager::instance().show_visible ();
1281 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1282 * editor window, and we may want stuff to be hidden.
1284 _status_bar_visibility.update ();
1286 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1288 /* all other dialogs are created conditionally */
1294 ARDOUR_UI::check_memory_locking ()
1296 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1297 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1301 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1303 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1305 struct rlimit limits;
1307 long pages, page_size;
1309 size_t pages_len=sizeof(pages);
1310 if ((page_size = getpagesize()) < 0 ||
1311 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1313 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1318 ram = (int64_t) pages * (int64_t) page_size;
1321 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1325 if (limits.rlim_cur != RLIM_INFINITY) {
1327 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1331 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1332 "This might cause %1 to run out of memory before your system "
1333 "runs out of memory. \n\n"
1334 "You can view the memory limit with 'ulimit -l', "
1335 "and it is normally controlled by %2"),
1338 X_("/etc/login.conf")
1340 X_(" /etc/security/limits.conf")
1344 msg.set_default_response (RESPONSE_OK);
1346 VBox* vbox = msg.get_vbox();
1348 CheckButton cb (_("Do not show this window again"));
1349 hbox.pack_start (cb, true, false);
1350 vbox->pack_start (hbox);
1355 pop_back_splash (msg);
1359 if (cb.get_active()) {
1360 XMLNode node (X_("no-memory-warning"));
1361 Config->add_instant_xml (node);
1366 #endif // !__APPLE__
1371 ARDOUR_UI::queue_finish ()
1373 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1377 ARDOUR_UI::idle_finish ()
1380 return false; /* do not call again */
1387 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1389 if (_session->dirty()) {
1390 vector<string> actions;
1391 actions.push_back (_("Don't quit"));
1392 actions.push_back (_("Just quit"));
1393 actions.push_back (_("Save and quit"));
1394 switch (ask_about_saving_session(actions)) {
1399 /* use the default name */
1400 if (save_state_canfail ("")) {
1401 /* failed - don't quit */
1402 MessageDialog msg (_main_window,
1403 string_compose (_("\
1404 %1 was unable to save your session.\n\n\
1405 If you still wish to quit, please use the\n\n\
1406 \"Just quit\" option."), PROGRAM_NAME));
1407 pop_back_splash(msg);
1417 second_connection.disconnect ();
1418 point_one_second_connection.disconnect ();
1419 point_zero_something_second_connection.disconnect();
1420 fps_connection.disconnect();
1423 delete ARDOUR_UI::instance()->video_timeline;
1424 ARDOUR_UI::instance()->video_timeline = NULL;
1425 stop_video_server();
1427 /* Save state before deleting the session, as that causes some
1428 windows to be destroyed before their visible state can be
1431 save_ardour_state ();
1433 if (key_editor.get (false)) {
1434 key_editor->disconnect ();
1437 close_all_dialogs ();
1440 _session->set_clean ();
1441 _session->remove_pending_capture_state ();
1446 halt_connection.disconnect ();
1447 AudioEngine::instance()->stop ();
1448 #ifdef WINDOWS_VST_SUPPORT
1449 fst_stop_threading();
1455 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1457 ArdourDialog window (_("Unsaved Session"));
1458 Gtk::HBox dhbox; // the hbox for the image and text
1459 Gtk::Label prompt_label;
1460 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1464 assert (actions.size() >= 3);
1466 window.add_button (actions[0], RESPONSE_REJECT);
1467 window.add_button (actions[1], RESPONSE_APPLY);
1468 window.add_button (actions[2], RESPONSE_ACCEPT);
1470 window.set_default_response (RESPONSE_ACCEPT);
1472 Gtk::Button noquit_button (msg);
1473 noquit_button.set_name ("EditorGTKButton");
1477 if (_session->snap_name() == _session->name()) {
1478 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?"),
1479 _session->snap_name());
1481 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?"),
1482 _session->snap_name());
1485 prompt_label.set_text (prompt);
1486 prompt_label.set_name (X_("PrompterLabel"));
1487 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1489 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1490 dhbox.set_homogeneous (false);
1491 dhbox.pack_start (*dimage, false, false, 5);
1492 dhbox.pack_start (prompt_label, true, false, 5);
1493 window.get_vbox()->pack_start (dhbox);
1495 window.set_name (_("Prompter"));
1496 window.set_modal (true);
1497 window.set_resizable (false);
1500 prompt_label.show();
1505 ResponseType r = (ResponseType) window.run();
1510 case RESPONSE_ACCEPT: // save and get out of here
1512 case RESPONSE_APPLY: // get out of here
1523 ARDOUR_UI::every_second ()
1526 update_xrun_count ();
1527 update_buffer_load ();
1528 update_disk_space ();
1529 update_timecode_format ();
1530 update_peak_thread_work ();
1532 if (nsm && nsm->is_active ()) {
1535 if (!_was_dirty && _session->dirty ()) {
1539 else if (_was_dirty && !_session->dirty ()){
1547 ARDOUR_UI::every_point_one_seconds ()
1549 // TODO get rid of this..
1550 // ShuttleControl is updated directly via TransportStateChange signal
1554 ARDOUR_UI::every_point_zero_something_seconds ()
1556 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1558 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1559 float mpeak = editor_meter->update_meters();
1560 if (mpeak > editor_meter_max_peak) {
1561 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1562 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1569 ARDOUR_UI::set_fps_timeout_connection ()
1571 unsigned int interval = 40;
1572 if (!_session) return;
1573 if (_session->timecode_frames_per_second() != 0) {
1574 /* ideally we'll use a select() to sleep and not accumulate
1575 * idle time to provide a regular periodic signal.
1576 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1577 * However, that'll require a dedicated thread and cross-thread
1578 * signals to the GUI Thread..
1580 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1581 * _session->frame_rate() / _session->nominal_frame_rate()
1582 / _session->timecode_frames_per_second()
1584 #ifdef PLATFORM_WINDOWS
1585 // the smallest windows scheduler time-slice is ~15ms.
1586 // periodic GUI timeouts shorter than that will cause
1587 // WaitForSingleObject to spinlock (100% of one CPU Core)
1588 // and gtk never enters idle mode.
1589 // also changing timeBeginPeriod(1) does not affect that in
1590 // any beneficial way, so we just limit the max rate for now.
1591 interval = std::max(30u, interval); // at most ~33Hz.
1593 interval = std::max(8u, interval); // at most 120Hz.
1596 fps_connection.disconnect();
1597 Timers::set_fps_interval (interval);
1601 ARDOUR_UI::update_sample_rate (framecnt_t)
1605 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1607 if (!AudioEngine::instance()->connected()) {
1609 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1613 framecnt_t rate = AudioEngine::instance()->sample_rate();
1616 /* no sample rate available */
1617 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1620 if (fmod (rate, 1000.0) != 0.0) {
1621 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1622 (float) rate / 1000.0f,
1623 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1625 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1627 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1631 sample_rate_label.set_markup (buf);
1635 ARDOUR_UI::update_format ()
1638 format_label.set_text ("");
1643 s << _("File:") << X_(" <span foreground=\"green\">");
1645 switch (_session->config.get_native_file_header_format ()) {
1677 switch (_session->config.get_native_file_data_format ()) {
1691 format_label.set_markup (s.str ());
1695 ARDOUR_UI::update_xrun_count ()
1699 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1700 should also be changed.
1704 const unsigned int x = _session->get_xrun_count ();
1706 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1708 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1711 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1713 xrun_label.set_markup (buf);
1714 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1718 ARDOUR_UI::update_cpu_load ()
1722 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1723 should also be changed.
1726 double const c = AudioEngine::instance()->get_dsp_load ();
1727 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1728 cpu_load_label.set_markup (buf);
1732 ARDOUR_UI::update_peak_thread_work ()
1735 const int c = SourceFactory::peak_work_queue_length ();
1737 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1738 peak_thread_work_label.set_markup (buf);
1740 peak_thread_work_label.set_markup (X_(""));
1745 ARDOUR_UI::update_buffer_load ()
1749 uint32_t const playback = _session ? _session->playback_load () : 100;
1750 uint32_t const capture = _session ? _session->capture_load () : 100;
1752 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1753 should also be changed.
1759 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1760 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1761 playback <= 5 ? X_("red") : X_("green"),
1763 capture <= 5 ? X_("red") : X_("green"),
1767 buffer_load_label.set_markup (buf);
1769 buffer_load_label.set_text ("");
1774 ARDOUR_UI::count_recenabled_streams (Route& route)
1776 Track* track = dynamic_cast<Track*>(&route);
1777 if (track && track->rec_enable_control()->get_value()) {
1778 rec_enabled_streams += track->n_inputs().n_total();
1783 ARDOUR_UI::update_disk_space()
1785 if (_session == 0) {
1789 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1791 framecnt_t fr = _session->frame_rate();
1794 /* skip update - no SR available */
1799 /* Available space is unknown */
1800 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1801 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1802 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1804 rec_enabled_streams = 0;
1805 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1807 framecnt_t frames = opt_frames.get_value_or (0);
1809 if (rec_enabled_streams) {
1810 frames /= rec_enabled_streams;
1817 hrs = frames / (fr * 3600);
1820 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1822 frames -= hrs * fr * 3600;
1823 mins = frames / (fr * 60);
1824 frames -= mins * fr * 60;
1827 bool const low = (hrs == 0 && mins <= 30);
1831 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1832 low ? X_("red") : X_("green"),
1838 disk_space_label.set_markup (buf);
1842 ARDOUR_UI::update_timecode_format ()
1848 TimecodeSlave* tcslave;
1849 SyncSource sync_src = Config->get_sync_source();
1851 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1852 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1857 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1858 matching ? X_("green") : X_("red"),
1859 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1861 snprintf (buf, sizeof (buf), "TC: n/a");
1864 timecode_format_label.set_markup (buf);
1868 ARDOUR_UI::update_wall_clock ()
1872 static int last_min = -1;
1875 tm_now = localtime (&now);
1876 if (last_min != tm_now->tm_min) {
1878 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1879 wall_clock_label.set_text (buf);
1880 last_min = tm_now->tm_min;
1887 ARDOUR_UI::open_recent_session ()
1889 bool can_return = (_session != 0);
1891 SessionDialog recent_session_dialog;
1895 ResponseType r = (ResponseType) recent_session_dialog.run ();
1898 case RESPONSE_ACCEPT:
1902 recent_session_dialog.hide();
1909 recent_session_dialog.hide();
1913 std::string path = recent_session_dialog.session_folder();
1914 std::string state = recent_session_dialog.session_name (should_be_new);
1916 if (should_be_new == true) {
1920 _session_is_new = false;
1922 if (load_session (path, state) == 0) {
1931 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1933 if (!AudioEngine::instance()->connected()) {
1934 MessageDialog msg (parent, string_compose (
1935 _("%1 is not connected to any audio backend.\n"
1936 "You cannot open or close sessions in this condition"),
1938 pop_back_splash (msg);
1946 ARDOUR_UI::open_session ()
1948 if (!check_audioengine (_main_window)) {
1952 /* ardour sessions are folders */
1953 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1954 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1955 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1956 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1959 string session_parent_dir = Glib::path_get_dirname(_session->path());
1960 open_session_selector.set_current_folder(session_parent_dir);
1962 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1965 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1967 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1968 string default_session_folder = Config->get_default_session_parent_dir();
1969 open_session_selector.add_shortcut_folder (default_session_folder);
1971 catch (Glib::Error & e) {
1972 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1975 FileFilter session_filter;
1976 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1977 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1978 open_session_selector.add_filter (session_filter);
1980 FileFilter archive_filter;
1981 archive_filter.add_pattern (X_("*.tar.xz"));
1982 archive_filter.set_name (_("Session Archives"));
1984 open_session_selector.add_filter (archive_filter);
1986 open_session_selector.set_filter (session_filter);
1988 int response = open_session_selector.run();
1989 open_session_selector.hide ();
1991 if (response == Gtk::RESPONSE_CANCEL) {
1995 string session_path = open_session_selector.get_filename();
1999 if (session_path.length() > 0) {
2000 int rv = ARDOUR::inflate_session (session_path,
2001 Config->get_default_session_parent_dir(), path, name);
2003 _session_is_new = false;
2004 load_session (path, name);
2007 MessageDialog msg (_main_window,
2008 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2011 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2012 _session_is_new = isnew;
2013 load_session (path, name);
2019 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
2025 _session->vca_manager().create_vca (n, name_template);
2029 ARDOUR_UI::session_add_mixed_track (
2030 const ChanCount& input,
2031 const ChanCount& output,
2032 RouteGroup* route_group,
2034 const string& name_template,
2036 PluginInfoPtr instrument,
2037 Plugin::PresetRecord* pset,
2038 ARDOUR::PresentationInfo::order_t order)
2040 if (_session == 0) {
2041 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2045 if (Profile->get_mixbus ()) {
2050 list<boost::shared_ptr<MidiTrack> > tracks;
2051 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2053 if (tracks.size() != how_many) {
2054 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2059 display_insufficient_ports_message ();
2065 ARDOUR_UI::session_add_midi_bus (
2066 RouteGroup* route_group,
2068 const string& name_template,
2070 PluginInfoPtr instrument,
2071 Plugin::PresetRecord* pset,
2072 ARDOUR::PresentationInfo::order_t order)
2074 if (_session == 0) {
2075 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2079 if (Profile->get_mixbus ()) {
2085 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2086 if (routes.size() != how_many) {
2087 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2092 display_insufficient_ports_message ();
2098 ARDOUR_UI::session_add_midi_route (
2100 RouteGroup* route_group,
2102 const string& name_template,
2104 PluginInfoPtr instrument,
2105 Plugin::PresetRecord* pset,
2106 ARDOUR::PresentationInfo::order_t order)
2108 ChanCount one_midi_channel;
2109 one_midi_channel.set (DataType::MIDI, 1);
2112 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2114 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2119 ARDOUR_UI::session_add_audio_route (
2121 int32_t input_channels,
2122 int32_t output_channels,
2123 ARDOUR::TrackMode mode,
2124 RouteGroup* route_group,
2126 string const & name_template,
2128 ARDOUR::PresentationInfo::order_t order)
2130 list<boost::shared_ptr<AudioTrack> > tracks;
2133 if (_session == 0) {
2134 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2140 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2142 if (tracks.size() != how_many) {
2143 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2149 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2151 if (routes.size() != how_many) {
2152 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2159 display_insufficient_ports_message ();
2164 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2165 (*i)->set_strict_io (true);
2167 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2168 (*i)->set_strict_io (true);
2174 ARDOUR_UI::display_insufficient_ports_message ()
2176 MessageDialog msg (_main_window,
2177 string_compose (_("There are insufficient ports available\n\
2178 to create a new track or bus.\n\
2179 You should save %1, exit and\n\
2180 restart with more ports."), PROGRAM_NAME));
2181 pop_back_splash (msg);
2186 ARDOUR_UI::transport_goto_start ()
2189 _session->goto_start();
2191 /* force displayed area in editor to start no matter
2192 what "follow playhead" setting is.
2196 editor->center_screen (_session->current_start_frame ());
2202 ARDOUR_UI::transport_goto_zero ()
2205 _session->request_locate (0);
2207 /* force displayed area in editor to start no matter
2208 what "follow playhead" setting is.
2212 editor->reset_x_origin (0);
2218 ARDOUR_UI::transport_goto_wallclock ()
2220 if (_session && editor) {
2227 localtime_r (&now, &tmnow);
2229 framecnt_t frame_rate = _session->frame_rate();
2231 if (frame_rate == 0) {
2232 /* no frame rate available */
2236 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2237 frames += tmnow.tm_min * (60 * frame_rate);
2238 frames += tmnow.tm_sec * frame_rate;
2240 _session->request_locate (frames, _session->transport_rolling ());
2242 /* force displayed area in editor to start no matter
2243 what "follow playhead" setting is.
2247 editor->center_screen (frames);
2253 ARDOUR_UI::transport_goto_end ()
2256 framepos_t const frame = _session->current_end_frame();
2257 _session->request_locate (frame);
2259 /* force displayed area in editor to start no matter
2260 what "follow playhead" setting is.
2264 editor->center_screen (frame);
2270 ARDOUR_UI::transport_stop ()
2276 if (_session->is_auditioning()) {
2277 _session->cancel_audition ();
2281 _session->request_stop (false, true);
2284 /** Check if any tracks are record enabled. If none are, record enable all of them.
2285 * @return true if track record-enabled status was changed, false otherwise.
2288 ARDOUR_UI::trx_record_enable_all_tracks ()
2294 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2295 bool none_record_enabled = true;
2297 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2298 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2301 if (t->rec_enable_control()->get_value()) {
2302 none_record_enabled = false;
2307 if (none_record_enabled) {
2308 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2311 return none_record_enabled;
2315 ARDOUR_UI::transport_record (bool roll)
2318 switch (_session->record_status()) {
2319 case Session::Disabled:
2320 if (_session->ntracks() == 0) {
2321 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."));
2325 if (Profile->get_trx()) {
2326 roll = trx_record_enable_all_tracks ();
2328 _session->maybe_enable_record ();
2333 case Session::Recording:
2335 _session->request_stop();
2337 _session->disable_record (false, true);
2341 case Session::Enabled:
2342 _session->disable_record (false, true);
2348 ARDOUR_UI::transport_roll ()
2354 if (_session->is_auditioning()) {
2359 if (_session->config.get_external_sync()) {
2360 switch (Config->get_sync_source()) {
2364 /* transport controlled by the master */
2370 bool rolling = _session->transport_rolling();
2372 if (_session->get_play_loop()) {
2374 /* If loop playback is not a mode, then we should cancel
2375 it when this action is requested. If it is a mode
2376 we just leave it in place.
2379 if (!Config->get_loop_is_mode()) {
2380 /* XXX it is not possible to just leave seamless loop and keep
2381 playing at present (nov 4th 2009)
2383 if (!Config->get_seamless_loop()) {
2384 /* stop loop playback and stop rolling */
2385 _session->request_play_loop (false, true);
2386 } else if (rolling) {
2387 /* stop loop playback but keep rolling */
2388 _session->request_play_loop (false, false);
2392 } else if (_session->get_play_range () ) {
2393 /* stop playing a range if we currently are */
2394 _session->request_play_range (0, true);
2398 _session->request_transport_speed (1.0f);
2403 ARDOUR_UI::get_smart_mode() const
2405 return ( editor->get_smart_mode() );
2410 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2416 if (_session->is_auditioning()) {
2417 _session->cancel_audition ();
2421 if (_session->config.get_external_sync()) {
2422 switch (Config->get_sync_source()) {
2426 /* transport controlled by the master */
2431 bool rolling = _session->transport_rolling();
2432 bool affect_transport = true;
2434 if (rolling && roll_out_of_bounded_mode) {
2435 /* drop out of loop/range playback but leave transport rolling */
2436 if (_session->get_play_loop()) {
2437 if (_session->actively_recording()) {
2439 /* just stop using the loop, then actually stop
2442 _session->request_play_loop (false, affect_transport);
2445 if (Config->get_seamless_loop()) {
2446 /* the disk buffers contain copies of the loop - we can't
2447 just keep playing, so stop the transport. the user
2448 can restart as they wish.
2450 affect_transport = true;
2452 /* disk buffers are normal, so we can keep playing */
2453 affect_transport = false;
2455 _session->request_play_loop (false, affect_transport);
2457 } else if (_session->get_play_range ()) {
2458 affect_transport = false;
2459 _session->request_play_range (0, true);
2463 if (affect_transport) {
2465 _session->request_stop (with_abort, true);
2467 } else if (!with_abort) { /* with_abort == true means the
2468 * command was intended to stop
2469 * transport, not start.
2472 /* the only external sync condition we can be in here
2473 * would be Engine (JACK) sync, in which case we still
2477 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
2478 _session->request_play_range (&editor->get_selection().time, true);
2479 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2481 _session->request_transport_speed (1.0f);
2487 ARDOUR_UI::toggle_session_auto_loop ()
2493 Location * looploc = _session->locations()->auto_loop_location();
2499 if (_session->get_play_loop()) {
2501 /* looping enabled, our job is to disable it */
2503 _session->request_play_loop (false);
2507 /* looping not enabled, our job is to enable it.
2509 loop-is-NOT-mode: this action always starts the transport rolling.
2510 loop-IS-mode: this action simply sets the loop play mechanism, but
2511 does not start transport.
2513 if (Config->get_loop_is_mode()) {
2514 _session->request_play_loop (true, false);
2516 _session->request_play_loop (true, true);
2520 //show the loop markers
2521 looploc->set_hidden (false, this);
2525 ARDOUR_UI::transport_play_selection ()
2531 editor->play_selection ();
2535 ARDOUR_UI::transport_play_preroll ()
2540 editor->play_with_preroll ();
2544 ARDOUR_UI::transport_rec_preroll ()
2549 editor->rec_with_preroll ();
2553 ARDOUR_UI::transport_rec_count_in ()
2558 editor->rec_with_count_in ();
2562 ARDOUR_UI::transport_rewind (int option)
2564 float current_transport_speed;
2567 current_transport_speed = _session->transport_speed();
2569 if (current_transport_speed >= 0.0f) {
2572 _session->request_transport_speed (-1.0f);
2575 _session->request_transport_speed (-4.0f);
2578 _session->request_transport_speed (-0.5f);
2583 _session->request_transport_speed (current_transport_speed * 1.5f);
2589 ARDOUR_UI::transport_forward (int option)
2595 float current_transport_speed = _session->transport_speed();
2597 if (current_transport_speed <= 0.0f) {
2600 _session->request_transport_speed (1.0f);
2603 _session->request_transport_speed (4.0f);
2606 _session->request_transport_speed (0.5f);
2611 _session->request_transport_speed (current_transport_speed * 1.5f);
2616 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2622 boost::shared_ptr<Route> r;
2624 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2626 boost::shared_ptr<Track> t;
2628 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2629 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2635 ARDOUR_UI::map_transport_state ()
2638 auto_loop_button.unset_active_state ();
2639 play_selection_button.unset_active_state ();
2640 roll_button.unset_active_state ();
2641 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2642 layered_button.set_sensitive (false);
2646 shuttle_box.map_transport_state ();
2648 float sp = _session->transport_speed();
2654 if (_session->get_play_range()) {
2656 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2657 roll_button.unset_active_state ();
2658 auto_loop_button.unset_active_state ();
2660 } else if (_session->get_play_loop ()) {
2662 auto_loop_button.set_active (true);
2663 play_selection_button.set_active (false);
2664 if (Config->get_loop_is_mode()) {
2665 roll_button.set_active (true);
2667 roll_button.set_active (false);
2672 roll_button.set_active (true);
2673 play_selection_button.set_active (false);
2674 auto_loop_button.set_active (false);
2677 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2678 /* light up both roll and play-selection if they are joined */
2679 roll_button.set_active (true);
2680 play_selection_button.set_active (true);
2682 layered_button.set_sensitive (!_session->actively_recording ());
2684 stop_button.set_active (false);
2688 layered_button.set_sensitive (true);
2689 stop_button.set_active (true);
2690 roll_button.set_active (false);
2691 play_selection_button.set_active (false);
2692 if (Config->get_loop_is_mode ()) {
2693 auto_loop_button.set_active (_session->get_play_loop());
2695 auto_loop_button.set_active (false);
2697 update_disk_space ();
2702 ARDOUR_UI::blink_handler (bool blink_on)
2704 transport_rec_enable_blink (blink_on);
2705 sync_blink (blink_on);
2707 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2710 error_blink (blink_on);
2711 solo_blink (blink_on);
2712 audition_blink (blink_on);
2713 feedback_blink (blink_on);
2717 ARDOUR_UI::update_clocks ()
2719 if (!_session) return;
2721 if (editor && !editor->dragging_playhead()) {
2722 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2727 ARDOUR_UI::start_clocking ()
2729 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2730 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2732 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2737 ARDOUR_UI::stop_clocking ()
2739 clock_signal_connection.disconnect ();
2743 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2747 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2749 label->set_text (buf);
2750 bar->set_fraction (fraction);
2752 /* process events, redraws, etc. */
2754 while (gtk_events_pending()) {
2755 gtk_main_iteration ();
2758 return true; /* continue with save-as */
2762 ARDOUR_UI::save_session_as ()
2768 if (!save_as_dialog) {
2769 save_as_dialog = new SaveAsDialog;
2772 save_as_dialog->set_name (_session->name());
2774 int response = save_as_dialog->run ();
2776 save_as_dialog->hide ();
2779 case Gtk::RESPONSE_OK:
2788 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2789 sa.new_name = save_as_dialog->new_name ();
2790 sa.switch_to = save_as_dialog->switch_to();
2791 sa.copy_media = save_as_dialog->copy_media();
2792 sa.copy_external = save_as_dialog->copy_external();
2793 sa.include_media = save_as_dialog->include_media ();
2795 /* Only bother with a progress dialog if we're going to copy
2796 media into the save-as target. Without that choice, this
2797 will be very fast because we're only talking about a few kB's to
2798 perhaps a couple of MB's of data.
2801 ArdourDialog progress_dialog (_("Save As"), true);
2804 if (sa.include_media && sa.copy_media) {
2806 Gtk::Label* label = manage (new Gtk::Label());
2807 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2809 progress_dialog.get_vbox()->pack_start (*label);
2810 progress_dialog.get_vbox()->pack_start (*progress_bar);
2812 progress_bar->show ();
2814 /* this signal will be emitted from within this, the calling thread,
2815 * after every file is copied. It provides information on percentage
2816 * complete (in terms of total data to copy), the number of files
2817 * copied so far, and the total number to copy.
2820 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2822 progress_dialog.show_all ();
2823 progress_dialog.present ();
2826 if (_session->save_as (sa)) {
2828 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2832 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2833 * the trick is this: if the new session was copy with media included,
2834 * then Session::save_as() will have already done a neat trick to avoid
2835 * us having to unload and load the new state. But if the media was not
2836 * included, then this is required (it avoids us having to otherwise
2837 * drop all references to media (sources).
2840 if (!sa.include_media && sa.switch_to) {
2841 unload_session (false);
2842 load_session (sa.final_session_folder_name, sa.new_name);
2847 ARDOUR_UI::archive_session ()
2855 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2857 SessionArchiveDialog sad;
2858 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2859 int response = sad.run ();
2861 if (response != Gtk::RESPONSE_OK) {
2866 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2867 MessageDialog msg (_("Session Archiving failed."));
2873 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2877 struct tm local_time;
2880 localtime_r (&n, &local_time);
2881 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2883 save_state (timebuf, switch_to_it);
2888 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2892 prompter.get_result (snapname);
2894 bool do_save = (snapname.length() != 0);
2897 char illegal = Session::session_name_is_legal(snapname);
2899 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2900 "snapshot names may not contain a '%1' character"), illegal));
2906 vector<std::string> p;
2907 get_state_files_in_directory (_session->session_directory().root_path(), p);
2908 vector<string> n = get_file_names_no_extension (p);
2910 if (find (n.begin(), n.end(), snapname) != n.end()) {
2912 do_save = overwrite_file_dialog (prompter,
2913 _("Confirm Snapshot Overwrite"),
2914 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2918 save_state (snapname, switch_to_it);
2928 /** Ask the user for the name of a new snapshot and then take it.
2932 ARDOUR_UI::snapshot_session (bool switch_to_it)
2934 ArdourPrompter prompter (true);
2936 prompter.set_name ("Prompter");
2937 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2939 prompter.set_title (_("Snapshot and switch"));
2940 prompter.set_prompt (_("New session name"));
2942 prompter.set_title (_("Take Snapshot"));
2943 prompter.set_prompt (_("Name of new snapshot"));
2947 prompter.set_initial_text (_session->snap_name());
2949 Glib::DateTime tm (g_date_time_new_now_local ());
2950 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2953 bool finished = false;
2955 switch (prompter.run()) {
2956 case RESPONSE_ACCEPT:
2958 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2969 /** Ask the user for a new session name and then rename the session to it.
2973 ARDOUR_UI::rename_session ()
2979 ArdourPrompter prompter (true);
2982 prompter.set_name ("Prompter");
2983 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2984 prompter.set_title (_("Rename Session"));
2985 prompter.set_prompt (_("New session name"));
2988 switch (prompter.run()) {
2989 case RESPONSE_ACCEPT:
2991 prompter.get_result (name);
2993 bool do_rename = (name.length() != 0);
2996 char illegal = Session::session_name_is_legal (name);
2999 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3000 "session names may not contain a '%1' character"), illegal));
3005 switch (_session->rename (name)) {
3007 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3008 msg.set_position (WIN_POS_MOUSE);
3016 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3017 msg.set_position (WIN_POS_MOUSE);
3033 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3035 if (!_session || _session->deletion_in_progress()) {
3039 XMLNode* node = new XMLNode (X_("UI"));
3041 WM::Manager::instance().add_state (*node);
3043 node->add_child_nocopy (gui_object_state->get_state());
3045 _session->add_extra_xml (*node);
3047 if (export_video_dialog) {
3048 _session->add_extra_xml (export_video_dialog->get_state());
3051 save_state_canfail (name, switch_to_it);
3055 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3060 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3065 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3070 ARDOUR_UI::primary_clock_value_changed ()
3073 _session->request_locate (primary_clock->current_time ());
3078 ARDOUR_UI::big_clock_value_changed ()
3081 _session->request_locate (big_clock->current_time ());
3086 ARDOUR_UI::secondary_clock_value_changed ()
3089 _session->request_locate (secondary_clock->current_time ());
3094 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3096 if (_session == 0) {
3100 if (_session->step_editing()) {
3104 Session::RecordState const r = _session->record_status ();
3105 bool const h = _session->have_rec_enabled_track ();
3107 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3109 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3111 rec_button.set_active_state (Gtkmm2ext::Off);
3113 } else if (r == Session::Recording && h) {
3114 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3116 rec_button.unset_active_state ();
3121 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3125 prompter.get_result (name);
3127 if (name.length()) {
3128 int failed = _session->save_template (name);
3130 if (failed == -2) { /* file already exists. */
3131 bool overwrite = overwrite_file_dialog (prompter,
3132 _("Confirm Template Overwrite"),
3133 _("A template already exists with that name. Do you want to overwrite it?"));
3136 _session->save_template (name, true);
3148 ARDOUR_UI::save_template ()
3150 ArdourPrompter prompter (true);
3152 if (!check_audioengine (_main_window)) {
3156 prompter.set_name (X_("Prompter"));
3157 prompter.set_title (_("Save Template"));
3158 prompter.set_prompt (_("Name for template:"));
3159 prompter.set_initial_text(_session->name() + _("-template"));
3160 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3162 bool finished = false;
3164 switch (prompter.run()) {
3165 case RESPONSE_ACCEPT:
3166 finished = process_save_template_prompter (prompter);
3176 void ARDOUR_UI::manage_templates ()
3183 ARDOUR_UI::edit_metadata ()
3185 SessionMetadataEditor dialog;
3186 dialog.set_session (_session);
3187 dialog.grab_focus ();
3192 ARDOUR_UI::import_metadata ()
3194 SessionMetadataImporter dialog;
3195 dialog.set_session (_session);
3200 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3202 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3204 MessageDialog msg (str,
3206 Gtk::MESSAGE_WARNING,
3207 Gtk::BUTTONS_YES_NO,
3211 msg.set_name (X_("OpenExistingDialog"));
3212 msg.set_title (_("Open Existing Session"));
3213 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3214 msg.set_position (Gtk::WIN_POS_CENTER);
3215 pop_back_splash (msg);
3217 switch (msg.run()) {
3226 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3228 BusProfile bus_profile;
3232 bus_profile.master_out_channels = 2;
3233 bus_profile.input_ac = AutoConnectPhysical;
3234 bus_profile.output_ac = AutoConnectMaster;
3235 bus_profile.requested_physical_in = 0; // use all available
3236 bus_profile.requested_physical_out = 0; // use all available
3240 /* get settings from advanced section of NSD */
3242 if (sd.create_master_bus()) {
3243 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3245 bus_profile.master_out_channels = 0;
3248 if (sd.connect_inputs()) {
3249 bus_profile.input_ac = AutoConnectPhysical;
3251 bus_profile.input_ac = AutoConnectOption (0);
3254 bus_profile.output_ac = AutoConnectOption (0);
3256 if (sd.connect_outputs ()) {
3257 if (sd.connect_outs_to_master()) {
3258 bus_profile.output_ac = AutoConnectMaster;
3259 } else if (sd.connect_outs_to_physical()) {
3260 bus_profile.output_ac = AutoConnectPhysical;
3264 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3265 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3268 if (build_session (session_path, session_name, bus_profile)) {
3276 ARDOUR_UI::load_from_application_api (const std::string& path)
3278 /* OS X El Capitan (and probably later) now somehow passes the command
3279 line arguments to an app via the openFile delegate protocol. Ardour
3280 already does its own command line processing, and having both
3281 pathways active causes crashes. So, if the command line was already
3282 set, do nothing here.
3285 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3289 ARDOUR_COMMAND_LINE::session_name = path;
3291 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3293 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3295 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3296 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3297 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3298 * -> SessionDialog is not displayed
3301 if (_session_dialog) {
3302 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3303 std::string session_path = path;
3304 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3305 session_path = Glib::path_get_dirname (session_path);
3307 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3308 _session_dialog->set_provided_session (session_name, session_path);
3309 _session_dialog->response (RESPONSE_NONE);
3310 _session_dialog->hide();
3315 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3316 /* /path/to/foo => /path/to/foo, foo */
3317 rv = load_session (path, basename_nosuffix (path));
3319 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3320 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3323 // if load_session fails -> pop up SessionDialog.
3325 ARDOUR_COMMAND_LINE::session_name = "";
3327 if (get_session_parameters (true, false)) {
3333 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3335 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3337 string session_name;
3338 string session_path;
3339 string template_name;
3341 bool likely_new = false;
3342 bool cancel_not_quit;
3344 /* deal with any existing DIRTY session now, rather than later. don't
3345 * treat a non-dirty session this way, so that it stays visible
3346 * as we bring up the new session dialog.
3349 if (_session && ARDOUR_UI::instance()->video_timeline) {
3350 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3353 /* if there is already a session, relabel the button
3354 on the SessionDialog so that we don't Quit directly
3356 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3358 if (_session && _session->dirty()) {
3359 if (unload_session (false)) {
3360 /* unload cancelled by user */
3363 ARDOUR_COMMAND_LINE::session_name = "";
3366 if (!load_template.empty()) {
3367 should_be_new = true;
3368 template_name = load_template;
3371 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3372 session_path = ARDOUR_COMMAND_LINE::session_name;
3374 if (!session_path.empty()) {
3375 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3376 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3377 /* session/snapshot file, change path to be dir */
3378 session_path = Glib::path_get_dirname (session_path);
3383 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3385 _session_dialog = &session_dialog;
3388 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3390 /* if they named a specific statefile, use it, otherwise they are
3391 just giving a session folder, and we want to use it as is
3392 to find the session.
3395 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3397 if (suffix != string::npos) {
3398 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3399 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3400 session_name = Glib::path_get_basename (session_name);
3402 session_path = ARDOUR_COMMAND_LINE::session_name;
3403 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3408 session_dialog.clear_given ();
3411 if (should_be_new || session_name.empty()) {
3412 /* need the dialog to get info from user */
3414 cerr << "run dialog\n";
3416 switch (session_dialog.run()) {
3417 case RESPONSE_ACCEPT:
3420 /* this is used for async * app->ShouldLoad(). */
3421 continue; // while loop
3424 if (quit_on_cancel) {
3425 // JE - Currently (July 2014) this section can only get reached if the
3426 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3427 // point does NOT indicate an abnormal termination). Therefore, let's
3428 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3430 pthread_cancel_all ();
3438 session_dialog.hide ();
3441 /* if we run the startup dialog again, offer more than just "new session" */
3443 should_be_new = false;
3445 session_name = session_dialog.session_name (likely_new);
3446 session_path = session_dialog.session_folder ();
3453 int rv = ARDOUR::inflate_session (session_name,
3454 Config->get_default_session_parent_dir(), session_path, session_name);
3456 MessageDialog msg (session_dialog,
3457 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3462 session_dialog.set_provided_session (session_name, session_path);
3466 // XXX check archive, inflate
3467 string::size_type suffix = session_name.find (statefile_suffix);
3469 if (suffix != string::npos) {
3470 session_name = session_name.substr (0, suffix);
3473 /* this shouldn't happen, but we catch it just in case it does */
3475 if (session_name.empty()) {
3479 if (session_dialog.use_session_template()) {
3480 template_name = session_dialog.session_template_name();
3481 _session_is_new = true;
3484 if (session_name[0] == G_DIR_SEPARATOR ||
3485 #ifdef PLATFORM_WINDOWS
3486 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3488 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3489 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3494 /* absolute path or cwd-relative path specified for session name: infer session folder
3495 from what was given.
3498 session_path = Glib::path_get_dirname (session_name);
3499 session_name = Glib::path_get_basename (session_name);
3503 session_path = session_dialog.session_folder();
3505 char illegal = Session::session_name_is_legal (session_name);
3508 MessageDialog msg (session_dialog,
3509 string_compose (_("To ensure compatibility with various systems\n"
3510 "session names may not contain a '%1' character"),
3513 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3518 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3521 if (likely_new && !nsm) {
3523 std::string existing = Glib::build_filename (session_path, session_name);
3525 if (!ask_about_loading_existing_session (existing)) {
3526 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3531 _session_is_new = false;
3536 pop_back_splash (session_dialog);
3537 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3539 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3543 char illegal = Session::session_name_is_legal(session_name);
3546 pop_back_splash (session_dialog);
3547 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3548 "session names may not contain a '%1' character"), illegal));
3550 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3554 _session_is_new = true;
3557 if (likely_new && template_name.empty()) {
3559 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3563 ret = load_session (session_path, session_name, template_name);
3566 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3570 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3571 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3575 /* clear this to avoid endless attempts to load the
3579 ARDOUR_COMMAND_LINE::session_name = "";
3583 _session_dialog = NULL;
3589 ARDOUR_UI::close_session()
3591 if (!check_audioengine (_main_window)) {
3595 if (unload_session (true)) {
3599 ARDOUR_COMMAND_LINE::session_name = "";
3601 if (get_session_parameters (true, false)) {
3606 /** @param snap_name Snapshot name (without .ardour suffix).
3607 * @return -2 if the load failed because we are not connected to the AudioEngine.
3610 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3612 /* load_session calls flush_pending() which allows
3613 * GUI interaction and potentially loading another session
3614 * (that was easy via snapshot sidebar).
3615 * Recursing into load_session() from load_session() and recusive
3616 * event loops causes all kind of crashes.
3618 assert (!session_load_in_progress);
3619 if (session_load_in_progress) {
3622 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3624 Session *new_session;
3629 unload_status = unload_session ();
3631 if (unload_status < 0) {
3633 } else if (unload_status > 0) {
3639 session_loaded = false;
3641 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3644 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3647 /* this one is special */
3649 catch (AudioEngine::PortRegistrationFailure& err) {
3651 MessageDialog msg (err.what(),
3654 Gtk::BUTTONS_CLOSE);
3656 msg.set_title (_("Port Registration Error"));
3657 msg.set_secondary_text (_("Click the Close button to try again."));
3658 msg.set_position (Gtk::WIN_POS_CENTER);
3659 pop_back_splash (msg);
3662 int response = msg.run ();
3667 case RESPONSE_CANCEL:
3674 catch (SessionException e) {
3675 MessageDialog msg (string_compose(
3676 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3677 path, snap_name, e.what()),
3682 msg.set_title (_("Loading Error"));
3683 msg.set_position (Gtk::WIN_POS_CENTER);
3684 pop_back_splash (msg);
3696 MessageDialog msg (string_compose(
3697 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3703 msg.set_title (_("Loading Error"));
3704 msg.set_position (Gtk::WIN_POS_CENTER);
3705 pop_back_splash (msg);
3717 list<string> const u = new_session->unknown_processors ();
3719 MissingPluginDialog d (_session, u);
3724 if (!new_session->writable()) {
3725 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3730 msg.set_title (_("Read-only Session"));
3731 msg.set_position (Gtk::WIN_POS_CENTER);
3732 pop_back_splash (msg);
3739 /* Now the session been created, add the transport controls */
3740 new_session->add_controllable(roll_controllable);
3741 new_session->add_controllable(stop_controllable);
3742 new_session->add_controllable(goto_start_controllable);
3743 new_session->add_controllable(goto_end_controllable);
3744 new_session->add_controllable(auto_loop_controllable);
3745 new_session->add_controllable(play_selection_controllable);
3746 new_session->add_controllable(rec_controllable);
3748 set_session (new_session);
3750 session_loaded = true;
3753 _session->set_clean ();
3756 #ifdef WINDOWS_VST_SUPPORT
3757 fst_stop_threading();
3761 Timers::TimerSuspender t;
3765 #ifdef WINDOWS_VST_SUPPORT
3766 fst_start_threading();
3771 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3772 * which is queued by set_session().
3773 * If session-loading fails we hide it explicitly.
3774 * This covers both cases in a central place.
3783 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3785 Session *new_session;
3788 session_loaded = false;
3789 x = unload_session ();
3797 _session_is_new = true;
3800 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3803 catch (SessionException e) {
3804 cerr << "Here are the errors associated with this failed session:\n";
3806 cerr << "---------\n";
3807 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3808 msg.set_title (_("Loading Error"));
3809 msg.set_position (Gtk::WIN_POS_CENTER);
3810 pop_back_splash (msg);
3815 cerr << "Here are the errors associated with this failed session:\n";
3817 cerr << "---------\n";
3818 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3819 msg.set_title (_("Loading Error"));
3820 msg.set_position (Gtk::WIN_POS_CENTER);
3821 pop_back_splash (msg);
3826 /* Give the new session the default GUI state, if such things exist */
3829 n = Config->instant_xml (X_("Editor"));
3831 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3832 new_session->add_instant_xml (*n, false);
3834 n = Config->instant_xml (X_("Mixer"));
3836 new_session->add_instant_xml (*n, false);
3839 n = Config->instant_xml (X_("Preferences"));
3841 new_session->add_instant_xml (*n, false);
3844 /* Put the playhead at 0 and scroll fully left */
3845 n = new_session->instant_xml (X_("Editor"));
3847 n->set_property (X_("playhead"), X_("0"));
3848 n->set_property (X_("left-frame"), X_("0"));
3851 set_session (new_session);
3853 session_loaded = true;
3855 new_session->save_state(new_session->name());
3861 ARDOUR_UI::launch_chat ()
3863 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3865 dialog.set_title (_("About the Chat"));
3866 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."));
3868 switch (dialog.run()) {
3871 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3872 #elif defined PLATFORM_WINDOWS
3873 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3875 open_uri("http://webchat.freenode.net/?channels=ardour");
3884 ARDOUR_UI::launch_manual ()
3886 PBD::open_uri (Config->get_tutorial_manual_url());
3890 ARDOUR_UI::launch_reference ()
3892 PBD::open_uri (Config->get_reference_manual_url());
3896 ARDOUR_UI::launch_tracker ()
3898 PBD::open_uri ("http://tracker.ardour.org");
3902 ARDOUR_UI::launch_subscribe ()
3904 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3908 ARDOUR_UI::launch_cheat_sheet ()
3911 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3913 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3918 ARDOUR_UI::launch_website ()
3920 PBD::open_uri ("http://ardour.org");
3924 ARDOUR_UI::launch_website_dev ()
3926 PBD::open_uri ("http://ardour.org/development.html");
3930 ARDOUR_UI::launch_forums ()
3932 PBD::open_uri ("https://community.ardour.org/forums");
3936 ARDOUR_UI::launch_howto_report ()
3938 PBD::open_uri ("http://ardour.org/reporting_bugs");
3942 ARDOUR_UI::loading_message (const std::string& msg)
3944 if (ARDOUR_COMMAND_LINE::no_splash) {
3952 splash->message (msg);
3956 ARDOUR_UI::show_splash ()
3960 splash = new Splash;
3970 ARDOUR_UI::hide_splash ()
3977 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3981 removed = rep.paths.size();
3984 MessageDialog msgd (_main_window,
3985 _("No files were ready for clean-up"),
3989 msgd.set_title (_("Clean-up"));
3990 msgd.set_secondary_text (_("If this seems surprising, \n\
3991 check for any existing snapshots.\n\
3992 These may still include regions that\n\
3993 require some unused files to continue to exist."));
3999 ArdourDialog results (_("Clean-up"), true, false);
4001 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4002 CleanupResultsModelColumns() {
4006 Gtk::TreeModelColumn<std::string> visible_name;
4007 Gtk::TreeModelColumn<std::string> fullpath;
4011 CleanupResultsModelColumns results_columns;
4012 Glib::RefPtr<Gtk::ListStore> results_model;
4013 Gtk::TreeView results_display;
4015 results_model = ListStore::create (results_columns);
4016 results_display.set_model (results_model);
4017 results_display.append_column (list_title, results_columns.visible_name);
4019 results_display.set_name ("CleanupResultsList");
4020 results_display.set_headers_visible (true);
4021 results_display.set_headers_clickable (false);
4022 results_display.set_reorderable (false);
4024 Gtk::ScrolledWindow list_scroller;
4027 Gtk::HBox dhbox; // the hbox for the image and text
4028 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4029 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4031 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4033 const string dead_directory = _session->session_directory().dead_path();
4036 %1 - number of files removed
4037 %2 - location of "dead"
4038 %3 - size of files affected
4039 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4042 const char* bprefix;
4043 double space_adjusted = 0;
4045 if (rep.space < 1000) {
4047 space_adjusted = rep.space;
4048 } else if (rep.space < 1000000) {
4049 bprefix = _("kilo");
4050 space_adjusted = floorf((float)rep.space / 1000.0);
4051 } else if (rep.space < 1000000 * 1000) {
4052 bprefix = _("mega");
4053 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4055 bprefix = _("giga");
4056 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4060 txt.set_markup (string_compose (P_("\
4061 The following file was deleted from %2,\n\
4062 releasing %3 %4bytes of disk space", "\
4063 The following %1 files were deleted from %2,\n\
4064 releasing %3 %4bytes of disk space", removed),
4065 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4067 txt.set_markup (string_compose (P_("\
4068 The following file was not in use and \n\
4069 has been moved to: %2\n\n\
4070 After a restart of %5\n\n\
4071 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4072 will release an additional %3 %4bytes of disk space.\n", "\
4073 The following %1 files were not in use and \n\
4074 have been moved to: %2\n\n\
4075 After a restart of %5\n\n\
4076 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4077 will release an additional %3 %4bytes of disk space.\n", removed),
4078 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4081 dhbox.pack_start (*dimage, true, false, 5);
4082 dhbox.pack_start (txt, true, false, 5);
4084 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4085 TreeModel::Row row = *(results_model->append());
4086 row[results_columns.visible_name] = *i;
4087 row[results_columns.fullpath] = *i;
4090 list_scroller.add (results_display);
4091 list_scroller.set_size_request (-1, 150);
4092 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4094 dvbox.pack_start (dhbox, true, false, 5);
4095 dvbox.pack_start (list_scroller, true, false, 5);
4096 ddhbox.pack_start (dvbox, true, false, 5);
4098 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4099 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4100 results.set_default_response (RESPONSE_CLOSE);
4101 results.set_position (Gtk::WIN_POS_MOUSE);
4103 results_display.show();
4104 list_scroller.show();
4111 //results.get_vbox()->show();
4112 results.set_resizable (false);
4119 ARDOUR_UI::cleanup ()
4121 if (_session == 0) {
4122 /* shouldn't happen: menu item is insensitive */
4127 MessageDialog checker (_("Are you sure you want to clean-up?"),
4129 Gtk::MESSAGE_QUESTION,
4132 checker.set_title (_("Clean-up"));
4134 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4135 ALL undo/redo information will be lost if you clean-up.\n\
4136 Clean-up will move all unused files to a \"dead\" location."));
4138 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4139 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4140 checker.set_default_response (RESPONSE_CANCEL);
4142 checker.set_name (_("CleanupDialog"));
4143 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4144 checker.set_position (Gtk::WIN_POS_MOUSE);
4146 switch (checker.run()) {
4147 case RESPONSE_ACCEPT:
4153 ARDOUR::CleanupReport rep;
4155 editor->prepare_for_cleanup ();
4157 /* do not allow flush until a session is reloaded */
4159 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4161 act->set_sensitive (false);
4164 if (_session->cleanup_sources (rep)) {
4165 editor->finish_cleanup ();
4169 editor->finish_cleanup ();
4172 display_cleanup_results (rep, _("Cleaned Files"), false);
4176 ARDOUR_UI::flush_trash ()
4178 if (_session == 0) {
4179 /* shouldn't happen: menu item is insensitive */
4183 ARDOUR::CleanupReport rep;
4185 if (_session->cleanup_trash_sources (rep)) {
4189 display_cleanup_results (rep, _("deleted file"), true);
4193 ARDOUR_UI::cleanup_peakfiles ()
4195 if (_session == 0) {
4196 /* shouldn't happen: menu item is insensitive */
4200 if (! _session->can_cleanup_peakfiles ()) {
4204 // get all region-views in this session
4206 TrackViewList empty;
4208 editor->get_regions_after(rs, (framepos_t) 0, empty);
4209 std::list<RegionView*> views = rs.by_layer();
4211 // remove displayed audio-region-views waveforms
4212 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4213 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4214 if (!arv) { continue ; }
4215 arv->delete_waves();
4218 // cleanup peak files:
4219 // - stop pending peakfile threads
4220 // - close peakfiles if any
4221 // - remove peak dir in session
4222 // - setup peakfiles (background thread)
4223 _session->cleanup_peakfiles ();
4225 // re-add waves to ARV
4226 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4227 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4228 if (!arv) { continue ; }
4229 arv->create_waves();
4233 PresentationInfo::order_t
4234 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4236 if (editor->get_selection().tracks.empty()) {
4237 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4240 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4243 we want the new routes to have their order keys set starting from
4244 the highest order key in the selection + 1 (if available).
4247 if (place == RouteDialogs::AfterSelection) {
4248 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4250 order_hint = rtav->route()->presentation_info().order();
4253 } else if (place == RouteDialogs::BeforeSelection) {
4254 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4256 order_hint = rtav->route()->presentation_info().order();
4258 } else if (place == RouteDialogs::First) {
4261 /* leave order_hint at max_order */
4268 ARDOUR_UI::start_duplicate_routes ()
4270 if (!duplicate_routes_dialog) {
4271 duplicate_routes_dialog = new DuplicateRouteDialog;
4274 if (duplicate_routes_dialog->restart (_session)) {
4278 duplicate_routes_dialog->present ();
4282 ARDOUR_UI::add_route ()
4284 if (!add_route_dialog.get (false)) {
4285 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4292 if (add_route_dialog->is_visible()) {
4293 /* we're already doing this */
4297 add_route_dialog->set_position (WIN_POS_MOUSE);
4298 add_route_dialog->present();
4302 ARDOUR_UI::add_route_dialog_response (int r)
4307 case AddRouteDialog::Add:
4309 case AddRouteDialog::AddAndClose:
4310 add_route_dialog->ArdourDialog::on_response (r);
4313 add_route_dialog->ArdourDialog::on_response (r);
4317 if ((count = add_route_dialog->count()) <= 0) {
4321 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4322 string template_path = add_route_dialog->track_template();
4323 DisplaySuspender ds;
4325 if (!template_path.empty()) {
4326 if (add_route_dialog->name_template_is_default()) {
4327 _session->new_route_from_template (count, order, template_path, string());
4329 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4334 ChanCount input_chan= add_route_dialog->channels ();
4335 ChanCount output_chan;
4336 string name_template = add_route_dialog->name_template ();
4337 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4338 RouteGroup* route_group = add_route_dialog->route_group ();
4339 AutoConnectOption oac = Config->get_output_auto_connect();
4340 bool strict_io = add_route_dialog->use_strict_io ();
4342 if (oac & AutoConnectMaster) {
4343 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4344 output_chan.set (DataType::MIDI, 0);
4346 output_chan = input_chan;
4349 /* XXX do something with name template */
4351 Session::ProcessorChangeBlocker pcb (_session);
4353 switch (add_route_dialog->type_wanted()) {
4354 case AddRouteDialog::AudioTrack:
4355 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4357 case AddRouteDialog::MidiTrack:
4358 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4360 case AddRouteDialog::MixedTrack:
4361 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4363 case AddRouteDialog::AudioBus:
4364 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4366 case AddRouteDialog::MidiBus:
4367 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4369 case AddRouteDialog::VCAMaster:
4370 session_add_vca (name_template, count);
4376 ARDOUR_UI::stop_video_server (bool ask_confirm)
4378 if (!video_server_process && ask_confirm) {
4379 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4381 if (video_server_process) {
4383 ArdourDialog confirm (_("Stop Video-Server"), true);
4384 Label m (_("Do you really want to stop the Video Server?"));
4385 confirm.get_vbox()->pack_start (m, true, true);
4386 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4387 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4388 confirm.show_all ();
4389 if (confirm.run() == RESPONSE_CANCEL) {
4393 delete video_server_process;
4394 video_server_process =0;
4399 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4401 ARDOUR_UI::start_video_server( float_window, true);
4405 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4411 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4412 if (video_server_process) {
4413 popup_error(_("The Video Server is already started."));
4415 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4421 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4423 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4425 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4427 video_server_dialog->set_transient_for (*float_window);
4430 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4431 video_server_dialog->hide();
4433 ResponseType r = (ResponseType) video_server_dialog->run ();
4434 video_server_dialog->hide();
4435 if (r != RESPONSE_ACCEPT) { return false; }
4436 if (video_server_dialog->show_again()) {
4437 Config->set_show_video_server_dialog(false);
4441 std::string icsd_exec = video_server_dialog->get_exec_path();
4442 std::string icsd_docroot = video_server_dialog->get_docroot();
4443 #ifndef PLATFORM_WINDOWS
4444 if (icsd_docroot.empty()) {
4445 icsd_docroot = VideoUtils::video_get_docroot (Config);
4450 #ifdef PLATFORM_WINDOWS
4451 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4452 /* OK, allow all drive letters */
4455 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4456 warning << _("Specified docroot is not an existing directory.") << endmsg;
4459 #ifndef PLATFORM_WINDOWS
4460 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4461 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4462 warning << _("Given Video Server is not an executable file.") << endmsg;
4466 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4467 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4468 warning << _("Given Video Server is not an executable file.") << endmsg;
4474 argp=(char**) calloc(9,sizeof(char*));
4475 argp[0] = strdup(icsd_exec.c_str());
4476 argp[1] = strdup("-P");
4477 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4478 argp[3] = strdup("-p");
4479 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4480 argp[5] = strdup("-C");
4481 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4482 argp[7] = strdup(icsd_docroot.c_str());
4484 stop_video_server();
4486 #ifdef PLATFORM_WINDOWS
4487 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4488 /* OK, allow all drive letters */
4491 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4492 Config->set_video_advanced_setup(false);
4494 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4495 Config->set_video_server_url(url_str);
4496 Config->set_video_server_docroot(icsd_docroot);
4497 Config->set_video_advanced_setup(true);
4500 if (video_server_process) {
4501 delete video_server_process;
4504 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4505 if (video_server_process->start()) {
4506 warning << _("Cannot launch the video-server") << endmsg;
4509 int timeout = 120; // 6 sec
4510 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4511 Glib::usleep (50000);
4513 if (--timeout <= 0 || !video_server_process->is_running()) break;
4516 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4518 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4519 delete video_server_process;
4520 video_server_process = 0;
4528 ARDOUR_UI::add_video (Gtk::Window* float_window)
4534 if (!start_video_server(float_window, false)) {
4535 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4540 add_video_dialog->set_transient_for (*float_window);
4543 if (add_video_dialog->is_visible()) {
4544 /* we're already doing this */
4548 ResponseType r = (ResponseType) add_video_dialog->run ();
4549 add_video_dialog->hide();
4550 if (r != RESPONSE_ACCEPT) { return; }
4552 bool local_file, orig_local_file;
4553 std::string path = add_video_dialog->file_name(local_file);
4555 std::string orig_path = path;
4556 orig_local_file = local_file;
4558 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4560 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4561 warning << string_compose(_("could not open %1"), path) << endmsg;
4564 if (!local_file && path.length() == 0) {
4565 warning << _("no video-file selected") << endmsg;
4569 std::string audio_from_video;
4570 bool detect_ltc = false;
4572 switch (add_video_dialog->import_option()) {
4573 case VTL_IMPORT_TRANSCODE:
4575 TranscodeVideoDialog *transcode_video_dialog;
4576 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4577 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4578 transcode_video_dialog->hide();
4579 if (r != RESPONSE_ACCEPT) {
4580 delete transcode_video_dialog;
4584 audio_from_video = transcode_video_dialog->get_audiofile();
4586 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4589 else if (!audio_from_video.empty()) {
4590 editor->embed_audio_from_video(
4592 video_timeline->get_offset(),
4593 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4596 switch (transcode_video_dialog->import_option()) {
4597 case VTL_IMPORT_TRANSCODED:
4598 path = transcode_video_dialog->get_filename();
4601 case VTL_IMPORT_REFERENCE:
4604 delete transcode_video_dialog;
4607 delete transcode_video_dialog;
4611 case VTL_IMPORT_NONE:
4615 /* strip _session->session_directory().video_path() from video file if possible */
4616 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4617 path=path.substr(_session->session_directory().video_path().size());
4618 if (path.at(0) == G_DIR_SEPARATOR) {
4619 path=path.substr(1);
4623 video_timeline->set_update_session_fps(auto_set_session_fps);
4625 if (video_timeline->video_file_info(path, local_file)) {
4626 XMLNode* node = new XMLNode(X_("Videotimeline"));
4627 node->set_property (X_("Filename"), path);
4628 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4629 node->set_property (X_("LocalFile"), local_file);
4630 if (orig_local_file) {
4631 node->set_property (X_("OriginalVideoFile"), orig_path);
4633 node->remove_property (X_("OriginalVideoFile"));
4635 _session->add_extra_xml (*node);
4636 _session->set_dirty ();
4638 if (!audio_from_video.empty() && detect_ltc) {
4639 std::vector<LTCFileReader::LTCMap> ltc_seq;
4642 /* TODO ask user about TV standard (LTC alignment if any) */
4643 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4644 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4646 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4648 /* TODO seek near end of file, and read LTC until end.
4649 * if it fails to find any LTC frames, scan complete file
4651 * calculate drift of LTC compared to video-duration,
4652 * ask user for reference (timecode from start/mid/end)
4655 // LTCFileReader will have written error messages
4658 ::g_unlink(audio_from_video.c_str());
4660 if (ltc_seq.size() == 0) {
4661 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4663 /* the very first TC in the file is somteimes not aligned properly */
4664 int i = ltc_seq.size() -1;
4665 ARDOUR::frameoffset_t video_start_offset =
4666 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4667 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4668 video_timeline->set_offset(video_start_offset);
4672 _session->maybe_update_session_range(
4673 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4674 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4677 if (add_video_dialog->launch_xjadeo() && local_file) {
4678 editor->set_xjadeo_sensitive(true);
4679 editor->toggle_xjadeo_proc(1);
4681 editor->toggle_xjadeo_proc(0);
4683 editor->toggle_ruler_video(true);
4688 ARDOUR_UI::remove_video ()
4690 video_timeline->close_session();
4691 editor->toggle_ruler_video(false);
4694 video_timeline->set_offset_locked(false);
4695 video_timeline->set_offset(0);
4697 /* delete session state */
4698 XMLNode* node = new XMLNode(X_("Videotimeline"));
4699 _session->add_extra_xml(*node);
4700 node = new XMLNode(X_("Videomonitor"));
4701 _session->add_extra_xml(*node);
4702 node = new XMLNode(X_("Videoexport"));
4703 _session->add_extra_xml(*node);
4704 stop_video_server();
4708 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4710 if (localcacheonly) {
4711 video_timeline->vmon_update();
4713 video_timeline->flush_cache();
4715 editor->queue_visual_videotimeline_update();
4719 ARDOUR_UI::export_video (bool range)
4721 if (ARDOUR::Config->get_show_video_export_info()) {
4722 ExportVideoInfobox infobox (_session);
4723 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4724 if (infobox.show_again()) {
4725 ARDOUR::Config->set_show_video_export_info(false);
4728 case GTK_RESPONSE_YES:
4729 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4735 export_video_dialog->set_session (_session);
4736 export_video_dialog->apply_state(editor->get_selection().time, range);
4737 export_video_dialog->run ();
4738 export_video_dialog->hide ();
4742 ARDOUR_UI::preferences_settings () const
4747 node = _session->instant_xml(X_("Preferences"));
4749 node = Config->instant_xml(X_("Preferences"));
4753 node = new XMLNode (X_("Preferences"));
4760 ARDOUR_UI::mixer_settings () const
4765 node = _session->instant_xml(X_("Mixer"));
4767 node = Config->instant_xml(X_("Mixer"));
4771 node = new XMLNode (X_("Mixer"));
4778 ARDOUR_UI::main_window_settings () const
4783 node = _session->instant_xml(X_("Main"));
4785 node = Config->instant_xml(X_("Main"));
4789 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4790 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4795 node = new XMLNode (X_("Main"));
4802 ARDOUR_UI::editor_settings () const
4807 node = _session->instant_xml(X_("Editor"));
4809 node = Config->instant_xml(X_("Editor"));
4813 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4814 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4819 node = new XMLNode (X_("Editor"));
4826 ARDOUR_UI::keyboard_settings () const
4830 node = Config->extra_xml(X_("Keyboard"));
4833 node = new XMLNode (X_("Keyboard"));
4840 ARDOUR_UI::create_xrun_marker (framepos_t where)
4843 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4844 _session->locations()->add (location);
4849 ARDOUR_UI::halt_on_xrun_message ()
4851 cerr << "HALT on xrun\n";
4852 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4857 ARDOUR_UI::xrun_handler (framepos_t where)
4863 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4865 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4866 create_xrun_marker(where);
4869 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4870 halt_on_xrun_message ();
4875 ARDOUR_UI::disk_overrun_handler ()
4877 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4879 if (!have_disk_speed_dialog_displayed) {
4880 have_disk_speed_dialog_displayed = true;
4881 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4882 The disk system on your computer\n\
4883 was not able to keep up with %1.\n\
4885 Specifically, it failed to write data to disk\n\
4886 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4887 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4893 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4894 static MessageDialog *scan_dlg = NULL;
4895 static ProgressBar *scan_pbar = NULL;
4896 static HBox *scan_tbox = NULL;
4897 static Gtk::Button *scan_timeout_button;
4900 ARDOUR_UI::cancel_plugin_scan ()
4902 PluginManager::instance().cancel_plugin_scan();
4906 ARDOUR_UI::cancel_plugin_timeout ()
4908 PluginManager::instance().cancel_plugin_timeout();
4909 scan_timeout_button->set_sensitive (false);
4913 ARDOUR_UI::plugin_scan_timeout (int timeout)
4915 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4919 scan_pbar->set_sensitive (false);
4920 scan_timeout_button->set_sensitive (true);
4921 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4924 scan_pbar->set_sensitive (false);
4925 scan_timeout_button->set_sensitive (false);
4931 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4933 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4937 const bool cancelled = PluginManager::instance().cancelled();
4938 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4939 if (cancelled && scan_dlg->is_mapped()) {
4944 if (cancelled || !can_cancel) {
4949 static Gtk::Button *cancel_button;
4951 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4952 VBox* vbox = scan_dlg->get_vbox();
4953 vbox->set_size_request(400,-1);
4954 scan_dlg->set_title (_("Scanning for plugins"));
4956 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4957 cancel_button->set_name ("EditorGTKButton");
4958 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4959 cancel_button->show();
4961 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4963 scan_tbox = manage( new HBox() );
4965 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4966 scan_timeout_button->set_name ("EditorGTKButton");
4967 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4968 scan_timeout_button->show();
4970 scan_pbar = manage(new ProgressBar());
4971 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4972 scan_pbar->set_text(_("Scan Timeout"));
4975 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4976 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4978 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4981 assert(scan_dlg && scan_tbox && cancel_button);
4983 if (type == X_("closeme")) {
4987 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4990 if (!can_cancel || !cancelled) {
4991 scan_timeout_button->set_sensitive(false);
4993 cancel_button->set_sensitive(can_cancel && !cancelled);
4999 ARDOUR_UI::gui_idle_handler ()
5002 /* due to idle calls, gtk_events_pending() may always return true */
5003 while (gtk_events_pending() && --timeout) {
5004 gtk_main_iteration ();
5009 ARDOUR_UI::disk_underrun_handler ()
5011 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5013 if (!have_disk_speed_dialog_displayed) {
5014 have_disk_speed_dialog_displayed = true;
5015 MessageDialog* msg = new MessageDialog (
5016 _main_window, string_compose (_("The disk system on your computer\n\
5017 was not able to keep up with %1.\n\
5019 Specifically, it failed to read data from disk\n\
5020 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5021 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5027 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5029 have_disk_speed_dialog_displayed = false;
5034 ARDOUR_UI::session_dialog (std::string msg)
5036 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5040 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5047 ARDOUR_UI::pending_state_dialog ()
5049 HBox* hbox = manage (new HBox());
5050 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5051 ArdourDialog dialog (_("Crash Recovery"), true);
5052 Label message (string_compose (_("\
5053 This session appears to have been in the\n\
5054 middle of recording when %1 or\n\
5055 the computer was shutdown.\n\
5057 %1 can recover any captured audio for\n\
5058 you, or it can ignore it. Please decide\n\
5059 what you would like to do.\n"), PROGRAM_NAME));
5060 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5061 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5062 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5063 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5064 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5065 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5066 dialog.set_default_response (RESPONSE_ACCEPT);
5067 dialog.set_position (WIN_POS_CENTER);
5072 switch (dialog.run ()) {
5073 case RESPONSE_ACCEPT:
5081 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5083 HBox* hbox = new HBox();
5084 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5085 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5086 Label message (string_compose (_("\
5087 This session was created with a sample rate of %1 Hz, but\n\
5088 %2 is currently running at %3 Hz. If you load this session,\n\
5089 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5091 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5092 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5093 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5094 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5095 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5096 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5097 dialog.set_default_response (RESPONSE_ACCEPT);
5098 dialog.set_position (WIN_POS_CENTER);
5103 switch (dialog.run()) {
5104 case RESPONSE_ACCEPT:
5114 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5116 MessageDialog msg (string_compose (_("\
5117 This session was created with a sample rate of %1 Hz, but\n\
5118 %2 is currently running at %3 Hz.\n\
5119 Audio will be recorded and played at the wrong sample rate.\n\
5120 Re-Configure the Audio Engine in\n\
5121 Menu > Window > Audio/Midi Setup"),
5122 desired, PROGRAM_NAME, actual),
5124 Gtk::MESSAGE_WARNING);
5129 ARDOUR_UI::use_config ()
5131 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5133 set_transport_controllable_state (*node);
5138 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5140 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5141 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5143 primary_clock->set (pos);
5146 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5147 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5149 secondary_clock->set (pos);
5152 if (big_clock_window) {
5153 big_clock->set (pos);
5155 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5159 ARDOUR_UI::step_edit_status_change (bool yn)
5161 // XXX should really store pre-step edit status of things
5162 // we make insensitive
5165 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5166 rec_button.set_sensitive (false);
5168 rec_button.unset_active_state ();;
5169 rec_button.set_sensitive (true);
5174 ARDOUR_UI::record_state_changed ()
5176 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5179 /* why bother - the clock isn't visible */
5183 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5185 if (big_clock_window) {
5186 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5187 big_clock->set_active (true);
5189 big_clock->set_active (false);
5196 ARDOUR_UI::first_idle ()
5199 _session->allow_auto_play (true);
5203 editor->first_idle();
5206 /* in 1 second, hide the splash screen
5208 * Consider hiding it *now*. If a user opens opens a dialog
5209 * during that one second while the splash is still visible,
5210 * the dialog will push-back the splash.
5211 * Closing the dialog later will pop it back.
5213 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5215 Keyboard::set_can_save_keybindings (true);
5220 ARDOUR_UI::store_clock_modes ()
5222 XMLNode* node = new XMLNode(X_("ClockModes"));
5224 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5225 XMLNode* child = new XMLNode (X_("Clock"));
5227 child->set_property (X_("name"), (*x)->name());
5228 child->set_property (X_("mode"), (*x)->mode());
5229 child->set_property (X_("on"), (*x)->on());
5231 node->add_child_nocopy (*child);
5234 _session->add_extra_xml (*node);
5235 _session->set_dirty ();
5238 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5239 : Controllable (name), ui (u), type(tp)
5245 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5248 /* do nothing: these are radio-style actions */
5252 const char *action = 0;
5256 action = X_("Roll");
5259 action = X_("Stop");
5262 action = X_("GotoStart");
5265 action = X_("GotoEnd");
5268 action = X_("Loop");
5271 action = X_("PlaySelection");
5274 action = X_("Record");
5284 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5292 ARDOUR_UI::TransportControllable::get_value (void) const
5319 ARDOUR_UI::setup_profile ()
5321 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5322 Profile->set_small_screen ();
5325 if (g_getenv ("TRX")) {
5326 Profile->set_trx ();
5329 if (g_getenv ("MIXBUS")) {
5330 Profile->set_mixbus ();
5335 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5337 MissingFileDialog dialog (s, str, type);
5342 int result = dialog.run ();
5349 return 1; // quit entire session load
5352 result = dialog.get_action ();
5358 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5360 AmbiguousFileDialog dialog (file, hits);
5367 return dialog.get_which ();
5370 /** Allocate our thread-local buffers */
5372 ARDOUR_UI::get_process_buffers ()
5374 _process_thread->get_buffers ();
5377 /** Drop our thread-local buffers */
5379 ARDOUR_UI::drop_process_buffers ()
5381 _process_thread->drop_buffers ();
5385 ARDOUR_UI::feedback_detected ()
5387 _feedback_exists = true;
5391 ARDOUR_UI::successful_graph_sort ()
5393 _feedback_exists = false;
5397 ARDOUR_UI::midi_panic ()
5400 _session->midi_panic();
5405 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5407 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5408 const char* end_big = "</span>";
5409 const char* start_mono = "<tt>";
5410 const char* end_mono = "</tt>";
5412 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5413 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5414 "From now on, use the backup copy with older versions of %3"),
5415 xml_path, backup_path, PROGRAM_NAME,
5417 start_mono, end_mono), true);
5423 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5425 using namespace Menu_Helpers;
5427 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5428 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5429 i->set_active (editor_meter->meter_type () == type);
5433 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5435 using namespace Gtk::Menu_Helpers;
5437 Gtk::Menu* m = manage (new Menu);
5438 MenuList& items = m->items ();
5440 RadioMenuItem::Group group;
5442 _suspend_editor_meter_callbacks = true;
5443 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5444 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5445 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5446 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5447 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5448 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5449 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5450 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5451 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5452 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5453 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5455 m->popup (ev->button, ev->time);
5456 _suspend_editor_meter_callbacks = false;
5460 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5462 if (ev->button == 3 && editor_meter) {
5463 popup_editor_meter_menu (ev);
5470 ARDOUR_UI::reset_peak_display ()
5472 if (!_session || !_session->master_out() || !editor_meter) return;
5473 editor_meter->clear_meters();
5474 editor_meter_max_peak = -INFINITY;
5475 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5479 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5481 if (!_session || !_session->master_out()) return;
5482 if (group == _session->master_out()->route_group()) {
5483 reset_peak_display ();
5488 ARDOUR_UI::reset_route_peak_display (Route* route)
5490 if (!_session || !_session->master_out()) return;
5491 if (_session->master_out().get() == route) {
5492 reset_peak_display ();
5497 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5499 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5500 audio_midi_setup->set_position (WIN_POS_CENTER);
5502 if (desired_sample_rate != 0) {
5503 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5504 audio_midi_setup->try_autostart ();
5505 if (ARDOUR::AudioEngine::instance()->running()) {
5512 int response = audio_midi_setup->run();
5514 case Gtk::RESPONSE_DELETE_EVENT:
5515 // after latency callibration engine may run,
5516 // Running() signal was emitted, but dialog will not
5517 // have emitted a response. The user needs to close
5518 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5519 if (!AudioEngine::instance()->running()) {
5524 if (!AudioEngine::instance()->running()) {
5527 audio_midi_setup->hide ();
5535 ARDOUR_UI::transport_numpad_timeout ()
5537 _numpad_locate_happening = false;
5538 if (_numpad_timeout_connection.connected() )
5539 _numpad_timeout_connection.disconnect();
5544 ARDOUR_UI::transport_numpad_decimal ()
5546 _numpad_timeout_connection.disconnect();
5548 if (_numpad_locate_happening) {
5549 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5550 _numpad_locate_happening = false;
5552 _pending_locate_num = 0;
5553 _numpad_locate_happening = true;
5554 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5559 ARDOUR_UI::transport_numpad_event (int num)
5561 if ( _numpad_locate_happening ) {
5562 _pending_locate_num = _pending_locate_num*10 + num;
5565 case 0: toggle_roll(false, false); break;
5566 case 1: transport_rewind(1); break;
5567 case 2: transport_forward(1); break;
5568 case 3: transport_record(true); break;
5569 case 4: toggle_session_auto_loop(); break;
5570 case 5: transport_record(false); toggle_session_auto_loop(); break;
5571 case 6: toggle_punch(); break;
5572 case 7: toggle_click(); break;
5573 case 8: toggle_auto_return(); break;
5574 case 9: toggle_follow_edits(); break;
5580 ARDOUR_UI::set_flat_buttons ()
5582 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5586 ARDOUR_UI::audioengine_became_silent ()
5588 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5590 Gtk::MESSAGE_WARNING,
5594 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5596 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5597 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5598 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5599 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5600 Gtk::HBox pay_button_box;
5601 Gtk::HBox subscribe_button_box;
5603 pay_button_box.pack_start (pay_button, true, false);
5604 subscribe_button_box.pack_start (subscribe_button, true, false);
5606 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 */
5608 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5609 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5611 msg.get_vbox()->pack_start (pay_label);
5612 msg.get_vbox()->pack_start (pay_button_box);
5613 msg.get_vbox()->pack_start (subscribe_label);
5614 msg.get_vbox()->pack_start (subscribe_button_box);
5616 msg.get_vbox()->show_all ();
5618 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5619 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5620 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5625 case Gtk::RESPONSE_YES:
5626 AudioEngine::instance()->reset_silence_countdown ();
5629 case Gtk::RESPONSE_NO:
5631 save_state_canfail ("");
5635 case Gtk::RESPONSE_CANCEL:
5637 /* don't reset, save session and exit */
5643 ARDOUR_UI::hide_application ()
5645 Application::instance ()-> hide ();
5649 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5651 /* icons, titles, WM stuff */
5653 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5655 if (window_icons.empty()) {
5656 Glib::RefPtr<Gdk::Pixbuf> icon;
5657 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5658 window_icons.push_back (icon);
5660 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5661 window_icons.push_back (icon);
5663 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5664 window_icons.push_back (icon);
5666 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5667 window_icons.push_back (icon);
5671 if (!window_icons.empty()) {
5672 window.set_default_icon_list (window_icons);
5675 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5677 if (!name.empty()) {
5681 window.set_title (title.get_string());
5682 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5684 window.set_flags (CAN_FOCUS);
5685 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5687 /* This is a hack to ensure that GTK-accelerators continue to
5688 * work. Once we switch over to entirely native bindings, this will be
5689 * unnecessary and should be removed
5691 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5693 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5694 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5695 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5696 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5700 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5702 Gtkmm2ext::Bindings* bindings = 0;
5703 Gtk::Window* window = 0;
5705 /* until we get ardour bindings working, we are not handling key
5709 if (ev->type != GDK_KEY_PRESS) {
5713 if (event_window == &_main_window) {
5715 window = event_window;
5717 /* find current tab contents */
5719 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5721 /* see if it uses the ardour binding system */
5724 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5727 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5731 window = event_window;
5733 /* see if window uses ardour binding system */
5735 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5738 /* An empty binding set is treated as if it doesn't exist */
5740 if (bindings && bindings->empty()) {
5744 return key_press_focus_accelerator_handler (*window, ev, bindings);
5747 static Gtkmm2ext::Bindings*
5748 get_bindings_from_widget_heirarchy (GtkWidget** w)
5753 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5756 *w = gtk_widget_get_parent (*w);
5759 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5763 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5765 GtkWindow* win = window.gobj();
5766 GtkWidget* focus = gtk_window_get_focus (win);
5767 GtkWidget* binding_widget = focus;
5768 bool special_handling_of_unmodified_accelerators = false;
5769 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5773 /* some widget has keyboard focus */
5775 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5777 /* A particular kind of focusable widget currently has keyboard
5778 * focus. All unmodified key events should go to that widget
5779 * first and not be used as an accelerator by default
5782 special_handling_of_unmodified_accelerators = true;
5786 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5787 if (focus_bindings) {
5788 bindings = focus_bindings;
5789 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5794 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",
5797 Gtkmm2ext::show_gdk_event_state (ev->state),
5798 special_handling_of_unmodified_accelerators,
5799 Keyboard::some_magic_widget_has_focus(),
5801 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5802 ((ev->state & mask) ? "yes" : "no"),
5803 window.get_title()));
5805 /* This exists to allow us to override the way GTK handles
5806 key events. The normal sequence is:
5808 a) event is delivered to a GtkWindow
5809 b) accelerators/mnemonics are activated
5810 c) if (b) didn't handle the event, propagate to
5811 the focus widget and/or focus chain
5813 The problem with this is that if the accelerators include
5814 keys without modifiers, such as the space bar or the
5815 letter "e", then pressing the key while typing into
5816 a text entry widget results in the accelerator being
5817 activated, instead of the desired letter appearing
5820 There is no good way of fixing this, but this
5821 represents a compromise. The idea is that
5822 key events involving modifiers (not Shift)
5823 get routed into the activation pathway first, then
5824 get propagated to the focus widget if necessary.
5826 If the key event doesn't involve modifiers,
5827 we deliver to the focus widget first, thus allowing
5828 it to get "normal text" without interference
5831 Of course, this can also be problematic: if there
5832 is a widget with focus, then it will swallow
5833 all "normal text" accelerators.
5837 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5839 /* no special handling or there are modifiers in effect: accelerate first */
5841 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5842 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5843 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5845 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5846 KeyboardKey k (ev->state, ev->keyval);
5850 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5852 if (bindings->activate (k, Bindings::Press)) {
5853 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5857 if (binding_widget) {
5858 binding_widget = gtk_widget_get_parent (binding_widget);
5859 if (binding_widget) {
5860 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5869 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5871 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5872 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5876 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5878 if (gtk_window_propagate_key_event (win, ev)) {
5879 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5885 /* no modifiers, propagate first */
5887 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5889 if (gtk_window_propagate_key_event (win, ev)) {
5890 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5894 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5895 KeyboardKey k (ev->state, ev->keyval);
5899 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5902 if (bindings->activate (k, Bindings::Press)) {
5903 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5907 if (binding_widget) {
5908 binding_widget = gtk_widget_get_parent (binding_widget);
5909 if (binding_widget) {
5910 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5919 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5921 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5922 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5927 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5932 ARDOUR_UI::load_bindings ()
5934 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5935 error << _("Global keybindings are missing") << endmsg;
5940 ARDOUR_UI::cancel_solo ()
5943 _session->cancel_all_solo ();
5948 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5950 /* this resets focus to the first focusable parent of the given widget,
5951 * or, if there is no focusable parent, cancels focus in the toplevel
5952 * window that the given widget is packed into (if there is one).
5959 Gtk::Widget* top = w->get_toplevel();
5961 if (!top || !top->is_toplevel()) {
5965 w = w->get_parent ();
5969 if (w->is_toplevel()) {
5970 /* Setting the focus widget to a Gtk::Window causes all
5971 * subsequent calls to ::has_focus() on the nominal
5972 * focus widget in that window to return
5973 * false. Workaround: never set focus to the toplevel
5979 if (w->get_can_focus ()) {
5980 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5981 win->set_focus (*w);
5984 w = w->get_parent ();
5987 if (top == &_main_window) {
5991 /* no focusable parent found, cancel focus in top level window.
5992 C++ API cannot be used for this. Thanks, references.
5995 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);