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 "time_axis_view_item.h"
181 #include "time_info_box.h"
184 #include "utils_videotl.h"
185 #include "video_server_dialog.h"
186 #include "add_video_dialog.h"
187 #include "transcode_video_dialog.h"
189 #include "pbd/i18n.h"
191 using namespace ARDOUR;
192 using namespace ARDOUR_UI_UTILS;
194 using namespace Gtkmm2ext;
197 using namespace Editing;
199 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
201 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
202 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
205 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
207 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
208 "Would you like these files to be copied and used for %1 %2.x?\n\n"
209 "(This will require you to restart %1.)"),
210 PROGRAM_NAME, PROGRAM_VERSION, version),
211 false, /* no markup */
214 true /* modal, though it hardly matters since it is the only window */
217 msg.set_default_response (Gtk::RESPONSE_YES);
220 return (msg.run() == Gtk::RESPONSE_YES);
224 libxml_generic_error_func (void* /* parsing_context*/,
232 vsnprintf (buf, sizeof (buf), msg, ap);
233 error << buf << endmsg;
238 libxml_structured_error_func (void* /* parsing_context*/,
246 replace_all (msg, "\n", "");
249 if (err->file && err->line) {
250 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
253 error << ':' << err->int2;
258 error << X_("XML error: ") << msg << endmsg;
264 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
265 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
266 , session_loaded (false)
267 , session_load_in_progress (false)
268 , gui_object_state (new GUIObjectState)
269 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
270 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
271 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
273 , global_actions (X_("global"))
274 , ignore_dual_punch (false)
275 , main_window_visibility (0)
280 , _mixer_on_top (false)
281 , _initial_verbose_plugin_scan (false)
282 , first_time_engine_run (true)
283 , secondary_clock_spacer (0)
284 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
285 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
286 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
287 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
288 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
289 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
290 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
291 , auto_input_button (ArdourButton::led_default_elements)
293 , auto_return_button (ArdourButton::led_default_elements)
294 , follow_edits_button (ArdourButton::led_default_elements)
295 , auditioning_alert_button (_("Audition"))
296 , solo_alert_button (_("Solo"))
297 , feedback_alert_button (_("Feedback"))
298 , error_alert_button ( ArdourButton::just_led_default_elements )
300 , editor_meter_peak_display()
301 , _suspend_editor_meter_callbacks (false)
302 , _numpad_locate_happening (false)
303 , _session_is_new (false)
304 , last_key_press_time (0)
308 , rc_option_editor (0)
309 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
310 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
311 , about (X_("about"), _("About"))
312 , location_ui (X_("locations"), S_("Ranges|Locations"))
313 , route_params (X_("inspector"), _("Tracks and Busses"))
314 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
315 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
316 , lua_script_window (X_("script-manager"), _("Script Manager"))
317 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
318 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
319 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
320 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
321 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
322 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
323 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
324 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
325 , video_server_process (0)
327 , have_configure_timeout (false)
328 , last_configure_time (0)
330 , have_disk_speed_dialog_displayed (false)
331 , _status_bar_visibility (X_("status-bar"))
332 , _feedback_exists (false)
333 , _log_not_acknowledged (LogLevelNone)
334 , duplicate_routes_dialog (0)
335 , editor_visibility_button (S_("Window|Editor"))
336 , mixer_visibility_button (S_("Window|Mixer"))
337 , prefs_visibility_button (S_("Window|Preferences"))
339 Gtkmm2ext::init (localedir);
341 UIConfiguration::instance().post_gui_init ();
343 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
345 /* "touch" the been-here-before path now that config has been migrated */
346 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
348 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
350 /* configuration was modified, exit immediately */
355 if (string (VERSIONSTRING).find (".pre") != string::npos) {
356 /* check this is not being run from ./ardev etc. */
357 if (!running_from_source_tree ()) {
358 pre_release_dialog ();
362 if (theArdourUI == 0) {
366 /* track main window visibility */
368 main_window_visibility = new VisibilityTracker (_main_window);
370 /* stop libxml from spewing to stdout/stderr */
372 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
373 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
375 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
376 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
377 UIConfiguration::instance().map_parameters (pc);
379 roll_button.set_controllable (roll_controllable);
380 stop_button.set_controllable (stop_controllable);
381 goto_start_button.set_controllable (goto_start_controllable);
382 goto_end_button.set_controllable (goto_end_controllable);
383 auto_loop_button.set_controllable (auto_loop_controllable);
384 play_selection_button.set_controllable (play_selection_controllable);
385 rec_button.set_controllable (rec_controllable);
387 roll_button.set_name ("transport button");
388 stop_button.set_name ("transport button");
389 goto_start_button.set_name ("transport button");
390 goto_end_button.set_name ("transport button");
391 auto_loop_button.set_name ("transport button");
392 play_selection_button.set_name ("transport button");
393 rec_button.set_name ("transport recenable button");
394 midi_panic_button.set_name ("transport button");
396 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
397 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
399 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
401 /* handle dialog requests */
403 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
405 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
407 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
409 /* handle Audio/MIDI setup when session requires it */
411 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
413 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
415 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
417 /* handle sr mismatch with a dialog - cross-thread from engine */
418 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
420 /* handle requests to quit (coming from JACK session) */
422 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
424 /* tell the user about feedback */
426 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
427 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
429 /* handle requests to deal with missing files */
431 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
433 /* and ambiguous files */
435 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
437 /* also plugin scan messages */
438 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
439 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
441 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
443 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
446 /* lets get this party started */
448 setup_gtk_ardour_enums ();
451 SessionEvent::create_per_thread_pool ("GUI", 4096);
453 /* we like keyboards */
455 keyboard = new ArdourKeyboard(*this);
457 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
459 keyboard->set_state (*node, Stateful::loading_state_version);
462 UIConfiguration::instance().reset_dpi ();
464 TimeAxisViewItem::set_constant_heights ();
466 /* Set this up so that our window proxies can register actions */
468 ActionManager::init ();
470 /* The following must happen after ARDOUR::init() so that Config is set up */
472 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
475 key_editor.set_state (*ui_xml, 0);
476 session_option_editor.set_state (*ui_xml, 0);
477 speaker_config_window.set_state (*ui_xml, 0);
478 about.set_state (*ui_xml, 0);
479 add_route_dialog.set_state (*ui_xml, 0);
480 add_video_dialog.set_state (*ui_xml, 0);
481 route_params.set_state (*ui_xml, 0);
482 bundle_manager.set_state (*ui_xml, 0);
483 location_ui.set_state (*ui_xml, 0);
484 big_clock_window.set_state (*ui_xml, 0);
485 audio_port_matrix.set_state (*ui_xml, 0);
486 midi_port_matrix.set_state (*ui_xml, 0);
487 export_video_dialog.set_state (*ui_xml, 0);
488 lua_script_window.set_state (*ui_xml, 0);
489 idleometer.set_state (*ui_xml, 0);
492 /* Separate windows */
494 WM::Manager::instance().register_window (&key_editor);
495 WM::Manager::instance().register_window (&session_option_editor);
496 WM::Manager::instance().register_window (&speaker_config_window);
497 WM::Manager::instance().register_window (&about);
498 WM::Manager::instance().register_window (&add_route_dialog);
499 WM::Manager::instance().register_window (&add_video_dialog);
500 WM::Manager::instance().register_window (&route_params);
501 WM::Manager::instance().register_window (&audio_midi_setup);
502 WM::Manager::instance().register_window (&export_video_dialog);
503 WM::Manager::instance().register_window (&lua_script_window);
504 WM::Manager::instance().register_window (&bundle_manager);
505 WM::Manager::instance().register_window (&location_ui);
506 WM::Manager::instance().register_window (&big_clock_window);
507 WM::Manager::instance().register_window (&audio_port_matrix);
508 WM::Manager::instance().register_window (&midi_port_matrix);
509 WM::Manager::instance().register_window (&idleometer);
511 /* do not retain position for add route dialog */
512 add_route_dialog.set_state_mask (WindowProxy::Size);
514 /* Trigger setting up the color scheme and loading the GTK RC file */
516 UIConfiguration::instance().load_rc_file (false);
518 _process_thread = new ProcessThread ();
519 _process_thread->init ();
521 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
527 ARDOUR_UI::pre_release_dialog ()
529 ArdourDialog d (_("Pre-Release Warning"), true, false);
530 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
532 Label* label = manage (new Label);
533 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
534 There are still several issues and bugs to be worked on,\n\
535 as well as general workflow improvements, before this can be considered\n\
536 release software. So, a few guidelines:\n\
538 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
539 though it may be so, depending on your workflow.\n\
540 2) Please wait for a helpful writeup of new features.\n\
541 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
542 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
543 making sure to note the product version number as 5.0-pre.\n\
544 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
545 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
546 can get there directly from within the program via the Help->Chat menu option.\n\
548 Full information on all the above can be found on the support page at\n\
550 http://ardour.org/support\n\
551 "), PROGRAM_NAME, VERSIONSTRING));
553 d.get_vbox()->set_border_width (12);
554 d.get_vbox()->pack_start (*label, false, false, 12);
555 d.get_vbox()->show_all ();
560 GlobalPortMatrixWindow*
561 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
566 return new GlobalPortMatrixWindow (_session, type);
570 ARDOUR_UI::attach_to_engine ()
572 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
573 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
577 ARDOUR_UI::engine_stopped ()
579 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
580 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
581 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
582 update_sample_rate (0);
587 ARDOUR_UI::engine_running ()
589 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
590 if (first_time_engine_run) {
592 first_time_engine_run = false;
596 _session->reset_xrun_count ();
598 update_disk_space ();
600 update_xrun_count ();
601 update_sample_rate (AudioEngine::instance()->sample_rate());
602 update_timecode_format ();
603 update_peak_thread_work ();
604 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
605 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
609 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
611 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
612 /* we can't rely on the original string continuing to exist when we are called
613 again in the GUI thread, so make a copy and note that we need to
616 char *copy = strdup (reason);
617 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
621 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
622 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
624 update_sample_rate (0);
628 /* if the reason is a non-empty string, it means that the backend was shutdown
629 rather than just Ardour.
632 if (strlen (reason)) {
633 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
635 msgstr = string_compose (_("\
636 The audio backend has either been shutdown or it\n\
637 disconnected %1 because %1\n\
638 was not fast enough. Try to restart\n\
639 the audio backend and save the session."), PROGRAM_NAME);
642 MessageDialog msg (_main_window, msgstr);
643 pop_back_splash (msg);
647 free (const_cast<char*> (reason));
652 ARDOUR_UI::post_engine ()
654 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
656 #ifdef AUDIOUNIT_SUPPORT
658 if (AUPluginInfo::au_get_crashlog(au_msg)) {
659 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
660 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
661 info << au_msg << endmsg;
665 ARDOUR::init_post_engine ();
667 /* connect to important signals */
669 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
670 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
671 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
672 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
673 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
675 if (setup_windows ()) {
676 throw failed_constructor ();
679 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
680 XMLNode* n = Config->extra_xml (X_("UI"));
682 _status_bar_visibility.set_state (*n);
685 check_memory_locking();
687 /* this is the first point at which all the possible actions are
688 * available, because some of the available actions are dependent on
689 * aspects of the engine/backend.
692 if (ARDOUR_COMMAND_LINE::show_key_actions) {
694 Bindings::save_all_bindings_as_html (sstr);
696 if (sstr.str().empty()) {
703 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
705 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
711 #ifdef PLATFORM_WINDOWS
717 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
718 #ifndef PLATFORM_WINDOWS
721 g_unlink (file_name);
723 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
729 #ifndef PLATFORM_WINDOWS
733 PBD::open_uri (string_compose ("file:///%1", file_name));
735 halt_connection.disconnect ();
736 AudioEngine::instance()->stop ();
741 if (ARDOUR_COMMAND_LINE::show_actions) {
744 vector<string> paths;
745 vector<string> labels;
746 vector<string> tooltips;
748 vector<Glib::RefPtr<Gtk::Action> > actions;
749 string ver_in = revision;
750 string ver = ver_in.substr(0, ver_in.find("-"));
753 output << "\n<h2>Menu actions</h2>" << endl;
754 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
755 output << " surfaces or scripts.\n</p>\n" << endl;
756 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
757 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
758 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
759 output << "<table class=\"dl\">\n <thead>" << endl;
760 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
761 output << " </thead>\n <tbody>" << endl;
763 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
765 vector<string>::iterator p;
766 vector<string>::iterator l;
768 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
769 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
770 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
772 output << " </tbody>\n </table>" << endl;
774 // output this mess to a browser for easiest X-platform use
775 // it is not pretty HTML, but it works and it's main purpose
776 // is to create raw html to fit in Ardour's manual with no editing
781 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
783 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
789 #ifdef PLATFORM_WINDOWS
795 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
796 #ifndef PLATFORM_WINDOWS
799 g_unlink (file_name);
801 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
807 #ifndef PLATFORM_WINDOWS
811 PBD::open_uri (string_compose ("file:///%1", file_name));
813 halt_connection.disconnect ();
814 AudioEngine::instance()->stop ();
818 /* this being a GUI and all, we want peakfiles */
820 AudioFileSource::set_build_peakfiles (true);
821 AudioFileSource::set_build_missing_peakfiles (true);
823 /* set default clock modes */
825 primary_clock->set_mode (AudioClock::Timecode);
826 secondary_clock->set_mode (AudioClock::BBT);
828 /* start the time-of-day-clock */
831 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
832 update_wall_clock ();
833 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
838 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
839 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
840 Config->map_parameters (pc);
842 UIConfiguration::instance().map_parameters (pc);
846 ARDOUR_UI::~ARDOUR_UI ()
848 UIConfiguration::instance().save_state();
852 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
853 // don't bother at 'real' exit. the OS cleans up for us.
854 delete big_clock; big_clock = 0;
855 delete primary_clock; primary_clock = 0;
856 delete secondary_clock; secondary_clock = 0;
857 delete _process_thread; _process_thread = 0;
858 delete time_info_box; time_info_box = 0;
859 delete meterbridge; meterbridge = 0;
860 delete luawindow; luawindow = 0;
861 delete editor; editor = 0;
862 delete mixer; mixer = 0;
863 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
865 delete gui_object_state; gui_object_state = 0;
866 delete main_window_visibility;
867 FastMeter::flush_pattern_cache ();
868 PixFader::flush_pattern_cache ();
872 /* Small trick to flush main-thread event pool.
873 * Other thread-pools are destroyed at pthread_exit(),
874 * but tmain thread termination is too late to trigger Pool::~Pool()
876 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.
877 delete ev->event_pool();
882 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
884 if (Splash::instance()) {
885 Splash::instance()->pop_back_for (win);
890 ARDOUR_UI::configure_timeout ()
892 if (last_configure_time == 0) {
893 /* no configure events yet */
897 /* force a gap of 0.5 seconds since the last configure event
900 if (get_microseconds() - last_configure_time < 500000) {
903 have_configure_timeout = false;
904 save_ardour_state ();
910 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
912 if (have_configure_timeout) {
913 last_configure_time = get_microseconds();
915 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
916 have_configure_timeout = true;
923 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
927 if (node.get_property ("roll", str)){
928 roll_controllable->set_id (str);
930 if (node.get_property ("stop", str)) {
931 stop_controllable->set_id (str);
933 if (node.get_property ("goto-start", str)) {
934 goto_start_controllable->set_id (str);
936 if (node.get_property ("goto-end", str)) {
937 goto_end_controllable->set_id (str);
939 if (node.get_property ("auto-loop", str)) {
940 auto_loop_controllable->set_id (str);
942 if (node.get_property ("play-selection", str)) {
943 play_selection_controllable->set_id (str);
945 if (node.get_property ("rec", str)) {
946 rec_controllable->set_id (str);
948 if (node.get_property ("shuttle", str)) {
949 shuttle_box.controllable()->set_id (str);
954 ARDOUR_UI::get_transport_controllable_state ()
956 XMLNode* node = new XMLNode(X_("TransportControllables"));
958 node->set_property (X_("roll"), roll_controllable->id());
959 node->set_property (X_("stop"), stop_controllable->id());
960 node->set_property (X_("goto-start"), goto_start_controllable->id());
961 node->set_property (X_("goto-end"), goto_end_controllable->id());
962 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
963 node->set_property (X_("play-selection"), play_selection_controllable->id());
964 node->set_property (X_("rec"), rec_controllable->id());
965 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
971 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
974 _session->save_state (snapshot_name);
979 ARDOUR_UI::autosave_session ()
981 if (g_main_depth() > 1) {
982 /* inside a recursive main loop,
983 give up because we may not be able to
989 if (!Config->get_periodic_safety_backups()) {
994 _session->maybe_write_autosave();
1001 ARDOUR_UI::session_dirty_changed ()
1008 ARDOUR_UI::update_autosave ()
1010 if (_session && _session->dirty()) {
1011 if (_autosave_connection.connected()) {
1012 _autosave_connection.disconnect();
1015 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1016 Config->get_periodic_safety_backup_interval() * 1000);
1019 if (_autosave_connection.connected()) {
1020 _autosave_connection.disconnect();
1026 ARDOUR_UI::check_announcements ()
1029 string _annc_filename;
1032 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1033 #elif defined PLATFORM_WINDOWS
1034 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1036 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1038 _annc_filename.append (VERSIONSTRING);
1040 _announce_string = "";
1042 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1043 FILE* fin = g_fopen (path.c_str(), "rb");
1045 while (!feof (fin)) {
1048 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1051 _announce_string.append (tmp, len);
1056 pingback (VERSIONSTRING, path);
1061 _hide_splash (gpointer arg)
1063 ((ARDOUR_UI*)arg)->hide_splash();
1068 ARDOUR_UI::starting ()
1070 Application* app = Application::instance ();
1071 const char *nsm_url;
1072 bool brand_new_user = ArdourStartup::required ();
1074 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1075 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1077 if (ARDOUR_COMMAND_LINE::check_announcements) {
1078 check_announcements ();
1083 /* we need to create this early because it may need to set the
1084 * audio backend end up.
1088 audio_midi_setup.get (true);
1090 std::cerr << "audio-midi engine setup failed."<< std::endl;
1094 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1095 nsm = new NSM_Client;
1096 if (!nsm->init (nsm_url)) {
1097 /* the ardour executable may have different names:
1099 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1100 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1101 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1103 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1105 const char *process_name = g_getenv ("ARDOUR_SELF");
1106 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1109 // wait for announce reply from nsm server
1110 for ( i = 0; i < 5000; ++i) {
1114 if (nsm->is_active()) {
1119 error << _("NSM server did not announce itself") << endmsg;
1122 // wait for open command from nsm server
1123 for ( i = 0; i < 5000; ++i) {
1125 Glib::usleep (1000);
1126 if (nsm->client_id ()) {
1132 error << _("NSM: no client ID provided") << endmsg;
1136 if (_session && nsm) {
1137 _session->set_nsm_state( nsm->is_active() );
1139 error << _("NSM: no session created") << endmsg;
1143 // nsm requires these actions disabled
1144 vector<string> action_names;
1145 action_names.push_back("SaveAs");
1146 action_names.push_back("Rename");
1147 action_names.push_back("New");
1148 action_names.push_back("Open");
1149 action_names.push_back("Recent");
1150 action_names.push_back("Close");
1152 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1153 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1155 act->set_sensitive (false);
1162 error << _("NSM: initialization failed") << endmsg;
1168 if (brand_new_user) {
1169 _initial_verbose_plugin_scan = true;
1174 _initial_verbose_plugin_scan = false;
1175 switch (s.response ()) {
1176 case Gtk::RESPONSE_OK:
1183 // TODO: maybe IFF brand_new_user
1184 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1185 std::string dspd (Config->get_default_session_parent_dir());
1186 Searchpath ds (ARDOUR::ardour_data_search_path());
1187 ds.add_subdirectory_to_paths ("sessions");
1188 vector<string> demos;
1189 find_files_matching_pattern (demos, ds, "*.tar.xz");
1191 ARDOUR::RecentSessions rs;
1192 ARDOUR::read_recent_sessions (rs);
1194 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1195 /* "demo-session" must be inside "demo-session.tar.xz"
1198 std::string name = basename_nosuffix (basename_nosuffix (*i));
1199 std::string path = Glib::build_filename (dspd, name);
1200 /* skip if session-dir already exists */
1201 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1204 /* skip sessions that are already in 'recent'.
1205 * eg. a new user changed <session-default-dir> shorly after installation
1207 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1208 if ((*r).first == name) {
1213 PBD::FileArchive ar (*i);
1214 if (0 == ar.inflate (dspd)) {
1215 store_recent_sessions (name, path);
1216 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1222 #ifdef NO_PLUGIN_STATE
1224 ARDOUR::RecentSessions rs;
1225 ARDOUR::read_recent_sessions (rs);
1227 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1229 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1231 /* already used Ardour, have sessions ... warn about plugin state */
1233 ArdourDialog d (_("Free/Demo Version Warning"), true);
1235 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1236 CheckButton c (_("Don't warn me about this again"));
1238 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"),
1239 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1240 _("It will not restore OR save any plugin settings"),
1241 _("If you load an existing session with plugin settings\n"
1242 "they will not be used and will be lost."),
1243 _("To get full access to updates without this limitation\n"
1244 "consider becoming a subscriber for a low cost every month.")));
1245 l.set_justify (JUSTIFY_CENTER);
1247 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1249 d.get_vbox()->pack_start (l, true, true);
1250 d.get_vbox()->pack_start (b, false, false, 12);
1251 d.get_vbox()->pack_start (c, false, false, 12);
1253 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1254 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1258 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1260 if (d.run () != RESPONSE_OK) {
1266 /* go get a session */
1268 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1270 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1271 std::cerr << "Cannot get session parameters."<< std::endl;
1278 WM::Manager::instance().show_visible ();
1280 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1281 * editor window, and we may want stuff to be hidden.
1283 _status_bar_visibility.update ();
1285 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1288 // in 1 second, hide the splash screen
1289 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1292 /* all other dialogs are created conditionally */
1298 ARDOUR_UI::check_memory_locking ()
1300 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1301 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1305 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1307 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1309 struct rlimit limits;
1311 long pages, page_size;
1313 size_t pages_len=sizeof(pages);
1314 if ((page_size = getpagesize()) < 0 ||
1315 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1317 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1322 ram = (int64_t) pages * (int64_t) page_size;
1325 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1329 if (limits.rlim_cur != RLIM_INFINITY) {
1331 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1335 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1336 "This might cause %1 to run out of memory before your system "
1337 "runs out of memory. \n\n"
1338 "You can view the memory limit with 'ulimit -l', "
1339 "and it is normally controlled by %2"),
1342 X_("/etc/login.conf")
1344 X_(" /etc/security/limits.conf")
1348 msg.set_default_response (RESPONSE_OK);
1350 VBox* vbox = msg.get_vbox();
1352 CheckButton cb (_("Do not show this window again"));
1353 hbox.pack_start (cb, true, false);
1354 vbox->pack_start (hbox);
1359 pop_back_splash (msg);
1363 if (cb.get_active()) {
1364 XMLNode node (X_("no-memory-warning"));
1365 Config->add_instant_xml (node);
1370 #endif // !__APPLE__
1375 ARDOUR_UI::queue_finish ()
1377 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1381 ARDOUR_UI::idle_finish ()
1384 return false; /* do not call again */
1391 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1393 if (_session->dirty()) {
1394 vector<string> actions;
1395 actions.push_back (_("Don't quit"));
1396 actions.push_back (_("Just quit"));
1397 actions.push_back (_("Save and quit"));
1398 switch (ask_about_saving_session(actions)) {
1403 /* use the default name */
1404 if (save_state_canfail ("")) {
1405 /* failed - don't quit */
1406 MessageDialog msg (_main_window,
1407 string_compose (_("\
1408 %1 was unable to save your session.\n\n\
1409 If you still wish to quit, please use the\n\n\
1410 \"Just quit\" option."), PROGRAM_NAME));
1411 pop_back_splash(msg);
1421 second_connection.disconnect ();
1422 point_one_second_connection.disconnect ();
1423 point_zero_something_second_connection.disconnect();
1424 fps_connection.disconnect();
1427 delete ARDOUR_UI::instance()->video_timeline;
1428 ARDOUR_UI::instance()->video_timeline = NULL;
1429 stop_video_server();
1431 /* Save state before deleting the session, as that causes some
1432 windows to be destroyed before their visible state can be
1435 save_ardour_state ();
1437 if (key_editor.get (false)) {
1438 key_editor->disconnect ();
1441 close_all_dialogs ();
1444 _session->set_clean ();
1445 _session->remove_pending_capture_state ();
1450 halt_connection.disconnect ();
1451 AudioEngine::instance()->stop ();
1452 #ifdef WINDOWS_VST_SUPPORT
1453 fst_stop_threading();
1459 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1461 ArdourDialog window (_("Unsaved Session"));
1462 Gtk::HBox dhbox; // the hbox for the image and text
1463 Gtk::Label prompt_label;
1464 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1468 assert (actions.size() >= 3);
1470 window.add_button (actions[0], RESPONSE_REJECT);
1471 window.add_button (actions[1], RESPONSE_APPLY);
1472 window.add_button (actions[2], RESPONSE_ACCEPT);
1474 window.set_default_response (RESPONSE_ACCEPT);
1476 Gtk::Button noquit_button (msg);
1477 noquit_button.set_name ("EditorGTKButton");
1481 if (_session->snap_name() == _session->name()) {
1482 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?"),
1483 _session->snap_name());
1485 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?"),
1486 _session->snap_name());
1489 prompt_label.set_text (prompt);
1490 prompt_label.set_name (X_("PrompterLabel"));
1491 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1493 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1494 dhbox.set_homogeneous (false);
1495 dhbox.pack_start (*dimage, false, false, 5);
1496 dhbox.pack_start (prompt_label, true, false, 5);
1497 window.get_vbox()->pack_start (dhbox);
1499 window.set_name (_("Prompter"));
1500 window.set_modal (true);
1501 window.set_resizable (false);
1504 prompt_label.show();
1509 ResponseType r = (ResponseType) window.run();
1514 case RESPONSE_ACCEPT: // save and get out of here
1516 case RESPONSE_APPLY: // get out of here
1527 ARDOUR_UI::every_second ()
1530 update_xrun_count ();
1531 update_buffer_load ();
1532 update_disk_space ();
1533 update_timecode_format ();
1534 update_peak_thread_work ();
1536 if (nsm && nsm->is_active ()) {
1539 if (!_was_dirty && _session->dirty ()) {
1543 else if (_was_dirty && !_session->dirty ()){
1551 ARDOUR_UI::every_point_one_seconds ()
1553 // TODO get rid of this..
1554 // ShuttleControl is updated directly via TransportStateChange signal
1558 ARDOUR_UI::every_point_zero_something_seconds ()
1560 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1562 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1563 float mpeak = editor_meter->update_meters();
1564 if (mpeak > editor_meter_max_peak) {
1565 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1566 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1573 ARDOUR_UI::set_fps_timeout_connection ()
1575 unsigned int interval = 40;
1576 if (!_session) return;
1577 if (_session->timecode_frames_per_second() != 0) {
1578 /* ideally we'll use a select() to sleep and not accumulate
1579 * idle time to provide a regular periodic signal.
1580 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1581 * However, that'll require a dedicated thread and cross-thread
1582 * signals to the GUI Thread..
1584 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1585 * _session->frame_rate() / _session->nominal_frame_rate()
1586 / _session->timecode_frames_per_second()
1588 #ifdef PLATFORM_WINDOWS
1589 // the smallest windows scheduler time-slice is ~15ms.
1590 // periodic GUI timeouts shorter than that will cause
1591 // WaitForSingleObject to spinlock (100% of one CPU Core)
1592 // and gtk never enters idle mode.
1593 // also changing timeBeginPeriod(1) does not affect that in
1594 // any beneficial way, so we just limit the max rate for now.
1595 interval = std::max(30u, interval); // at most ~33Hz.
1597 interval = std::max(8u, interval); // at most 120Hz.
1600 fps_connection.disconnect();
1601 Timers::set_fps_interval (interval);
1605 ARDOUR_UI::update_sample_rate (framecnt_t)
1609 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1611 if (!AudioEngine::instance()->connected()) {
1613 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1617 framecnt_t rate = AudioEngine::instance()->sample_rate();
1620 /* no sample rate available */
1621 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1624 if (fmod (rate, 1000.0) != 0.0) {
1625 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1626 (float) rate / 1000.0f,
1627 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1629 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1631 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1635 sample_rate_label.set_markup (buf);
1639 ARDOUR_UI::update_format ()
1642 format_label.set_text ("");
1647 s << _("File:") << X_(" <span foreground=\"green\">");
1649 switch (_session->config.get_native_file_header_format ()) {
1681 switch (_session->config.get_native_file_data_format ()) {
1695 format_label.set_markup (s.str ());
1699 ARDOUR_UI::update_xrun_count ()
1703 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1704 should also be changed.
1708 const unsigned int x = _session->get_xrun_count ();
1710 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1712 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1715 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1717 xrun_label.set_markup (buf);
1718 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1722 ARDOUR_UI::update_cpu_load ()
1726 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1727 should also be changed.
1730 double const c = AudioEngine::instance()->get_dsp_load ();
1731 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1732 cpu_load_label.set_markup (buf);
1736 ARDOUR_UI::update_peak_thread_work ()
1739 const int c = SourceFactory::peak_work_queue_length ();
1741 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1742 peak_thread_work_label.set_markup (buf);
1744 peak_thread_work_label.set_markup (X_(""));
1749 ARDOUR_UI::update_buffer_load ()
1753 uint32_t const playback = _session ? _session->playback_load () : 100;
1754 uint32_t const capture = _session ? _session->capture_load () : 100;
1756 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1757 should also be changed.
1763 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1764 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1765 playback <= 5 ? X_("red") : X_("green"),
1767 capture <= 5 ? X_("red") : X_("green"),
1771 buffer_load_label.set_markup (buf);
1773 buffer_load_label.set_text ("");
1778 ARDOUR_UI::count_recenabled_streams (Route& route)
1780 Track* track = dynamic_cast<Track*>(&route);
1781 if (track && track->rec_enable_control()->get_value()) {
1782 rec_enabled_streams += track->n_inputs().n_total();
1787 ARDOUR_UI::update_disk_space()
1789 if (_session == 0) {
1793 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1795 framecnt_t fr = _session->frame_rate();
1798 /* skip update - no SR available */
1803 /* Available space is unknown */
1804 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1805 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1806 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1808 rec_enabled_streams = 0;
1809 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1811 framecnt_t frames = opt_frames.get_value_or (0);
1813 if (rec_enabled_streams) {
1814 frames /= rec_enabled_streams;
1821 hrs = frames / (fr * 3600);
1824 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1826 frames -= hrs * fr * 3600;
1827 mins = frames / (fr * 60);
1828 frames -= mins * fr * 60;
1831 bool const low = (hrs == 0 && mins <= 30);
1835 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1836 low ? X_("red") : X_("green"),
1842 disk_space_label.set_markup (buf);
1846 ARDOUR_UI::update_timecode_format ()
1852 TimecodeSlave* tcslave;
1853 SyncSource sync_src = Config->get_sync_source();
1855 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1856 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1861 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1862 matching ? X_("green") : X_("red"),
1863 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1865 snprintf (buf, sizeof (buf), "TC: n/a");
1868 timecode_format_label.set_markup (buf);
1872 ARDOUR_UI::update_wall_clock ()
1876 static int last_min = -1;
1879 tm_now = localtime (&now);
1880 if (last_min != tm_now->tm_min) {
1882 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1883 wall_clock_label.set_text (buf);
1884 last_min = tm_now->tm_min;
1891 ARDOUR_UI::open_recent_session ()
1893 bool can_return = (_session != 0);
1895 SessionDialog recent_session_dialog;
1899 ResponseType r = (ResponseType) recent_session_dialog.run ();
1902 case RESPONSE_ACCEPT:
1906 recent_session_dialog.hide();
1913 recent_session_dialog.hide();
1917 std::string path = recent_session_dialog.session_folder();
1918 std::string state = recent_session_dialog.session_name (should_be_new);
1920 if (should_be_new == true) {
1924 _session_is_new = false;
1926 if (load_session (path, state) == 0) {
1933 // in 1 second, hide the splash screen
1934 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1939 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1941 if (!AudioEngine::instance()->connected()) {
1942 MessageDialog msg (parent, string_compose (
1943 _("%1 is not connected to any audio backend.\n"
1944 "You cannot open or close sessions in this condition"),
1946 pop_back_splash (msg);
1954 ARDOUR_UI::open_session ()
1956 if (!check_audioengine (_main_window)) {
1960 /* ardour sessions are folders */
1961 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1962 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1963 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1964 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1967 string session_parent_dir = Glib::path_get_dirname(_session->path());
1968 open_session_selector.set_current_folder(session_parent_dir);
1970 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1973 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1975 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1976 string default_session_folder = Config->get_default_session_parent_dir();
1977 open_session_selector.add_shortcut_folder (default_session_folder);
1979 catch (Glib::Error & e) {
1980 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1983 FileFilter session_filter;
1984 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1985 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1986 open_session_selector.add_filter (session_filter);
1988 FileFilter archive_filter;
1989 archive_filter.add_pattern (X_("*.tar.xz"));
1990 archive_filter.set_name (_("Session Archives"));
1992 open_session_selector.add_filter (archive_filter);
1994 open_session_selector.set_filter (session_filter);
1996 int response = open_session_selector.run();
1997 open_session_selector.hide ();
1999 if (response == Gtk::RESPONSE_CANCEL) {
2003 string session_path = open_session_selector.get_filename();
2007 if (session_path.length() > 0) {
2008 int rv = ARDOUR::inflate_session (session_path,
2009 Config->get_default_session_parent_dir(), path, name);
2011 _session_is_new = false;
2012 load_session (path, name);
2015 MessageDialog msg (_main_window,
2016 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2019 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2020 _session_is_new = isnew;
2021 load_session (path, name);
2027 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
2033 _session->vca_manager().create_vca (n, name_template);
2037 ARDOUR_UI::session_add_mixed_track (
2038 const ChanCount& input,
2039 const ChanCount& output,
2040 RouteGroup* route_group,
2042 const string& name_template,
2044 PluginInfoPtr instrument,
2045 Plugin::PresetRecord* pset,
2046 ARDOUR::PresentationInfo::order_t order)
2048 if (_session == 0) {
2049 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2053 if (Profile->get_mixbus ()) {
2058 list<boost::shared_ptr<MidiTrack> > tracks;
2059 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2061 if (tracks.size() != how_many) {
2062 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2067 display_insufficient_ports_message ();
2073 ARDOUR_UI::session_add_midi_bus (
2074 RouteGroup* route_group,
2076 const string& name_template,
2078 PluginInfoPtr instrument,
2079 Plugin::PresetRecord* pset,
2080 ARDOUR::PresentationInfo::order_t order)
2082 if (_session == 0) {
2083 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2087 if (Profile->get_mixbus ()) {
2093 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2094 if (routes.size() != how_many) {
2095 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2100 display_insufficient_ports_message ();
2106 ARDOUR_UI::session_add_midi_route (
2108 RouteGroup* route_group,
2110 const string& name_template,
2112 PluginInfoPtr instrument,
2113 Plugin::PresetRecord* pset,
2114 ARDOUR::PresentationInfo::order_t order)
2116 ChanCount one_midi_channel;
2117 one_midi_channel.set (DataType::MIDI, 1);
2120 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2122 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2127 ARDOUR_UI::session_add_audio_route (
2129 int32_t input_channels,
2130 int32_t output_channels,
2131 ARDOUR::TrackMode mode,
2132 RouteGroup* route_group,
2134 string const & name_template,
2136 ARDOUR::PresentationInfo::order_t order)
2138 list<boost::shared_ptr<AudioTrack> > tracks;
2141 if (_session == 0) {
2142 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2148 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2150 if (tracks.size() != how_many) {
2151 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2157 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2159 if (routes.size() != how_many) {
2160 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2167 display_insufficient_ports_message ();
2172 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2173 (*i)->set_strict_io (true);
2175 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2176 (*i)->set_strict_io (true);
2182 ARDOUR_UI::display_insufficient_ports_message ()
2184 MessageDialog msg (_main_window,
2185 string_compose (_("There are insufficient ports available\n\
2186 to create a new track or bus.\n\
2187 You should save %1, exit and\n\
2188 restart with more ports."), PROGRAM_NAME));
2189 pop_back_splash (msg);
2194 ARDOUR_UI::transport_goto_start ()
2197 _session->goto_start();
2199 /* force displayed area in editor to start no matter
2200 what "follow playhead" setting is.
2204 editor->center_screen (_session->current_start_frame ());
2210 ARDOUR_UI::transport_goto_zero ()
2213 _session->request_locate (0);
2215 /* force displayed area in editor to start no matter
2216 what "follow playhead" setting is.
2220 editor->reset_x_origin (0);
2226 ARDOUR_UI::transport_goto_wallclock ()
2228 if (_session && editor) {
2235 localtime_r (&now, &tmnow);
2237 framecnt_t frame_rate = _session->frame_rate();
2239 if (frame_rate == 0) {
2240 /* no frame rate available */
2244 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2245 frames += tmnow.tm_min * (60 * frame_rate);
2246 frames += tmnow.tm_sec * frame_rate;
2248 _session->request_locate (frames, _session->transport_rolling ());
2250 /* force displayed area in editor to start no matter
2251 what "follow playhead" setting is.
2255 editor->center_screen (frames);
2261 ARDOUR_UI::transport_goto_end ()
2264 framepos_t const frame = _session->current_end_frame();
2265 _session->request_locate (frame);
2267 /* force displayed area in editor to start no matter
2268 what "follow playhead" setting is.
2272 editor->center_screen (frame);
2278 ARDOUR_UI::transport_stop ()
2284 if (_session->is_auditioning()) {
2285 _session->cancel_audition ();
2289 _session->request_stop (false, true);
2292 /** Check if any tracks are record enabled. If none are, record enable all of them.
2293 * @return true if track record-enabled status was changed, false otherwise.
2296 ARDOUR_UI::trx_record_enable_all_tracks ()
2302 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2303 bool none_record_enabled = true;
2305 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2306 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2309 if (t->rec_enable_control()->get_value()) {
2310 none_record_enabled = false;
2315 if (none_record_enabled) {
2316 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2319 return none_record_enabled;
2323 ARDOUR_UI::transport_record (bool roll)
2326 switch (_session->record_status()) {
2327 case Session::Disabled:
2328 if (_session->ntracks() == 0) {
2329 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."));
2333 if (Profile->get_trx()) {
2334 roll = trx_record_enable_all_tracks ();
2336 _session->maybe_enable_record ();
2341 case Session::Recording:
2343 _session->request_stop();
2345 _session->disable_record (false, true);
2349 case Session::Enabled:
2350 _session->disable_record (false, true);
2356 ARDOUR_UI::transport_roll ()
2362 if (_session->is_auditioning()) {
2367 if (_session->config.get_external_sync()) {
2368 switch (Config->get_sync_source()) {
2372 /* transport controlled by the master */
2378 bool rolling = _session->transport_rolling();
2380 if (_session->get_play_loop()) {
2382 /* If loop playback is not a mode, then we should cancel
2383 it when this action is requested. If it is a mode
2384 we just leave it in place.
2387 if (!Config->get_loop_is_mode()) {
2388 /* XXX it is not possible to just leave seamless loop and keep
2389 playing at present (nov 4th 2009)
2391 if (!Config->get_seamless_loop()) {
2392 /* stop loop playback and stop rolling */
2393 _session->request_play_loop (false, true);
2394 } else if (rolling) {
2395 /* stop loop playback but keep rolling */
2396 _session->request_play_loop (false, false);
2400 } else if (_session->get_play_range () ) {
2401 /* stop playing a range if we currently are */
2402 _session->request_play_range (0, true);
2406 _session->request_transport_speed (1.0f);
2411 ARDOUR_UI::get_smart_mode() const
2413 return ( editor->get_smart_mode() );
2418 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2424 if (_session->is_auditioning()) {
2425 _session->cancel_audition ();
2429 if (_session->config.get_external_sync()) {
2430 switch (Config->get_sync_source()) {
2434 /* transport controlled by the master */
2439 bool rolling = _session->transport_rolling();
2440 bool affect_transport = true;
2442 if (rolling && roll_out_of_bounded_mode) {
2443 /* drop out of loop/range playback but leave transport rolling */
2444 if (_session->get_play_loop()) {
2445 if (_session->actively_recording()) {
2447 /* just stop using the loop, then actually stop
2450 _session->request_play_loop (false, affect_transport);
2453 if (Config->get_seamless_loop()) {
2454 /* the disk buffers contain copies of the loop - we can't
2455 just keep playing, so stop the transport. the user
2456 can restart as they wish.
2458 affect_transport = true;
2460 /* disk buffers are normal, so we can keep playing */
2461 affect_transport = false;
2463 _session->request_play_loop (false, affect_transport);
2465 } else if (_session->get_play_range ()) {
2466 affect_transport = false;
2467 _session->request_play_range (0, true);
2471 if (affect_transport) {
2473 _session->request_stop (with_abort, true);
2475 } else if (!with_abort) { /* with_abort == true means the
2476 * command was intended to stop
2477 * transport, not start.
2480 /* the only external sync condition we can be in here
2481 * would be Engine (JACK) sync, in which case we still
2485 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
2486 _session->request_play_range (&editor->get_selection().time, true);
2487 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2489 _session->request_transport_speed (1.0f);
2495 ARDOUR_UI::toggle_session_auto_loop ()
2501 Location * looploc = _session->locations()->auto_loop_location();
2507 if (_session->get_play_loop()) {
2509 /* looping enabled, our job is to disable it */
2511 _session->request_play_loop (false);
2515 /* looping not enabled, our job is to enable it.
2517 loop-is-NOT-mode: this action always starts the transport rolling.
2518 loop-IS-mode: this action simply sets the loop play mechanism, but
2519 does not start transport.
2521 if (Config->get_loop_is_mode()) {
2522 _session->request_play_loop (true, false);
2524 _session->request_play_loop (true, true);
2528 //show the loop markers
2529 looploc->set_hidden (false, this);
2533 ARDOUR_UI::transport_play_selection ()
2539 editor->play_selection ();
2543 ARDOUR_UI::transport_play_preroll ()
2548 editor->play_with_preroll ();
2552 ARDOUR_UI::transport_rec_preroll ()
2557 editor->rec_with_preroll ();
2561 ARDOUR_UI::transport_rec_count_in ()
2566 editor->rec_with_count_in ();
2570 ARDOUR_UI::transport_rewind (int option)
2572 float current_transport_speed;
2575 current_transport_speed = _session->transport_speed();
2577 if (current_transport_speed >= 0.0f) {
2580 _session->request_transport_speed (-1.0f);
2583 _session->request_transport_speed (-4.0f);
2586 _session->request_transport_speed (-0.5f);
2591 _session->request_transport_speed (current_transport_speed * 1.5f);
2597 ARDOUR_UI::transport_forward (int option)
2603 float current_transport_speed = _session->transport_speed();
2605 if (current_transport_speed <= 0.0f) {
2608 _session->request_transport_speed (1.0f);
2611 _session->request_transport_speed (4.0f);
2614 _session->request_transport_speed (0.5f);
2619 _session->request_transport_speed (current_transport_speed * 1.5f);
2624 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2630 boost::shared_ptr<Route> r;
2632 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2634 boost::shared_ptr<Track> t;
2636 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2637 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2643 ARDOUR_UI::map_transport_state ()
2646 auto_loop_button.unset_active_state ();
2647 play_selection_button.unset_active_state ();
2648 roll_button.unset_active_state ();
2649 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2650 layered_button.set_sensitive (false);
2654 shuttle_box.map_transport_state ();
2656 float sp = _session->transport_speed();
2662 if (_session->get_play_range()) {
2664 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2665 roll_button.unset_active_state ();
2666 auto_loop_button.unset_active_state ();
2668 } else if (_session->get_play_loop ()) {
2670 auto_loop_button.set_active (true);
2671 play_selection_button.set_active (false);
2672 if (Config->get_loop_is_mode()) {
2673 roll_button.set_active (true);
2675 roll_button.set_active (false);
2680 roll_button.set_active (true);
2681 play_selection_button.set_active (false);
2682 auto_loop_button.set_active (false);
2685 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2686 /* light up both roll and play-selection if they are joined */
2687 roll_button.set_active (true);
2688 play_selection_button.set_active (true);
2690 layered_button.set_sensitive (!_session->actively_recording ());
2692 stop_button.set_active (false);
2696 layered_button.set_sensitive (true);
2697 stop_button.set_active (true);
2698 roll_button.set_active (false);
2699 play_selection_button.set_active (false);
2700 if (Config->get_loop_is_mode ()) {
2701 auto_loop_button.set_active (_session->get_play_loop());
2703 auto_loop_button.set_active (false);
2705 update_disk_space ();
2710 ARDOUR_UI::blink_handler (bool blink_on)
2712 transport_rec_enable_blink (blink_on);
2713 sync_blink (blink_on);
2715 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2718 error_blink (blink_on);
2719 solo_blink (blink_on);
2720 audition_blink (blink_on);
2721 feedback_blink (blink_on);
2725 ARDOUR_UI::update_clocks ()
2727 if (!_session) return;
2729 if (editor && !editor->dragging_playhead()) {
2730 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2735 ARDOUR_UI::start_clocking ()
2737 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2738 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2740 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2745 ARDOUR_UI::stop_clocking ()
2747 clock_signal_connection.disconnect ();
2751 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2755 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2757 label->set_text (buf);
2758 bar->set_fraction (fraction);
2760 /* process events, redraws, etc. */
2762 while (gtk_events_pending()) {
2763 gtk_main_iteration ();
2766 return true; /* continue with save-as */
2770 ARDOUR_UI::save_session_as ()
2776 if (!save_as_dialog) {
2777 save_as_dialog = new SaveAsDialog;
2780 save_as_dialog->set_name (_session->name());
2782 int response = save_as_dialog->run ();
2784 save_as_dialog->hide ();
2787 case Gtk::RESPONSE_OK:
2796 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2797 sa.new_name = save_as_dialog->new_name ();
2798 sa.switch_to = save_as_dialog->switch_to();
2799 sa.copy_media = save_as_dialog->copy_media();
2800 sa.copy_external = save_as_dialog->copy_external();
2801 sa.include_media = save_as_dialog->include_media ();
2803 /* Only bother with a progress dialog if we're going to copy
2804 media into the save-as target. Without that choice, this
2805 will be very fast because we're only talking about a few kB's to
2806 perhaps a couple of MB's of data.
2809 ArdourDialog progress_dialog (_("Save As"), true);
2812 if (sa.include_media && sa.copy_media) {
2814 Gtk::Label* label = manage (new Gtk::Label());
2815 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2817 progress_dialog.get_vbox()->pack_start (*label);
2818 progress_dialog.get_vbox()->pack_start (*progress_bar);
2820 progress_bar->show ();
2822 /* this signal will be emitted from within this, the calling thread,
2823 * after every file is copied. It provides information on percentage
2824 * complete (in terms of total data to copy), the number of files
2825 * copied so far, and the total number to copy.
2828 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2830 progress_dialog.show_all ();
2831 progress_dialog.present ();
2834 if (_session->save_as (sa)) {
2836 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2840 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2841 * the trick is this: if the new session was copy with media included,
2842 * then Session::save_as() will have already done a neat trick to avoid
2843 * us having to unload and load the new state. But if the media was not
2844 * included, then this is required (it avoids us having to otherwise
2845 * drop all references to media (sources).
2848 if (!sa.include_media && sa.switch_to) {
2849 unload_session (false);
2850 load_session (sa.final_session_folder_name, sa.new_name);
2856 ARDOUR_UI::archive_session ()
2864 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2866 SessionArchiveDialog sad;
2867 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2868 int response = sad.run ();
2870 if (response != Gtk::RESPONSE_OK) {
2875 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2876 MessageDialog msg (_("Session Archiving failed."));
2882 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2886 struct tm local_time;
2889 localtime_r (&n, &local_time);
2890 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2892 save_state (timebuf, switch_to_it);
2897 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2901 prompter.get_result (snapname);
2903 bool do_save = (snapname.length() != 0);
2906 char illegal = Session::session_name_is_legal(snapname);
2908 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2909 "snapshot names may not contain a '%1' character"), illegal));
2915 vector<std::string> p;
2916 get_state_files_in_directory (_session->session_directory().root_path(), p);
2917 vector<string> n = get_file_names_no_extension (p);
2919 if (find (n.begin(), n.end(), snapname) != n.end()) {
2921 do_save = overwrite_file_dialog (prompter,
2922 _("Confirm Snapshot Overwrite"),
2923 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2927 save_state (snapname, switch_to_it);
2937 /** Ask the user for the name of a new snapshot and then take it.
2941 ARDOUR_UI::snapshot_session (bool switch_to_it)
2943 ArdourPrompter prompter (true);
2945 prompter.set_name ("Prompter");
2946 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2948 prompter.set_title (_("Snapshot and switch"));
2949 prompter.set_prompt (_("New session name"));
2951 prompter.set_title (_("Take Snapshot"));
2952 prompter.set_prompt (_("Name of new snapshot"));
2956 prompter.set_initial_text (_session->snap_name());
2958 Glib::DateTime tm (g_date_time_new_now_local ());
2959 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2962 bool finished = false;
2964 switch (prompter.run()) {
2965 case RESPONSE_ACCEPT:
2967 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2978 /** Ask the user for a new session name and then rename the session to it.
2982 ARDOUR_UI::rename_session ()
2988 ArdourPrompter prompter (true);
2991 prompter.set_name ("Prompter");
2992 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2993 prompter.set_title (_("Rename Session"));
2994 prompter.set_prompt (_("New session name"));
2997 switch (prompter.run()) {
2998 case RESPONSE_ACCEPT:
3000 prompter.get_result (name);
3002 bool do_rename = (name.length() != 0);
3005 char illegal = Session::session_name_is_legal (name);
3008 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3009 "session names may not contain a '%1' character"), illegal));
3014 switch (_session->rename (name)) {
3016 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3017 msg.set_position (WIN_POS_MOUSE);
3025 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3026 msg.set_position (WIN_POS_MOUSE);
3042 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3044 if (!_session || _session->deletion_in_progress()) {
3048 XMLNode* node = new XMLNode (X_("UI"));
3050 WM::Manager::instance().add_state (*node);
3052 node->add_child_nocopy (gui_object_state->get_state());
3054 _session->add_extra_xml (*node);
3056 if (export_video_dialog) {
3057 _session->add_extra_xml (export_video_dialog->get_state());
3060 save_state_canfail (name, switch_to_it);
3064 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3069 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3074 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3079 ARDOUR_UI::primary_clock_value_changed ()
3082 _session->request_locate (primary_clock->current_time ());
3087 ARDOUR_UI::big_clock_value_changed ()
3090 _session->request_locate (big_clock->current_time ());
3095 ARDOUR_UI::secondary_clock_value_changed ()
3098 _session->request_locate (secondary_clock->current_time ());
3103 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3105 if (_session == 0) {
3109 if (_session->step_editing()) {
3113 Session::RecordState const r = _session->record_status ();
3114 bool const h = _session->have_rec_enabled_track ();
3116 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3118 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3120 rec_button.set_active_state (Gtkmm2ext::Off);
3122 } else if (r == Session::Recording && h) {
3123 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3125 rec_button.unset_active_state ();
3130 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3134 prompter.get_result (name);
3136 if (name.length()) {
3137 int failed = _session->save_template (name);
3139 if (failed == -2) { /* file already exists. */
3140 bool overwrite = overwrite_file_dialog (prompter,
3141 _("Confirm Template Overwrite"),
3142 _("A template already exists with that name. Do you want to overwrite it?"));
3145 _session->save_template (name, true);
3157 ARDOUR_UI::save_template ()
3159 ArdourPrompter prompter (true);
3161 if (!check_audioengine (_main_window)) {
3165 prompter.set_name (X_("Prompter"));
3166 prompter.set_title (_("Save Template"));
3167 prompter.set_prompt (_("Name for template:"));
3168 prompter.set_initial_text(_session->name() + _("-template"));
3169 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3171 bool finished = false;
3173 switch (prompter.run()) {
3174 case RESPONSE_ACCEPT:
3175 finished = process_save_template_prompter (prompter);
3186 ARDOUR_UI::edit_metadata ()
3188 SessionMetadataEditor dialog;
3189 dialog.set_session (_session);
3190 dialog.grab_focus ();
3195 ARDOUR_UI::import_metadata ()
3197 SessionMetadataImporter dialog;
3198 dialog.set_session (_session);
3203 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3205 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3207 MessageDialog msg (str,
3209 Gtk::MESSAGE_WARNING,
3210 Gtk::BUTTONS_YES_NO,
3214 msg.set_name (X_("OpenExistingDialog"));
3215 msg.set_title (_("Open Existing Session"));
3216 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3217 msg.set_position (Gtk::WIN_POS_CENTER);
3218 pop_back_splash (msg);
3220 switch (msg.run()) {
3229 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3231 BusProfile bus_profile;
3235 bus_profile.master_out_channels = 2;
3236 bus_profile.input_ac = AutoConnectPhysical;
3237 bus_profile.output_ac = AutoConnectMaster;
3238 bus_profile.requested_physical_in = 0; // use all available
3239 bus_profile.requested_physical_out = 0; // use all available
3243 /* get settings from advanced section of NSD */
3245 if (sd.create_master_bus()) {
3246 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3248 bus_profile.master_out_channels = 0;
3251 if (sd.connect_inputs()) {
3252 bus_profile.input_ac = AutoConnectPhysical;
3254 bus_profile.input_ac = AutoConnectOption (0);
3257 bus_profile.output_ac = AutoConnectOption (0);
3259 if (sd.connect_outputs ()) {
3260 if (sd.connect_outs_to_master()) {
3261 bus_profile.output_ac = AutoConnectMaster;
3262 } else if (sd.connect_outs_to_physical()) {
3263 bus_profile.output_ac = AutoConnectPhysical;
3267 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3268 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3271 if (build_session (session_path, session_name, bus_profile)) {
3279 ARDOUR_UI::load_from_application_api (const std::string& path)
3281 /* OS X El Capitan (and probably later) now somehow passes the command
3282 line arguments to an app via the openFile delegate protocol. Ardour
3283 already does its own command line processing, and having both
3284 pathways active causes crashes. So, if the command line was already
3285 set, do nothing here.
3288 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3292 ARDOUR_COMMAND_LINE::session_name = path;
3294 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3296 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3298 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3299 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3300 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3301 * -> SessionDialog is not displayed
3304 if (_session_dialog) {
3305 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3306 std::string session_path = path;
3307 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3308 session_path = Glib::path_get_dirname (session_path);
3310 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3311 _session_dialog->set_provided_session (session_name, session_path);
3312 _session_dialog->response (RESPONSE_NONE);
3313 _session_dialog->hide();
3318 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3319 /* /path/to/foo => /path/to/foo, foo */
3320 rv = load_session (path, basename_nosuffix (path));
3322 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3323 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3326 // if load_session fails -> pop up SessionDialog.
3328 ARDOUR_COMMAND_LINE::session_name = "";
3330 if (get_session_parameters (true, false)) {
3336 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3338 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3340 string session_name;
3341 string session_path;
3342 string template_name;
3344 bool likely_new = false;
3345 bool cancel_not_quit;
3347 /* deal with any existing DIRTY session now, rather than later. don't
3348 * treat a non-dirty session this way, so that it stays visible
3349 * as we bring up the new session dialog.
3352 if (_session && ARDOUR_UI::instance()->video_timeline) {
3353 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3356 /* if there is already a session, relabel the button
3357 on the SessionDialog so that we don't Quit directly
3359 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3361 if (_session && _session->dirty()) {
3362 if (unload_session (false)) {
3363 /* unload cancelled by user */
3366 ARDOUR_COMMAND_LINE::session_name = "";
3369 if (!load_template.empty()) {
3370 should_be_new = true;
3371 template_name = load_template;
3374 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3375 session_path = ARDOUR_COMMAND_LINE::session_name;
3377 if (!session_path.empty()) {
3378 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3379 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3380 /* session/snapshot file, change path to be dir */
3381 session_path = Glib::path_get_dirname (session_path);
3386 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3388 _session_dialog = &session_dialog;
3391 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3393 /* if they named a specific statefile, use it, otherwise they are
3394 just giving a session folder, and we want to use it as is
3395 to find the session.
3398 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3400 if (suffix != string::npos) {
3401 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3402 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3403 session_name = Glib::path_get_basename (session_name);
3405 session_path = ARDOUR_COMMAND_LINE::session_name;
3406 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3411 session_dialog.clear_given ();
3414 if (should_be_new || session_name.empty()) {
3415 /* need the dialog to get info from user */
3417 cerr << "run dialog\n";
3419 switch (session_dialog.run()) {
3420 case RESPONSE_ACCEPT:
3423 /* this is used for async * app->ShouldLoad(). */
3424 continue; // while loop
3427 if (quit_on_cancel) {
3428 // JE - Currently (July 2014) this section can only get reached if the
3429 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3430 // point does NOT indicate an abnormal termination). Therefore, let's
3431 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3433 pthread_cancel_all ();
3441 session_dialog.hide ();
3444 /* if we run the startup dialog again, offer more than just "new session" */
3446 should_be_new = false;
3448 session_name = session_dialog.session_name (likely_new);
3449 session_path = session_dialog.session_folder ();
3456 int rv = ARDOUR::inflate_session (session_name,
3457 Config->get_default_session_parent_dir(), session_path, session_name);
3459 MessageDialog msg (session_dialog,
3460 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3465 session_dialog.set_provided_session (session_name, session_path);
3469 // XXX check archive, inflate
3470 string::size_type suffix = session_name.find (statefile_suffix);
3472 if (suffix != string::npos) {
3473 session_name = session_name.substr (0, suffix);
3476 /* this shouldn't happen, but we catch it just in case it does */
3478 if (session_name.empty()) {
3482 if (session_dialog.use_session_template()) {
3483 template_name = session_dialog.session_template_name();
3484 _session_is_new = true;
3487 if (session_name[0] == G_DIR_SEPARATOR ||
3488 #ifdef PLATFORM_WINDOWS
3489 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3491 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3492 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3497 /* absolute path or cwd-relative path specified for session name: infer session folder
3498 from what was given.
3501 session_path = Glib::path_get_dirname (session_name);
3502 session_name = Glib::path_get_basename (session_name);
3506 session_path = session_dialog.session_folder();
3508 char illegal = Session::session_name_is_legal (session_name);
3511 MessageDialog msg (session_dialog,
3512 string_compose (_("To ensure compatibility with various systems\n"
3513 "session names may not contain a '%1' character"),
3516 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3521 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3524 if (likely_new && !nsm) {
3526 std::string existing = Glib::build_filename (session_path, session_name);
3528 if (!ask_about_loading_existing_session (existing)) {
3529 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3534 _session_is_new = false;
3539 pop_back_splash (session_dialog);
3540 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3542 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3546 char illegal = Session::session_name_is_legal(session_name);
3549 pop_back_splash (session_dialog);
3550 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3551 "session names may not contain a '%1' character"), illegal));
3553 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3557 _session_is_new = true;
3560 if (likely_new && template_name.empty()) {
3562 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3566 ret = load_session (session_path, session_name, template_name);
3569 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3573 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3574 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3578 /* clear this to avoid endless attempts to load the
3582 ARDOUR_COMMAND_LINE::session_name = "";
3586 _session_dialog = NULL;
3592 ARDOUR_UI::close_session()
3594 if (!check_audioengine (_main_window)) {
3598 if (unload_session (true)) {
3602 ARDOUR_COMMAND_LINE::session_name = "";
3604 if (get_session_parameters (true, false)) {
3607 if (splash && splash->is_visible()) {
3608 // in 1 second, hide the splash screen
3609 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3613 /** @param snap_name Snapshot name (without .ardour suffix).
3614 * @return -2 if the load failed because we are not connected to the AudioEngine.
3617 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3619 /* load_session calls flush_pending() which allows
3620 * GUI interaction and potentially loading another session
3621 * (that was easy via snapshot sidebar).
3622 * Recursing into load_session() from load_session() and recusive
3623 * event loops causes all kind of crashes.
3625 assert (!session_load_in_progress);
3626 if (session_load_in_progress) {
3629 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3631 Session *new_session;
3636 unload_status = unload_session ();
3638 if (unload_status < 0) {
3640 } else if (unload_status > 0) {
3646 session_loaded = false;
3648 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3651 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3654 /* this one is special */
3656 catch (AudioEngine::PortRegistrationFailure& err) {
3658 MessageDialog msg (err.what(),
3661 Gtk::BUTTONS_CLOSE);
3663 msg.set_title (_("Port Registration Error"));
3664 msg.set_secondary_text (_("Click the Close button to try again."));
3665 msg.set_position (Gtk::WIN_POS_CENTER);
3666 pop_back_splash (msg);
3669 int response = msg.run ();
3674 case RESPONSE_CANCEL:
3681 catch (SessionException e) {
3682 MessageDialog msg (string_compose(
3683 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3684 path, snap_name, e.what()),
3689 msg.set_title (_("Loading Error"));
3690 msg.set_position (Gtk::WIN_POS_CENTER);
3691 pop_back_splash (msg);
3703 MessageDialog msg (string_compose(
3704 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3710 msg.set_title (_("Loading Error"));
3711 msg.set_position (Gtk::WIN_POS_CENTER);
3712 pop_back_splash (msg);
3724 list<string> const u = new_session->unknown_processors ();
3726 MissingPluginDialog d (_session, u);
3731 if (!new_session->writable()) {
3732 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3737 msg.set_title (_("Read-only Session"));
3738 msg.set_position (Gtk::WIN_POS_CENTER);
3739 pop_back_splash (msg);
3746 /* Now the session been created, add the transport controls */
3747 new_session->add_controllable(roll_controllable);
3748 new_session->add_controllable(stop_controllable);
3749 new_session->add_controllable(goto_start_controllable);
3750 new_session->add_controllable(goto_end_controllable);
3751 new_session->add_controllable(auto_loop_controllable);
3752 new_session->add_controllable(play_selection_controllable);
3753 new_session->add_controllable(rec_controllable);
3755 set_session (new_session);
3757 session_loaded = true;
3760 _session->set_clean ();
3763 #ifdef WINDOWS_VST_SUPPORT
3764 fst_stop_threading();
3768 Timers::TimerSuspender t;
3772 #ifdef WINDOWS_VST_SUPPORT
3773 fst_start_threading();
3782 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3784 Session *new_session;
3787 session_loaded = false;
3788 x = unload_session ();
3796 _session_is_new = true;
3799 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3802 catch (SessionException e) {
3803 cerr << "Here are the errors associated with this failed session:\n";
3805 cerr << "---------\n";
3806 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3807 msg.set_title (_("Loading Error"));
3808 msg.set_position (Gtk::WIN_POS_CENTER);
3809 pop_back_splash (msg);
3814 cerr << "Here are the errors associated with this failed session:\n";
3816 cerr << "---------\n";
3817 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3818 msg.set_title (_("Loading Error"));
3819 msg.set_position (Gtk::WIN_POS_CENTER);
3820 pop_back_splash (msg);
3825 /* Give the new session the default GUI state, if such things exist */
3828 n = Config->instant_xml (X_("Editor"));
3830 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3831 new_session->add_instant_xml (*n, false);
3833 n = Config->instant_xml (X_("Mixer"));
3835 new_session->add_instant_xml (*n, false);
3838 n = Config->instant_xml (X_("Preferences"));
3840 new_session->add_instant_xml (*n, false);
3843 /* Put the playhead at 0 and scroll fully left */
3844 n = new_session->instant_xml (X_("Editor"));
3846 n->set_property (X_("playhead"), X_("0"));
3847 n->set_property (X_("left-frame"), X_("0"));
3850 set_session (new_session);
3852 session_loaded = true;
3854 new_session->save_state(new_session->name());
3860 ARDOUR_UI::launch_chat ()
3862 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3864 dialog.set_title (_("About the Chat"));
3865 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."));
3867 switch (dialog.run()) {
3870 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3871 #elif defined PLATFORM_WINDOWS
3872 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3874 open_uri("http://webchat.freenode.net/?channels=ardour");
3883 ARDOUR_UI::launch_manual ()
3885 PBD::open_uri (Config->get_tutorial_manual_url());
3889 ARDOUR_UI::launch_reference ()
3891 PBD::open_uri (Config->get_reference_manual_url());
3895 ARDOUR_UI::launch_tracker ()
3897 PBD::open_uri ("http://tracker.ardour.org");
3901 ARDOUR_UI::launch_subscribe ()
3903 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3907 ARDOUR_UI::launch_cheat_sheet ()
3910 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3912 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3917 ARDOUR_UI::launch_website ()
3919 PBD::open_uri ("http://ardour.org");
3923 ARDOUR_UI::launch_website_dev ()
3925 PBD::open_uri ("http://ardour.org/development.html");
3929 ARDOUR_UI::launch_forums ()
3931 PBD::open_uri ("https://community.ardour.org/forums");
3935 ARDOUR_UI::launch_howto_report ()
3937 PBD::open_uri ("http://ardour.org/reporting_bugs");
3941 ARDOUR_UI::loading_message (const std::string& msg)
3943 if (ARDOUR_COMMAND_LINE::no_splash) {
3951 splash->message (msg);
3955 ARDOUR_UI::show_splash ()
3959 splash = new Splash;
3969 ARDOUR_UI::hide_splash ()
3976 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3980 removed = rep.paths.size();
3983 MessageDialog msgd (_main_window,
3984 _("No files were ready for clean-up"),
3988 msgd.set_title (_("Clean-up"));
3989 msgd.set_secondary_text (_("If this seems surprising, \n\
3990 check for any existing snapshots.\n\
3991 These may still include regions that\n\
3992 require some unused files to continue to exist."));
3998 ArdourDialog results (_("Clean-up"), true, false);
4000 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4001 CleanupResultsModelColumns() {
4005 Gtk::TreeModelColumn<std::string> visible_name;
4006 Gtk::TreeModelColumn<std::string> fullpath;
4010 CleanupResultsModelColumns results_columns;
4011 Glib::RefPtr<Gtk::ListStore> results_model;
4012 Gtk::TreeView results_display;
4014 results_model = ListStore::create (results_columns);
4015 results_display.set_model (results_model);
4016 results_display.append_column (list_title, results_columns.visible_name);
4018 results_display.set_name ("CleanupResultsList");
4019 results_display.set_headers_visible (true);
4020 results_display.set_headers_clickable (false);
4021 results_display.set_reorderable (false);
4023 Gtk::ScrolledWindow list_scroller;
4026 Gtk::HBox dhbox; // the hbox for the image and text
4027 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4028 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4030 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4032 const string dead_directory = _session->session_directory().dead_path();
4035 %1 - number of files removed
4036 %2 - location of "dead"
4037 %3 - size of files affected
4038 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4041 const char* bprefix;
4042 double space_adjusted = 0;
4044 if (rep.space < 1000) {
4046 space_adjusted = rep.space;
4047 } else if (rep.space < 1000000) {
4048 bprefix = _("kilo");
4049 space_adjusted = floorf((float)rep.space / 1000.0);
4050 } else if (rep.space < 1000000 * 1000) {
4051 bprefix = _("mega");
4052 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4054 bprefix = _("giga");
4055 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4059 txt.set_markup (string_compose (P_("\
4060 The following file was deleted from %2,\n\
4061 releasing %3 %4bytes of disk space", "\
4062 The following %1 files were deleted from %2,\n\
4063 releasing %3 %4bytes of disk space", removed),
4064 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4066 txt.set_markup (string_compose (P_("\
4067 The following file was not in use and \n\
4068 has been moved to: %2\n\n\
4069 After a restart of %5\n\n\
4070 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4071 will release an additional %3 %4bytes of disk space.\n", "\
4072 The following %1 files were not in use and \n\
4073 have been moved to: %2\n\n\
4074 After a restart of %5\n\n\
4075 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4076 will release an additional %3 %4bytes of disk space.\n", removed),
4077 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4080 dhbox.pack_start (*dimage, true, false, 5);
4081 dhbox.pack_start (txt, true, false, 5);
4083 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4084 TreeModel::Row row = *(results_model->append());
4085 row[results_columns.visible_name] = *i;
4086 row[results_columns.fullpath] = *i;
4089 list_scroller.add (results_display);
4090 list_scroller.set_size_request (-1, 150);
4091 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4093 dvbox.pack_start (dhbox, true, false, 5);
4094 dvbox.pack_start (list_scroller, true, false, 5);
4095 ddhbox.pack_start (dvbox, true, false, 5);
4097 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4098 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4099 results.set_default_response (RESPONSE_CLOSE);
4100 results.set_position (Gtk::WIN_POS_MOUSE);
4102 results_display.show();
4103 list_scroller.show();
4110 //results.get_vbox()->show();
4111 results.set_resizable (false);
4118 ARDOUR_UI::cleanup ()
4120 if (_session == 0) {
4121 /* shouldn't happen: menu item is insensitive */
4126 MessageDialog checker (_("Are you sure you want to clean-up?"),
4128 Gtk::MESSAGE_QUESTION,
4131 checker.set_title (_("Clean-up"));
4133 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4134 ALL undo/redo information will be lost if you clean-up.\n\
4135 Clean-up will move all unused files to a \"dead\" location."));
4137 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4138 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4139 checker.set_default_response (RESPONSE_CANCEL);
4141 checker.set_name (_("CleanupDialog"));
4142 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4143 checker.set_position (Gtk::WIN_POS_MOUSE);
4145 switch (checker.run()) {
4146 case RESPONSE_ACCEPT:
4152 ARDOUR::CleanupReport rep;
4154 editor->prepare_for_cleanup ();
4156 /* do not allow flush until a session is reloaded */
4158 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4160 act->set_sensitive (false);
4163 if (_session->cleanup_sources (rep)) {
4164 editor->finish_cleanup ();
4168 editor->finish_cleanup ();
4171 display_cleanup_results (rep, _("Cleaned Files"), false);
4175 ARDOUR_UI::flush_trash ()
4177 if (_session == 0) {
4178 /* shouldn't happen: menu item is insensitive */
4182 ARDOUR::CleanupReport rep;
4184 if (_session->cleanup_trash_sources (rep)) {
4188 display_cleanup_results (rep, _("deleted file"), true);
4192 ARDOUR_UI::cleanup_peakfiles ()
4194 if (_session == 0) {
4195 /* shouldn't happen: menu item is insensitive */
4199 if (! _session->can_cleanup_peakfiles ()) {
4203 // get all region-views in this session
4205 TrackViewList empty;
4207 editor->get_regions_after(rs, (framepos_t) 0, empty);
4208 std::list<RegionView*> views = rs.by_layer();
4210 // remove displayed audio-region-views waveforms
4211 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4212 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4213 if (!arv) { continue ; }
4214 arv->delete_waves();
4217 // cleanup peak files:
4218 // - stop pending peakfile threads
4219 // - close peakfiles if any
4220 // - remove peak dir in session
4221 // - setup peakfiles (background thread)
4222 _session->cleanup_peakfiles ();
4224 // re-add waves to ARV
4225 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4226 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4227 if (!arv) { continue ; }
4228 arv->create_waves();
4232 PresentationInfo::order_t
4233 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4235 if (editor->get_selection().tracks.empty()) {
4236 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4239 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4242 we want the new routes to have their order keys set starting from
4243 the highest order key in the selection + 1 (if available).
4246 if (place == RouteDialogs::AfterSelection) {
4247 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4249 order_hint = rtav->route()->presentation_info().order();
4252 } else if (place == RouteDialogs::BeforeSelection) {
4253 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4255 order_hint = rtav->route()->presentation_info().order();
4257 } else if (place == RouteDialogs::First) {
4260 /* leave order_hint at max_order */
4267 ARDOUR_UI::start_duplicate_routes ()
4269 if (!duplicate_routes_dialog) {
4270 duplicate_routes_dialog = new DuplicateRouteDialog;
4273 if (duplicate_routes_dialog->restart (_session)) {
4277 duplicate_routes_dialog->present ();
4281 ARDOUR_UI::add_route ()
4283 if (!add_route_dialog.get (false)) {
4284 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4291 if (add_route_dialog->is_visible()) {
4292 /* we're already doing this */
4296 add_route_dialog->set_position (WIN_POS_MOUSE);
4297 add_route_dialog->present();
4301 ARDOUR_UI::add_route_dialog_response (int r)
4306 case AddRouteDialog::Add:
4308 case AddRouteDialog::AddAndClose:
4309 add_route_dialog->ArdourDialog::on_response (r);
4312 add_route_dialog->ArdourDialog::on_response (r);
4316 if ((count = add_route_dialog->count()) <= 0) {
4320 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4321 string template_path = add_route_dialog->track_template();
4322 DisplaySuspender ds;
4324 if (!template_path.empty()) {
4325 if (add_route_dialog->name_template_is_default()) {
4326 _session->new_route_from_template (count, order, template_path, string());
4328 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4333 ChanCount input_chan= add_route_dialog->channels ();
4334 ChanCount output_chan;
4335 string name_template = add_route_dialog->name_template ();
4336 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4337 RouteGroup* route_group = add_route_dialog->route_group ();
4338 AutoConnectOption oac = Config->get_output_auto_connect();
4339 bool strict_io = add_route_dialog->use_strict_io ();
4341 if (oac & AutoConnectMaster) {
4342 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4343 output_chan.set (DataType::MIDI, 0);
4345 output_chan = input_chan;
4348 /* XXX do something with name template */
4350 Session::ProcessorChangeBlocker pcb (_session);
4352 switch (add_route_dialog->type_wanted()) {
4353 case AddRouteDialog::AudioTrack:
4354 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4356 case AddRouteDialog::MidiTrack:
4357 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4359 case AddRouteDialog::MixedTrack:
4360 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4362 case AddRouteDialog::AudioBus:
4363 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4365 case AddRouteDialog::MidiBus:
4366 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4368 case AddRouteDialog::VCAMaster:
4369 session_add_vca (name_template, count);
4375 ARDOUR_UI::stop_video_server (bool ask_confirm)
4377 if (!video_server_process && ask_confirm) {
4378 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4380 if (video_server_process) {
4382 ArdourDialog confirm (_("Stop Video-Server"), true);
4383 Label m (_("Do you really want to stop the Video Server?"));
4384 confirm.get_vbox()->pack_start (m, true, true);
4385 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4386 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4387 confirm.show_all ();
4388 if (confirm.run() == RESPONSE_CANCEL) {
4392 delete video_server_process;
4393 video_server_process =0;
4398 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4400 ARDOUR_UI::start_video_server( float_window, true);
4404 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4410 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4411 if (video_server_process) {
4412 popup_error(_("The Video Server is already started."));
4414 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4420 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4422 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4424 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4426 video_server_dialog->set_transient_for (*float_window);
4429 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4430 video_server_dialog->hide();
4432 ResponseType r = (ResponseType) video_server_dialog->run ();
4433 video_server_dialog->hide();
4434 if (r != RESPONSE_ACCEPT) { return false; }
4435 if (video_server_dialog->show_again()) {
4436 Config->set_show_video_server_dialog(false);
4440 std::string icsd_exec = video_server_dialog->get_exec_path();
4441 std::string icsd_docroot = video_server_dialog->get_docroot();
4442 #ifndef PLATFORM_WINDOWS
4443 if (icsd_docroot.empty()) {
4444 icsd_docroot = VideoUtils::video_get_docroot (Config);
4449 #ifdef PLATFORM_WINDOWS
4450 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4451 /* OK, allow all drive letters */
4454 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4455 warning << _("Specified docroot is not an existing directory.") << endmsg;
4458 #ifndef PLATFORM_WINDOWS
4459 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4460 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4461 warning << _("Given Video Server is not an executable file.") << endmsg;
4465 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4466 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4467 warning << _("Given Video Server is not an executable file.") << endmsg;
4473 argp=(char**) calloc(9,sizeof(char*));
4474 argp[0] = strdup(icsd_exec.c_str());
4475 argp[1] = strdup("-P");
4476 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4477 argp[3] = strdup("-p");
4478 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4479 argp[5] = strdup("-C");
4480 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4481 argp[7] = strdup(icsd_docroot.c_str());
4483 stop_video_server();
4485 #ifdef PLATFORM_WINDOWS
4486 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4487 /* OK, allow all drive letters */
4490 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4491 Config->set_video_advanced_setup(false);
4493 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4494 Config->set_video_server_url(url_str);
4495 Config->set_video_server_docroot(icsd_docroot);
4496 Config->set_video_advanced_setup(true);
4499 if (video_server_process) {
4500 delete video_server_process;
4503 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4504 if (video_server_process->start()) {
4505 warning << _("Cannot launch the video-server") << endmsg;
4508 int timeout = 120; // 6 sec
4509 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4510 Glib::usleep (50000);
4512 if (--timeout <= 0 || !video_server_process->is_running()) break;
4515 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4517 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4518 delete video_server_process;
4519 video_server_process = 0;
4527 ARDOUR_UI::add_video (Gtk::Window* float_window)
4533 if (!start_video_server(float_window, false)) {
4534 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4539 add_video_dialog->set_transient_for (*float_window);
4542 if (add_video_dialog->is_visible()) {
4543 /* we're already doing this */
4547 ResponseType r = (ResponseType) add_video_dialog->run ();
4548 add_video_dialog->hide();
4549 if (r != RESPONSE_ACCEPT) { return; }
4551 bool local_file, orig_local_file;
4552 std::string path = add_video_dialog->file_name(local_file);
4554 std::string orig_path = path;
4555 orig_local_file = local_file;
4557 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4559 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4560 warning << string_compose(_("could not open %1"), path) << endmsg;
4563 if (!local_file && path.length() == 0) {
4564 warning << _("no video-file selected") << endmsg;
4568 std::string audio_from_video;
4569 bool detect_ltc = false;
4571 switch (add_video_dialog->import_option()) {
4572 case VTL_IMPORT_TRANSCODE:
4574 TranscodeVideoDialog *transcode_video_dialog;
4575 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4576 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4577 transcode_video_dialog->hide();
4578 if (r != RESPONSE_ACCEPT) {
4579 delete transcode_video_dialog;
4583 audio_from_video = transcode_video_dialog->get_audiofile();
4585 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4588 else if (!audio_from_video.empty()) {
4589 editor->embed_audio_from_video(
4591 video_timeline->get_offset(),
4592 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4595 switch (transcode_video_dialog->import_option()) {
4596 case VTL_IMPORT_TRANSCODED:
4597 path = transcode_video_dialog->get_filename();
4600 case VTL_IMPORT_REFERENCE:
4603 delete transcode_video_dialog;
4606 delete transcode_video_dialog;
4610 case VTL_IMPORT_NONE:
4614 /* strip _session->session_directory().video_path() from video file if possible */
4615 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4616 path=path.substr(_session->session_directory().video_path().size());
4617 if (path.at(0) == G_DIR_SEPARATOR) {
4618 path=path.substr(1);
4622 video_timeline->set_update_session_fps(auto_set_session_fps);
4624 if (video_timeline->video_file_info(path, local_file)) {
4625 XMLNode* node = new XMLNode(X_("Videotimeline"));
4626 node->set_property (X_("Filename"), path);
4627 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4628 node->set_property (X_("LocalFile"), local_file);
4629 if (orig_local_file) {
4630 node->set_property (X_("OriginalVideoFile"), orig_path);
4632 node->remove_property (X_("OriginalVideoFile"));
4634 _session->add_extra_xml (*node);
4635 _session->set_dirty ();
4637 if (!audio_from_video.empty() && detect_ltc) {
4638 std::vector<LTCFileReader::LTCMap> ltc_seq;
4641 /* TODO ask user about TV standard (LTC alignment if any) */
4642 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4643 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4645 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4647 /* TODO seek near end of file, and read LTC until end.
4648 * if it fails to find any LTC frames, scan complete file
4650 * calculate drift of LTC compared to video-duration,
4651 * ask user for reference (timecode from start/mid/end)
4654 // LTCFileReader will have written error messages
4657 ::g_unlink(audio_from_video.c_str());
4659 if (ltc_seq.size() == 0) {
4660 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4662 /* the very first TC in the file is somteimes not aligned properly */
4663 int i = ltc_seq.size() -1;
4664 ARDOUR::frameoffset_t video_start_offset =
4665 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4666 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4667 video_timeline->set_offset(video_start_offset);
4671 _session->maybe_update_session_range(
4672 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4673 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4676 if (add_video_dialog->launch_xjadeo() && local_file) {
4677 editor->set_xjadeo_sensitive(true);
4678 editor->toggle_xjadeo_proc(1);
4680 editor->toggle_xjadeo_proc(0);
4682 editor->toggle_ruler_video(true);
4687 ARDOUR_UI::remove_video ()
4689 video_timeline->close_session();
4690 editor->toggle_ruler_video(false);
4693 video_timeline->set_offset_locked(false);
4694 video_timeline->set_offset(0);
4696 /* delete session state */
4697 XMLNode* node = new XMLNode(X_("Videotimeline"));
4698 _session->add_extra_xml(*node);
4699 node = new XMLNode(X_("Videomonitor"));
4700 _session->add_extra_xml(*node);
4701 node = new XMLNode(X_("Videoexport"));
4702 _session->add_extra_xml(*node);
4703 stop_video_server();
4707 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4709 if (localcacheonly) {
4710 video_timeline->vmon_update();
4712 video_timeline->flush_cache();
4714 editor->queue_visual_videotimeline_update();
4718 ARDOUR_UI::export_video (bool range)
4720 if (ARDOUR::Config->get_show_video_export_info()) {
4721 ExportVideoInfobox infobox (_session);
4722 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4723 if (infobox.show_again()) {
4724 ARDOUR::Config->set_show_video_export_info(false);
4727 case GTK_RESPONSE_YES:
4728 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4734 export_video_dialog->set_session (_session);
4735 export_video_dialog->apply_state(editor->get_selection().time, range);
4736 export_video_dialog->run ();
4737 export_video_dialog->hide ();
4741 ARDOUR_UI::preferences_settings () const
4746 node = _session->instant_xml(X_("Preferences"));
4748 node = Config->instant_xml(X_("Preferences"));
4752 node = new XMLNode (X_("Preferences"));
4759 ARDOUR_UI::mixer_settings () const
4764 node = _session->instant_xml(X_("Mixer"));
4766 node = Config->instant_xml(X_("Mixer"));
4770 node = new XMLNode (X_("Mixer"));
4777 ARDOUR_UI::main_window_settings () const
4782 node = _session->instant_xml(X_("Main"));
4784 node = Config->instant_xml(X_("Main"));
4788 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4789 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4794 node = new XMLNode (X_("Main"));
4801 ARDOUR_UI::editor_settings () const
4806 node = _session->instant_xml(X_("Editor"));
4808 node = Config->instant_xml(X_("Editor"));
4812 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4813 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4818 node = new XMLNode (X_("Editor"));
4825 ARDOUR_UI::keyboard_settings () const
4829 node = Config->extra_xml(X_("Keyboard"));
4832 node = new XMLNode (X_("Keyboard"));
4839 ARDOUR_UI::create_xrun_marker (framepos_t where)
4842 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4843 _session->locations()->add (location);
4848 ARDOUR_UI::halt_on_xrun_message ()
4850 cerr << "HALT on xrun\n";
4851 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4856 ARDOUR_UI::xrun_handler (framepos_t where)
4862 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4864 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4865 create_xrun_marker(where);
4868 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4869 halt_on_xrun_message ();
4874 ARDOUR_UI::disk_overrun_handler ()
4876 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4878 if (!have_disk_speed_dialog_displayed) {
4879 have_disk_speed_dialog_displayed = true;
4880 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4881 The disk system on your computer\n\
4882 was not able to keep up with %1.\n\
4884 Specifically, it failed to write data to disk\n\
4885 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4886 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4892 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4893 static MessageDialog *scan_dlg = NULL;
4894 static ProgressBar *scan_pbar = NULL;
4895 static HBox *scan_tbox = NULL;
4896 static Gtk::Button *scan_timeout_button;
4899 ARDOUR_UI::cancel_plugin_scan ()
4901 PluginManager::instance().cancel_plugin_scan();
4905 ARDOUR_UI::cancel_plugin_timeout ()
4907 PluginManager::instance().cancel_plugin_timeout();
4908 scan_timeout_button->set_sensitive (false);
4912 ARDOUR_UI::plugin_scan_timeout (int timeout)
4914 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4918 scan_pbar->set_sensitive (false);
4919 scan_timeout_button->set_sensitive (true);
4920 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4923 scan_pbar->set_sensitive (false);
4924 scan_timeout_button->set_sensitive (false);
4930 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4932 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4936 const bool cancelled = PluginManager::instance().cancelled();
4937 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4938 if (cancelled && scan_dlg->is_mapped()) {
4943 if (cancelled || !can_cancel) {
4948 static Gtk::Button *cancel_button;
4950 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4951 VBox* vbox = scan_dlg->get_vbox();
4952 vbox->set_size_request(400,-1);
4953 scan_dlg->set_title (_("Scanning for plugins"));
4955 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4956 cancel_button->set_name ("EditorGTKButton");
4957 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4958 cancel_button->show();
4960 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4962 scan_tbox = manage( new HBox() );
4964 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4965 scan_timeout_button->set_name ("EditorGTKButton");
4966 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4967 scan_timeout_button->show();
4969 scan_pbar = manage(new ProgressBar());
4970 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4971 scan_pbar->set_text(_("Scan Timeout"));
4974 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4975 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4977 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4980 assert(scan_dlg && scan_tbox && cancel_button);
4982 if (type == X_("closeme")) {
4986 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4989 if (!can_cancel || !cancelled) {
4990 scan_timeout_button->set_sensitive(false);
4992 cancel_button->set_sensitive(can_cancel && !cancelled);
4998 ARDOUR_UI::gui_idle_handler ()
5001 /* due to idle calls, gtk_events_pending() may always return true */
5002 while (gtk_events_pending() && --timeout) {
5003 gtk_main_iteration ();
5008 ARDOUR_UI::disk_underrun_handler ()
5010 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5012 if (!have_disk_speed_dialog_displayed) {
5013 have_disk_speed_dialog_displayed = true;
5014 MessageDialog* msg = new MessageDialog (
5015 _main_window, string_compose (_("The disk system on your computer\n\
5016 was not able to keep up with %1.\n\
5018 Specifically, it failed to read data from disk\n\
5019 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5020 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5026 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5028 have_disk_speed_dialog_displayed = false;
5033 ARDOUR_UI::session_dialog (std::string msg)
5035 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5039 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5046 ARDOUR_UI::pending_state_dialog ()
5048 HBox* hbox = manage (new HBox());
5049 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5050 ArdourDialog dialog (_("Crash Recovery"), true);
5051 Label message (string_compose (_("\
5052 This session appears to have been in the\n\
5053 middle of recording when %1 or\n\
5054 the computer was shutdown.\n\
5056 %1 can recover any captured audio for\n\
5057 you, or it can ignore it. Please decide\n\
5058 what you would like to do.\n"), PROGRAM_NAME));
5059 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5060 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5061 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5062 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5063 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5064 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5065 dialog.set_default_response (RESPONSE_ACCEPT);
5066 dialog.set_position (WIN_POS_CENTER);
5071 switch (dialog.run ()) {
5072 case RESPONSE_ACCEPT:
5080 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5082 HBox* hbox = new HBox();
5083 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5084 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5085 Label message (string_compose (_("\
5086 This session was created with a sample rate of %1 Hz, but\n\
5087 %2 is currently running at %3 Hz. If you load this session,\n\
5088 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5090 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5091 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5092 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5093 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5094 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5095 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5096 dialog.set_default_response (RESPONSE_ACCEPT);
5097 dialog.set_position (WIN_POS_CENTER);
5102 switch (dialog.run()) {
5103 case RESPONSE_ACCEPT:
5113 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5115 MessageDialog msg (string_compose (_("\
5116 This session was created with a sample rate of %1 Hz, but\n\
5117 %2 is currently running at %3 Hz.\n\
5118 Audio will be recorded and played at the wrong sample rate.\n\
5119 Re-Configure the Audio Engine in\n\
5120 Menu > Window > Audio/Midi Setup"),
5121 desired, PROGRAM_NAME, actual),
5123 Gtk::MESSAGE_WARNING);
5128 ARDOUR_UI::use_config ()
5130 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5132 set_transport_controllable_state (*node);
5137 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5139 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5140 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5142 primary_clock->set (pos);
5145 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5146 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5148 secondary_clock->set (pos);
5151 if (big_clock_window) {
5152 big_clock->set (pos);
5154 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5158 ARDOUR_UI::step_edit_status_change (bool yn)
5160 // XXX should really store pre-step edit status of things
5161 // we make insensitive
5164 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5165 rec_button.set_sensitive (false);
5167 rec_button.unset_active_state ();;
5168 rec_button.set_sensitive (true);
5173 ARDOUR_UI::record_state_changed ()
5175 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5178 /* why bother - the clock isn't visible */
5182 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5184 if (big_clock_window) {
5185 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5186 big_clock->set_active (true);
5188 big_clock->set_active (false);
5195 ARDOUR_UI::first_idle ()
5198 _session->allow_auto_play (true);
5202 editor->first_idle();
5205 Keyboard::set_can_save_keybindings (true);
5210 ARDOUR_UI::store_clock_modes ()
5212 XMLNode* node = new XMLNode(X_("ClockModes"));
5214 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5215 XMLNode* child = new XMLNode (X_("Clock"));
5217 child->set_property (X_("name"), (*x)->name());
5218 child->set_property (X_("mode"), (*x)->mode());
5219 child->set_property (X_("on"), (*x)->on());
5221 node->add_child_nocopy (*child);
5224 _session->add_extra_xml (*node);
5225 _session->set_dirty ();
5228 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5229 : Controllable (name), ui (u), type(tp)
5235 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5238 /* do nothing: these are radio-style actions */
5242 const char *action = 0;
5246 action = X_("Roll");
5249 action = X_("Stop");
5252 action = X_("GotoStart");
5255 action = X_("GotoEnd");
5258 action = X_("Loop");
5261 action = X_("PlaySelection");
5264 action = X_("Record");
5274 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5282 ARDOUR_UI::TransportControllable::get_value (void) const
5309 ARDOUR_UI::setup_profile ()
5311 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5312 Profile->set_small_screen ();
5315 if (g_getenv ("TRX")) {
5316 Profile->set_trx ();
5319 if (g_getenv ("MIXBUS")) {
5320 Profile->set_mixbus ();
5325 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5327 MissingFileDialog dialog (s, str, type);
5332 int result = dialog.run ();
5339 return 1; // quit entire session load
5342 result = dialog.get_action ();
5348 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5350 AmbiguousFileDialog dialog (file, hits);
5357 return dialog.get_which ();
5360 /** Allocate our thread-local buffers */
5362 ARDOUR_UI::get_process_buffers ()
5364 _process_thread->get_buffers ();
5367 /** Drop our thread-local buffers */
5369 ARDOUR_UI::drop_process_buffers ()
5371 _process_thread->drop_buffers ();
5375 ARDOUR_UI::feedback_detected ()
5377 _feedback_exists = true;
5381 ARDOUR_UI::successful_graph_sort ()
5383 _feedback_exists = false;
5387 ARDOUR_UI::midi_panic ()
5390 _session->midi_panic();
5395 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5397 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5398 const char* end_big = "</span>";
5399 const char* start_mono = "<tt>";
5400 const char* end_mono = "</tt>";
5402 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5403 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5404 "From now on, use the backup copy with older versions of %3"),
5405 xml_path, backup_path, PROGRAM_NAME,
5407 start_mono, end_mono), true);
5413 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5415 using namespace Menu_Helpers;
5417 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5418 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5419 i->set_active (editor_meter->meter_type () == type);
5423 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5425 using namespace Gtk::Menu_Helpers;
5427 Gtk::Menu* m = manage (new Menu);
5428 MenuList& items = m->items ();
5430 RadioMenuItem::Group group;
5432 _suspend_editor_meter_callbacks = true;
5433 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5434 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5435 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5436 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5437 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5438 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5439 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5440 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5441 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5442 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5443 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5445 m->popup (ev->button, ev->time);
5446 _suspend_editor_meter_callbacks = false;
5450 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5452 if (ev->button == 3 && editor_meter) {
5453 popup_editor_meter_menu (ev);
5460 ARDOUR_UI::reset_peak_display ()
5462 if (!_session || !_session->master_out() || !editor_meter) return;
5463 editor_meter->clear_meters();
5464 editor_meter_max_peak = -INFINITY;
5465 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5469 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5471 if (!_session || !_session->master_out()) return;
5472 if (group == _session->master_out()->route_group()) {
5473 reset_peak_display ();
5478 ARDOUR_UI::reset_route_peak_display (Route* route)
5480 if (!_session || !_session->master_out()) return;
5481 if (_session->master_out().get() == route) {
5482 reset_peak_display ();
5487 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5489 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5490 audio_midi_setup->set_position (WIN_POS_CENTER);
5492 if (desired_sample_rate != 0) {
5493 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5494 audio_midi_setup->try_autostart ();
5495 if (ARDOUR::AudioEngine::instance()->running()) {
5502 int response = audio_midi_setup->run();
5504 case Gtk::RESPONSE_DELETE_EVENT:
5505 // after latency callibration engine may run,
5506 // Running() signal was emitted, but dialog will not
5507 // have emitted a response. The user needs to close
5508 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5509 if (!AudioEngine::instance()->running()) {
5514 if (!AudioEngine::instance()->running()) {
5517 audio_midi_setup->hide ();
5525 ARDOUR_UI::transport_numpad_timeout ()
5527 _numpad_locate_happening = false;
5528 if (_numpad_timeout_connection.connected() )
5529 _numpad_timeout_connection.disconnect();
5534 ARDOUR_UI::transport_numpad_decimal ()
5536 _numpad_timeout_connection.disconnect();
5538 if (_numpad_locate_happening) {
5539 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5540 _numpad_locate_happening = false;
5542 _pending_locate_num = 0;
5543 _numpad_locate_happening = true;
5544 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5549 ARDOUR_UI::transport_numpad_event (int num)
5551 if ( _numpad_locate_happening ) {
5552 _pending_locate_num = _pending_locate_num*10 + num;
5555 case 0: toggle_roll(false, false); break;
5556 case 1: transport_rewind(1); break;
5557 case 2: transport_forward(1); break;
5558 case 3: transport_record(true); break;
5559 case 4: toggle_session_auto_loop(); break;
5560 case 5: transport_record(false); toggle_session_auto_loop(); break;
5561 case 6: toggle_punch(); break;
5562 case 7: toggle_click(); break;
5563 case 8: toggle_auto_return(); break;
5564 case 9: toggle_follow_edits(); break;
5570 ARDOUR_UI::set_flat_buttons ()
5572 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5576 ARDOUR_UI::audioengine_became_silent ()
5578 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5580 Gtk::MESSAGE_WARNING,
5584 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5586 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5587 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5588 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5589 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5590 Gtk::HBox pay_button_box;
5591 Gtk::HBox subscribe_button_box;
5593 pay_button_box.pack_start (pay_button, true, false);
5594 subscribe_button_box.pack_start (subscribe_button, true, false);
5596 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 */
5598 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5599 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5601 msg.get_vbox()->pack_start (pay_label);
5602 msg.get_vbox()->pack_start (pay_button_box);
5603 msg.get_vbox()->pack_start (subscribe_label);
5604 msg.get_vbox()->pack_start (subscribe_button_box);
5606 msg.get_vbox()->show_all ();
5608 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5609 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5610 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5615 case Gtk::RESPONSE_YES:
5616 AudioEngine::instance()->reset_silence_countdown ();
5619 case Gtk::RESPONSE_NO:
5621 save_state_canfail ("");
5625 case Gtk::RESPONSE_CANCEL:
5627 /* don't reset, save session and exit */
5633 ARDOUR_UI::hide_application ()
5635 Application::instance ()-> hide ();
5639 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5641 /* icons, titles, WM stuff */
5643 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5645 if (window_icons.empty()) {
5646 Glib::RefPtr<Gdk::Pixbuf> icon;
5647 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5648 window_icons.push_back (icon);
5650 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5651 window_icons.push_back (icon);
5653 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5654 window_icons.push_back (icon);
5656 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5657 window_icons.push_back (icon);
5661 if (!window_icons.empty()) {
5662 window.set_default_icon_list (window_icons);
5665 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5667 if (!name.empty()) {
5671 window.set_title (title.get_string());
5672 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5674 window.set_flags (CAN_FOCUS);
5675 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5677 /* This is a hack to ensure that GTK-accelerators continue to
5678 * work. Once we switch over to entirely native bindings, this will be
5679 * unnecessary and should be removed
5681 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5683 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5684 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5685 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5686 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5690 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5692 Gtkmm2ext::Bindings* bindings = 0;
5693 Gtk::Window* window = 0;
5695 /* until we get ardour bindings working, we are not handling key
5699 if (ev->type != GDK_KEY_PRESS) {
5703 if (event_window == &_main_window) {
5705 window = event_window;
5707 /* find current tab contents */
5709 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5711 /* see if it uses the ardour binding system */
5714 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5717 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5721 window = event_window;
5723 /* see if window uses ardour binding system */
5725 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5728 /* An empty binding set is treated as if it doesn't exist */
5730 if (bindings && bindings->empty()) {
5734 return key_press_focus_accelerator_handler (*window, ev, bindings);
5737 static Gtkmm2ext::Bindings*
5738 get_bindings_from_widget_heirarchy (GtkWidget** w)
5743 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5746 *w = gtk_widget_get_parent (*w);
5749 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5753 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5755 GtkWindow* win = window.gobj();
5756 GtkWidget* focus = gtk_window_get_focus (win);
5757 GtkWidget* binding_widget = focus;
5758 bool special_handling_of_unmodified_accelerators = false;
5759 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5763 /* some widget has keyboard focus */
5765 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5767 /* A particular kind of focusable widget currently has keyboard
5768 * focus. All unmodified key events should go to that widget
5769 * first and not be used as an accelerator by default
5772 special_handling_of_unmodified_accelerators = true;
5776 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5777 if (focus_bindings) {
5778 bindings = focus_bindings;
5779 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5784 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",
5787 Gtkmm2ext::show_gdk_event_state (ev->state),
5788 special_handling_of_unmodified_accelerators,
5789 Keyboard::some_magic_widget_has_focus(),
5791 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5792 ((ev->state & mask) ? "yes" : "no"),
5793 window.get_title()));
5795 /* This exists to allow us to override the way GTK handles
5796 key events. The normal sequence is:
5798 a) event is delivered to a GtkWindow
5799 b) accelerators/mnemonics are activated
5800 c) if (b) didn't handle the event, propagate to
5801 the focus widget and/or focus chain
5803 The problem with this is that if the accelerators include
5804 keys without modifiers, such as the space bar or the
5805 letter "e", then pressing the key while typing into
5806 a text entry widget results in the accelerator being
5807 activated, instead of the desired letter appearing
5810 There is no good way of fixing this, but this
5811 represents a compromise. The idea is that
5812 key events involving modifiers (not Shift)
5813 get routed into the activation pathway first, then
5814 get propagated to the focus widget if necessary.
5816 If the key event doesn't involve modifiers,
5817 we deliver to the focus widget first, thus allowing
5818 it to get "normal text" without interference
5821 Of course, this can also be problematic: if there
5822 is a widget with focus, then it will swallow
5823 all "normal text" accelerators.
5827 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5829 /* no special handling or there are modifiers in effect: accelerate first */
5831 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5832 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5833 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5835 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5836 KeyboardKey k (ev->state, ev->keyval);
5840 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5842 if (bindings->activate (k, Bindings::Press)) {
5843 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5847 if (binding_widget) {
5848 binding_widget = gtk_widget_get_parent (binding_widget);
5849 if (binding_widget) {
5850 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5859 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5861 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5862 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5866 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5868 if (gtk_window_propagate_key_event (win, ev)) {
5869 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5875 /* no modifiers, propagate first */
5877 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5879 if (gtk_window_propagate_key_event (win, ev)) {
5880 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5884 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5885 KeyboardKey k (ev->state, ev->keyval);
5889 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5892 if (bindings->activate (k, Bindings::Press)) {
5893 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5897 if (binding_widget) {
5898 binding_widget = gtk_widget_get_parent (binding_widget);
5899 if (binding_widget) {
5900 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5909 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5911 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5912 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5917 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5922 ARDOUR_UI::load_bindings ()
5924 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5925 error << _("Global keybindings are missing") << endmsg;
5930 ARDOUR_UI::cancel_solo ()
5933 _session->cancel_all_solo ();
5938 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5940 /* this resets focus to the first focusable parent of the given widget,
5941 * or, if there is no focusable parent, cancels focus in the toplevel
5942 * window that the given widget is packed into (if there is one).
5949 Gtk::Widget* top = w->get_toplevel();
5951 if (!top || !top->is_toplevel()) {
5955 w = w->get_parent ();
5959 if (w->is_toplevel()) {
5960 /* Setting the focus widget to a Gtk::Window causes all
5961 * subsequent calls to ::has_focus() on the nominal
5962 * focus widget in that window to return
5963 * false. Workaround: never set focus to the toplevel
5969 if (w->get_can_focus ()) {
5970 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5971 win->set_focus (*w);
5974 w = w->get_parent ();
5977 if (top == &_main_window) {
5981 /* no focusable parent found, cancel focus in top level window.
5982 C++ API cannot be used for this. Thanks, references.
5985 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);