2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/types_convert.h"
65 #include "pbd/file_utils.h"
66 #include "pbd/localtime_r.h"
67 #include "pbd/pthread_utils.h"
68 #include "pbd/replace_all.h"
69 #include "pbd/scoped_file_descriptor.h"
70 #include "pbd/xml++.h"
72 #include "gtkmm2ext/application.h"
73 #include "gtkmm2ext/bindings.h"
74 #include "gtkmm2ext/gtk_ui.h"
75 #include "gtkmm2ext/utils.h"
76 #include "gtkmm2ext/click_box.h"
77 #include "gtkmm2ext/fastmeter.h"
78 #include "gtkmm2ext/popup.h"
79 #include "gtkmm2ext/window_title.h"
81 #include "ardour/ardour.h"
82 #include "ardour/audio_backend.h"
83 #include "ardour/audio_track.h"
84 #include "ardour/audioengine.h"
85 #include "ardour/audiofilesource.h"
86 #include "ardour/automation_watch.h"
87 #include "ardour/diskstream.h"
88 #include "ardour/filename_extensions.h"
89 #include "ardour/filesystem_paths.h"
90 #include "ardour/ltc_file_reader.h"
91 #include "ardour/midi_track.h"
92 #include "ardour/port.h"
93 #include "ardour/plugin_manager.h"
94 #include "ardour/process_thread.h"
95 #include "ardour/profile.h"
96 #include "ardour/recent_sessions.h"
97 #include "ardour/record_enable_control.h"
98 #include "ardour/revision.h"
99 #include "ardour/session_directory.h"
100 #include "ardour/session_route.h"
101 #include "ardour/session_state_utils.h"
102 #include "ardour/session_utils.h"
103 #include "ardour/source_factory.h"
104 #include "ardour/slave.h"
105 #include "ardour/system_exec.h"
106 #include "ardour/track.h"
107 #include "ardour/vca_manager.h"
108 #include "ardour/utils.h"
110 #include "LuaBridge/LuaBridge.h"
112 #ifdef WINDOWS_VST_SUPPORT
115 #ifdef AUDIOUNIT_SUPPORT
116 #include "ardour/audio_unit.h"
119 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
124 #include "timecode/time.h"
126 typedef uint64_t microseconds_t;
130 #include "enums_convert.h"
132 #include "add_route_dialog.h"
133 #include "ambiguous_file_dialog.h"
134 #include "ardour_ui.h"
135 #include "audio_clock.h"
136 #include "audio_region_view.h"
137 #include "big_clock_window.h"
138 #include "bundle_manager.h"
139 #include "duplicate_routes_dialog.h"
141 #include "engine_dialog.h"
142 #include "export_video_dialog.h"
143 #include "export_video_infobox.h"
144 #include "gain_meter.h"
145 #include "global_port_matrix.h"
146 #include "gui_object.h"
147 #include "gui_thread.h"
148 #include "idleometer.h"
149 #include "keyboard.h"
150 #include "keyeditor.h"
151 #include "location_ui.h"
152 #include "lua_script_manager.h"
153 #include "luawindow.h"
154 #include "main_clock.h"
155 #include "missing_file_dialog.h"
156 #include "missing_plugin_dialog.h"
157 #include "mixer_ui.h"
158 #include "meterbridge.h"
159 #include "meter_patterns.h"
160 #include "mouse_cursors.h"
163 #include "pingback.h"
164 #include "processor_box.h"
165 #include "prompter.h"
166 #include "public_editor.h"
167 #include "rc_option_editor.h"
168 #include "route_time_axis.h"
169 #include "route_params_ui.h"
170 #include "save_as_dialog.h"
171 #include "script_selector.h"
172 #include "session_archive_dialog.h"
173 #include "session_dialog.h"
174 #include "session_metadata_dialog.h"
175 #include "session_option_editor.h"
176 #include "speaker_dialog.h"
179 #include "time_axis_view_item.h"
180 #include "time_info_box.h"
183 #include "utils_videotl.h"
184 #include "video_server_dialog.h"
185 #include "add_video_dialog.h"
186 #include "transcode_video_dialog.h"
188 #include "pbd/i18n.h"
190 using namespace ARDOUR;
191 using namespace ARDOUR_UI_UTILS;
193 using namespace Gtkmm2ext;
196 using namespace Editing;
198 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
200 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
201 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
204 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
206 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
207 "Would you like these files to be copied and used for %1 %2.x?\n\n"
208 "(This will require you to restart %1.)"),
209 PROGRAM_NAME, PROGRAM_VERSION, version),
210 false, /* no markup */
213 true /* modal, though it hardly matters since it is the only window */
216 msg.set_default_response (Gtk::RESPONSE_YES);
219 return (msg.run() == Gtk::RESPONSE_YES);
223 libxml_generic_error_func (void* /* parsing_context*/,
231 vsnprintf (buf, sizeof (buf), msg, ap);
232 error << buf << endmsg;
237 libxml_structured_error_func (void* /* parsing_context*/,
245 replace_all (msg, "\n", "");
248 if (err->file && err->line) {
249 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
252 error << ':' << err->int2;
257 error << X_("XML error: ") << msg << endmsg;
263 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
264 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
265 , session_loaded (false)
266 , gui_object_state (new GUIObjectState)
267 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
268 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
269 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
271 , global_actions (X_("global"))
272 , ignore_dual_punch (false)
273 , main_window_visibility (0)
278 , _mixer_on_top (false)
279 , _initial_verbose_plugin_scan (false)
280 , first_time_engine_run (true)
281 , secondary_clock_spacer (0)
282 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
283 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
284 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
285 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
286 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
287 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
288 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
289 , auto_input_button (ArdourButton::led_default_elements)
291 , auto_return_button (ArdourButton::led_default_elements)
292 , follow_edits_button (ArdourButton::led_default_elements)
293 , auditioning_alert_button (_("Audition"))
294 , solo_alert_button (_("Solo"))
295 , feedback_alert_button (_("Feedback"))
296 , error_alert_button ( ArdourButton::just_led_default_elements )
298 , editor_meter_peak_display()
299 , _suspend_editor_meter_callbacks (false)
300 , _numpad_locate_happening (false)
301 , _session_is_new (false)
302 , last_key_press_time (0)
306 , rc_option_editor (0)
307 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
308 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
309 , about (X_("about"), _("About"))
310 , location_ui (X_("locations"), S_("Ranges|Locations"))
311 , route_params (X_("inspector"), _("Tracks and Busses"))
312 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
313 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
314 , lua_script_window (X_("script-manager"), _("Script Manager"))
315 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
316 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
317 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
318 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
319 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
320 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
321 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
322 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
323 , video_server_process (0)
325 , have_configure_timeout (false)
326 , last_configure_time (0)
328 , have_disk_speed_dialog_displayed (false)
329 , _status_bar_visibility (X_("status-bar"))
330 , _feedback_exists (false)
331 , _log_not_acknowledged (LogLevelNone)
332 , duplicate_routes_dialog (0)
333 , editor_visibility_button (S_("Window|Editor"))
334 , mixer_visibility_button (S_("Window|Mixer"))
335 , prefs_visibility_button (S_("Window|Preferences"))
337 Gtkmm2ext::init (localedir);
339 UIConfiguration::instance().post_gui_init ();
341 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
343 /* "touch" the been-here-before path now that config has been migrated */
344 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
346 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
348 /* configuration was modified, exit immediately */
353 if (string (VERSIONSTRING).find (".pre") != string::npos) {
354 /* check this is not being run from ./ardev etc. */
355 if (!running_from_source_tree ()) {
356 pre_release_dialog ();
360 if (theArdourUI == 0) {
364 /* track main window visibility */
366 main_window_visibility = new VisibilityTracker (_main_window);
368 /* stop libxml from spewing to stdout/stderr */
370 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
371 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
373 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
374 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
375 UIConfiguration::instance().map_parameters (pc);
377 roll_button.set_controllable (roll_controllable);
378 stop_button.set_controllable (stop_controllable);
379 goto_start_button.set_controllable (goto_start_controllable);
380 goto_end_button.set_controllable (goto_end_controllable);
381 auto_loop_button.set_controllable (auto_loop_controllable);
382 play_selection_button.set_controllable (play_selection_controllable);
383 rec_button.set_controllable (rec_controllable);
385 roll_button.set_name ("transport button");
386 stop_button.set_name ("transport button");
387 goto_start_button.set_name ("transport button");
388 goto_end_button.set_name ("transport button");
389 auto_loop_button.set_name ("transport button");
390 play_selection_button.set_name ("transport button");
391 rec_button.set_name ("transport recenable button");
392 midi_panic_button.set_name ("transport button");
394 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
395 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
397 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
399 /* handle dialog requests */
401 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
403 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
405 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
407 /* handle Audio/MIDI setup when session requires it */
409 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
411 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
413 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
415 /* handle sr mismatch with a dialog - cross-thread from engine */
416 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
418 /* handle requests to quit (coming from JACK session) */
420 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
422 /* tell the user about feedback */
424 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
425 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
427 /* handle requests to deal with missing files */
429 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
431 /* and ambiguous files */
433 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
435 /* also plugin scan messages */
436 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
437 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
439 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
441 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
444 /* lets get this party started */
446 setup_gtk_ardour_enums ();
449 SessionEvent::create_per_thread_pool ("GUI", 4096);
451 /* we like keyboards */
453 keyboard = new ArdourKeyboard(*this);
455 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
457 keyboard->set_state (*node, Stateful::loading_state_version);
460 UIConfiguration::instance().reset_dpi ();
462 TimeAxisViewItem::set_constant_heights ();
464 /* Set this up so that our window proxies can register actions */
466 ActionManager::init ();
468 /* The following must happen after ARDOUR::init() so that Config is set up */
470 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
473 key_editor.set_state (*ui_xml, 0);
474 session_option_editor.set_state (*ui_xml, 0);
475 speaker_config_window.set_state (*ui_xml, 0);
476 about.set_state (*ui_xml, 0);
477 add_route_dialog.set_state (*ui_xml, 0);
478 add_video_dialog.set_state (*ui_xml, 0);
479 route_params.set_state (*ui_xml, 0);
480 bundle_manager.set_state (*ui_xml, 0);
481 location_ui.set_state (*ui_xml, 0);
482 big_clock_window.set_state (*ui_xml, 0);
483 audio_port_matrix.set_state (*ui_xml, 0);
484 midi_port_matrix.set_state (*ui_xml, 0);
485 export_video_dialog.set_state (*ui_xml, 0);
486 lua_script_window.set_state (*ui_xml, 0);
487 idleometer.set_state (*ui_xml, 0);
490 /* Separate windows */
492 WM::Manager::instance().register_window (&key_editor);
493 WM::Manager::instance().register_window (&session_option_editor);
494 WM::Manager::instance().register_window (&speaker_config_window);
495 WM::Manager::instance().register_window (&about);
496 WM::Manager::instance().register_window (&add_route_dialog);
497 WM::Manager::instance().register_window (&add_video_dialog);
498 WM::Manager::instance().register_window (&route_params);
499 WM::Manager::instance().register_window (&audio_midi_setup);
500 WM::Manager::instance().register_window (&export_video_dialog);
501 WM::Manager::instance().register_window (&lua_script_window);
502 WM::Manager::instance().register_window (&bundle_manager);
503 WM::Manager::instance().register_window (&location_ui);
504 WM::Manager::instance().register_window (&big_clock_window);
505 WM::Manager::instance().register_window (&audio_port_matrix);
506 WM::Manager::instance().register_window (&midi_port_matrix);
507 WM::Manager::instance().register_window (&idleometer);
509 /* do not retain position for add route dialog */
510 add_route_dialog.set_state_mask (WindowProxy::Size);
512 /* Trigger setting up the color scheme and loading the GTK RC file */
514 UIConfiguration::instance().load_rc_file (false);
516 _process_thread = new ProcessThread ();
517 _process_thread->init ();
519 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
525 ARDOUR_UI::pre_release_dialog ()
527 ArdourDialog d (_("Pre-Release Warning"), true, false);
528 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
530 Label* label = manage (new Label);
531 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
532 There are still several issues and bugs to be worked on,\n\
533 as well as general workflow improvements, before this can be considered\n\
534 release software. So, a few guidelines:\n\
536 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
537 though it may be so, depending on your workflow.\n\
538 2) Please wait for a helpful writeup of new features.\n\
539 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
540 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
541 making sure to note the product version number as 5.0-pre.\n\
542 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
543 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
544 can get there directly from within the program via the Help->Chat menu option.\n\
546 Full information on all the above can be found on the support page at\n\
548 http://ardour.org/support\n\
549 "), PROGRAM_NAME, VERSIONSTRING));
551 d.get_vbox()->set_border_width (12);
552 d.get_vbox()->pack_start (*label, false, false, 12);
553 d.get_vbox()->show_all ();
558 GlobalPortMatrixWindow*
559 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
564 return new GlobalPortMatrixWindow (_session, type);
568 ARDOUR_UI::attach_to_engine ()
570 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
571 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
575 ARDOUR_UI::engine_stopped ()
577 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
578 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
579 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
580 update_sample_rate (0);
585 ARDOUR_UI::engine_running ()
587 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
588 if (first_time_engine_run) {
590 first_time_engine_run = false;
594 _session->reset_xrun_count ();
596 update_disk_space ();
598 update_xrun_count ();
599 update_sample_rate (AudioEngine::instance()->sample_rate());
600 update_timecode_format ();
601 update_peak_thread_work ();
602 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
603 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
607 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
609 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
610 /* we can't rely on the original string continuing to exist when we are called
611 again in the GUI thread, so make a copy and note that we need to
614 char *copy = strdup (reason);
615 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
619 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
620 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
622 update_sample_rate (0);
626 /* if the reason is a non-empty string, it means that the backend was shutdown
627 rather than just Ardour.
630 if (strlen (reason)) {
631 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
633 msgstr = string_compose (_("\
634 The audio backend has either been shutdown or it\n\
635 disconnected %1 because %1\n\
636 was not fast enough. Try to restart\n\
637 the audio backend and save the session."), PROGRAM_NAME);
640 MessageDialog msg (_main_window, msgstr);
641 pop_back_splash (msg);
645 free (const_cast<char*> (reason));
650 ARDOUR_UI::post_engine ()
652 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
654 #ifdef AUDIOUNIT_SUPPORT
656 if (AUPluginInfo::au_get_crashlog(au_msg)) {
657 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
658 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
659 info << au_msg << endmsg;
663 ARDOUR::init_post_engine ();
665 /* connect to important signals */
667 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
668 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
669 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
670 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
671 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
673 if (setup_windows ()) {
674 throw failed_constructor ();
677 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
678 XMLNode* n = Config->extra_xml (X_("UI"));
680 _status_bar_visibility.set_state (*n);
683 check_memory_locking();
685 /* this is the first point at which all the possible actions are
686 * available, because some of the available actions are dependent on
687 * aspects of the engine/backend.
690 if (ARDOUR_COMMAND_LINE::show_key_actions) {
693 vector<string> paths;
694 vector<string> labels;
695 vector<string> tooltips;
697 vector<Glib::RefPtr<Gtk::Action> > actions;
698 string ver_in = revision;
699 string ver = ver_in.substr(0, ver_in.find("-"));
701 cout << "\n<h2>Menu actions</h2>" << endl;
702 cout << "<!-- created by running " << PROGRAM_NAME << " -b -->" << endl;
703 cout << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
704 cout << " surfaces or scripts.\n</p>\n" << endl;
705 cout << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
706 cout << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
707 cout << " time by running " << PROGRAM_NAME << " with the -b flag.\n</p>\n" << endl;
708 cout << "<table class=\"dl\">\n <thead>" << endl;
709 cout << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
710 cout << " </thead>\n <tbody>" << endl;
712 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
714 vector<string>::iterator p;
715 vector<string>::iterator l;
717 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
718 cout << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
719 cout << "</kbd></th><td>" << *l << "</td></tr>" << endl;
721 cout << " </tbody>\n </table class=\"dl\">" << endl;
723 halt_connection.disconnect ();
724 AudioEngine::instance()->stop ();
728 /* this being a GUI and all, we want peakfiles */
730 AudioFileSource::set_build_peakfiles (true);
731 AudioFileSource::set_build_missing_peakfiles (true);
733 /* set default clock modes */
735 primary_clock->set_mode (AudioClock::Timecode);
736 secondary_clock->set_mode (AudioClock::BBT);
738 /* start the time-of-day-clock */
741 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
742 update_wall_clock ();
743 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
748 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
749 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
750 Config->map_parameters (pc);
752 UIConfiguration::instance().map_parameters (pc);
756 ARDOUR_UI::~ARDOUR_UI ()
758 UIConfiguration::instance().save_state();
762 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
763 // don't bother at 'real' exit. the OS cleans up for us.
764 delete big_clock; big_clock = 0;
765 delete primary_clock; primary_clock = 0;
766 delete secondary_clock; secondary_clock = 0;
767 delete _process_thread; _process_thread = 0;
768 delete time_info_box; time_info_box = 0;
769 delete meterbridge; meterbridge = 0;
770 delete luawindow; luawindow = 0;
771 delete editor; editor = 0;
772 delete mixer; mixer = 0;
773 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
775 delete gui_object_state; gui_object_state = 0;
776 delete main_window_visibility;
777 FastMeter::flush_pattern_cache ();
778 PixFader::flush_pattern_cache ();
782 /* Small trick to flush main-thread event pool.
783 * Other thread-pools are destroyed at pthread_exit(),
784 * but tmain thread termination is too late to trigger Pool::~Pool()
786 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.
787 delete ev->event_pool();
792 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
794 if (Splash::instance()) {
795 Splash::instance()->pop_back_for (win);
800 ARDOUR_UI::configure_timeout ()
802 if (last_configure_time == 0) {
803 /* no configure events yet */
807 /* force a gap of 0.5 seconds since the last configure event
810 if (get_microseconds() - last_configure_time < 500000) {
813 have_configure_timeout = false;
814 save_ardour_state ();
820 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
822 if (have_configure_timeout) {
823 last_configure_time = get_microseconds();
825 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
826 have_configure_timeout = true;
833 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
837 if (node.get_property ("roll", str)){
838 roll_controllable->set_id (str);
840 if (node.get_property ("stop", str)) {
841 stop_controllable->set_id (str);
843 if (node.get_property ("goto-start", str)) {
844 goto_start_controllable->set_id (str);
846 if (node.get_property ("goto-end", str)) {
847 goto_end_controllable->set_id (str);
849 if (node.get_property ("auto-loop", str)) {
850 auto_loop_controllable->set_id (str);
852 if (node.get_property ("play-selection", str)) {
853 play_selection_controllable->set_id (str);
855 if (node.get_property ("rec", str)) {
856 rec_controllable->set_id (str);
858 if (node.get_property ("shuttle", str)) {
859 shuttle_box.controllable()->set_id (str);
864 ARDOUR_UI::get_transport_controllable_state ()
866 XMLNode* node = new XMLNode(X_("TransportControllables"));
868 node->set_property (X_("roll"), roll_controllable->id());
869 node->set_property (X_("stop"), stop_controllable->id());
870 node->set_property (X_("goto_start"), goto_start_controllable->id());
871 node->set_property (X_("goto_end"), goto_end_controllable->id());
872 node->set_property (X_("auto_loop"), auto_loop_controllable->id());
873 node->set_property (X_("play_selection"), play_selection_controllable->id());
874 node->set_property (X_("rec"), rec_controllable->id());
875 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
881 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
884 _session->save_state (snapshot_name);
889 ARDOUR_UI::autosave_session ()
891 if (g_main_depth() > 1) {
892 /* inside a recursive main loop,
893 give up because we may not be able to
899 if (!Config->get_periodic_safety_backups()) {
904 _session->maybe_write_autosave();
911 ARDOUR_UI::session_dirty_changed ()
918 ARDOUR_UI::update_autosave ()
920 if (_session && _session->dirty()) {
921 if (_autosave_connection.connected()) {
922 _autosave_connection.disconnect();
925 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
926 Config->get_periodic_safety_backup_interval() * 1000);
929 if (_autosave_connection.connected()) {
930 _autosave_connection.disconnect();
936 ARDOUR_UI::check_announcements ()
939 string _annc_filename;
942 _annc_filename = PROGRAM_NAME "_announcements_osx_";
943 #elif defined PLATFORM_WINDOWS
944 _annc_filename = PROGRAM_NAME "_announcements_windows_";
946 _annc_filename = PROGRAM_NAME "_announcements_linux_";
948 _annc_filename.append (VERSIONSTRING);
950 _announce_string = "";
952 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
953 FILE* fin = g_fopen (path.c_str(), "rb");
955 while (!feof (fin)) {
958 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
961 _announce_string.append (tmp, len);
966 pingback (VERSIONSTRING, path);
971 _hide_splash (gpointer arg)
973 ((ARDOUR_UI*)arg)->hide_splash();
978 ARDOUR_UI::starting ()
980 Application* app = Application::instance ();
982 bool brand_new_user = ArdourStartup::required ();
984 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
985 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
987 if (ARDOUR_COMMAND_LINE::check_announcements) {
988 check_announcements ();
993 /* we need to create this early because it may need to set the
994 * audio backend end up.
998 audio_midi_setup.get (true);
1000 std::cerr << "audio-midi engine setup failed."<< std::endl;
1004 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1005 nsm = new NSM_Client;
1006 if (!nsm->init (nsm_url)) {
1007 /* the ardour executable may have different names:
1009 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1010 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1011 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1013 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1015 const char *process_name = g_getenv ("ARDOUR_SELF");
1016 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1019 // wait for announce reply from nsm server
1020 for ( i = 0; i < 5000; ++i) {
1024 if (nsm->is_active()) {
1029 error << _("NSM server did not announce itself") << endmsg;
1032 // wait for open command from nsm server
1033 for ( i = 0; i < 5000; ++i) {
1035 Glib::usleep (1000);
1036 if (nsm->client_id ()) {
1042 error << _("NSM: no client ID provided") << endmsg;
1046 if (_session && nsm) {
1047 _session->set_nsm_state( nsm->is_active() );
1049 error << _("NSM: no session created") << endmsg;
1053 // nsm requires these actions disabled
1054 vector<string> action_names;
1055 action_names.push_back("SaveAs");
1056 action_names.push_back("Rename");
1057 action_names.push_back("New");
1058 action_names.push_back("Open");
1059 action_names.push_back("Recent");
1060 action_names.push_back("Close");
1062 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1063 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1065 act->set_sensitive (false);
1072 error << _("NSM: initialization failed") << endmsg;
1078 if (brand_new_user) {
1079 _initial_verbose_plugin_scan = true;
1084 _initial_verbose_plugin_scan = false;
1085 switch (s.response ()) {
1086 case Gtk::RESPONSE_OK:
1093 // TODO: maybe IFF brand_new_user
1094 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1095 std::string dspd (Config->get_default_session_parent_dir());
1096 Searchpath ds (ARDOUR::ardour_data_search_path());
1097 ds.add_subdirectory_to_paths ("sessions");
1098 vector<string> demos;
1099 find_files_matching_pattern (demos, ds, "*.tar.xz");
1101 ARDOUR::RecentSessions rs;
1102 ARDOUR::read_recent_sessions (rs);
1104 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1105 /* "demo-session" must be inside "demo-session.tar.xz"
1108 std::string name = basename_nosuffix (basename_nosuffix (*i));
1109 std::string path = Glib::build_filename (dspd, name);
1110 /* skip if session-dir already exists */
1111 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1114 /* skip sessions that are already in 'recent'.
1115 * eg. a new user changed <session-default-dir> shorly after installation
1117 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1118 if ((*r).first == name) {
1123 PBD::FileArchive ar (*i);
1124 if (0 == ar.inflate (dspd)) {
1125 store_recent_sessions (name, path);
1126 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1132 #ifdef NO_PLUGIN_STATE
1134 ARDOUR::RecentSessions rs;
1135 ARDOUR::read_recent_sessions (rs);
1137 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1139 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1141 /* already used Ardour, have sessions ... warn about plugin state */
1143 ArdourDialog d (_("Free/Demo Version Warning"), true);
1145 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1146 CheckButton c (_("Don't warn me about this again"));
1148 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"),
1149 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1150 _("It will not restore OR save any plugin settings"),
1151 _("If you load an existing session with plugin settings\n"
1152 "they will not be used and will be lost."),
1153 _("To get full access to updates without this limitation\n"
1154 "consider becoming a subscriber for a low cost every month.")));
1155 l.set_justify (JUSTIFY_CENTER);
1157 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1159 d.get_vbox()->pack_start (l, true, true);
1160 d.get_vbox()->pack_start (b, false, false, 12);
1161 d.get_vbox()->pack_start (c, false, false, 12);
1163 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1164 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1168 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1170 if (d.run () != RESPONSE_OK) {
1176 /* go get a session */
1178 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1180 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1181 std::cerr << "Cannot get session parameters."<< std::endl;
1188 WM::Manager::instance().show_visible ();
1190 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1191 * editor window, and we may want stuff to be hidden.
1193 _status_bar_visibility.update ();
1195 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1197 if (splash && splash->is_visible()) {
1198 // in 1 second, hide the splash screen
1199 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1202 /* all other dialogs are created conditionally */
1208 ARDOUR_UI::check_memory_locking ()
1210 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1211 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1215 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1217 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1219 struct rlimit limits;
1221 long pages, page_size;
1223 size_t pages_len=sizeof(pages);
1224 if ((page_size = getpagesize()) < 0 ||
1225 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1227 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1232 ram = (int64_t) pages * (int64_t) page_size;
1235 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1239 if (limits.rlim_cur != RLIM_INFINITY) {
1241 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1245 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1246 "This might cause %1 to run out of memory before your system "
1247 "runs out of memory. \n\n"
1248 "You can view the memory limit with 'ulimit -l', "
1249 "and it is normally controlled by %2"),
1252 X_("/etc/login.conf")
1254 X_(" /etc/security/limits.conf")
1258 msg.set_default_response (RESPONSE_OK);
1260 VBox* vbox = msg.get_vbox();
1262 CheckButton cb (_("Do not show this window again"));
1263 hbox.pack_start (cb, true, false);
1264 vbox->pack_start (hbox);
1269 pop_back_splash (msg);
1273 if (cb.get_active()) {
1274 XMLNode node (X_("no-memory-warning"));
1275 Config->add_instant_xml (node);
1280 #endif // !__APPLE__
1285 ARDOUR_UI::queue_finish ()
1287 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1291 ARDOUR_UI::idle_finish ()
1294 return false; /* do not call again */
1301 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1303 if (_session->dirty()) {
1304 vector<string> actions;
1305 actions.push_back (_("Don't quit"));
1306 actions.push_back (_("Just quit"));
1307 actions.push_back (_("Save and quit"));
1308 switch (ask_about_saving_session(actions)) {
1313 /* use the default name */
1314 if (save_state_canfail ("")) {
1315 /* failed - don't quit */
1316 MessageDialog msg (_main_window,
1317 string_compose (_("\
1318 %1 was unable to save your session.\n\n\
1319 If you still wish to quit, please use the\n\n\
1320 \"Just quit\" option."), PROGRAM_NAME));
1321 pop_back_splash(msg);
1331 second_connection.disconnect ();
1332 point_one_second_connection.disconnect ();
1333 point_zero_something_second_connection.disconnect();
1334 fps_connection.disconnect();
1337 delete ARDOUR_UI::instance()->video_timeline;
1338 ARDOUR_UI::instance()->video_timeline = NULL;
1339 stop_video_server();
1341 /* Save state before deleting the session, as that causes some
1342 windows to be destroyed before their visible state can be
1345 save_ardour_state ();
1347 if (key_editor.get (false)) {
1348 key_editor->disconnect ();
1351 close_all_dialogs ();
1354 _session->set_clean ();
1355 _session->remove_pending_capture_state ();
1360 halt_connection.disconnect ();
1361 AudioEngine::instance()->stop ();
1362 #ifdef WINDOWS_VST_SUPPORT
1363 fst_stop_threading();
1369 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1371 ArdourDialog window (_("Unsaved Session"));
1372 Gtk::HBox dhbox; // the hbox for the image and text
1373 Gtk::Label prompt_label;
1374 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1378 assert (actions.size() >= 3);
1380 window.add_button (actions[0], RESPONSE_REJECT);
1381 window.add_button (actions[1], RESPONSE_APPLY);
1382 window.add_button (actions[2], RESPONSE_ACCEPT);
1384 window.set_default_response (RESPONSE_ACCEPT);
1386 Gtk::Button noquit_button (msg);
1387 noquit_button.set_name ("EditorGTKButton");
1391 if (_session->snap_name() == _session->name()) {
1392 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?"),
1393 _session->snap_name());
1395 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?"),
1396 _session->snap_name());
1399 prompt_label.set_text (prompt);
1400 prompt_label.set_name (X_("PrompterLabel"));
1401 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1403 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1404 dhbox.set_homogeneous (false);
1405 dhbox.pack_start (*dimage, false, false, 5);
1406 dhbox.pack_start (prompt_label, true, false, 5);
1407 window.get_vbox()->pack_start (dhbox);
1409 window.set_name (_("Prompter"));
1410 window.set_modal (true);
1411 window.set_resizable (false);
1414 prompt_label.show();
1419 ResponseType r = (ResponseType) window.run();
1424 case RESPONSE_ACCEPT: // save and get out of here
1426 case RESPONSE_APPLY: // get out of here
1437 ARDOUR_UI::every_second ()
1440 update_xrun_count ();
1441 update_buffer_load ();
1442 update_disk_space ();
1443 update_timecode_format ();
1444 update_peak_thread_work ();
1446 if (nsm && nsm->is_active ()) {
1449 if (!_was_dirty && _session->dirty ()) {
1453 else if (_was_dirty && !_session->dirty ()){
1461 ARDOUR_UI::every_point_one_seconds ()
1463 // TODO get rid of this..
1464 // ShuttleControl is updated directly via TransportStateChange signal
1468 ARDOUR_UI::every_point_zero_something_seconds ()
1470 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1472 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1473 float mpeak = editor_meter->update_meters();
1474 if (mpeak > editor_meter_max_peak) {
1475 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1476 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1483 ARDOUR_UI::set_fps_timeout_connection ()
1485 unsigned int interval = 40;
1486 if (!_session) return;
1487 if (_session->timecode_frames_per_second() != 0) {
1488 /* ideally we'll use a select() to sleep and not accumulate
1489 * idle time to provide a regular periodic signal.
1490 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1491 * However, that'll require a dedicated thread and cross-thread
1492 * signals to the GUI Thread..
1494 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1495 * _session->frame_rate() / _session->nominal_frame_rate()
1496 / _session->timecode_frames_per_second()
1498 #ifdef PLATFORM_WINDOWS
1499 // the smallest windows scheduler time-slice is ~15ms.
1500 // periodic GUI timeouts shorter than that will cause
1501 // WaitForSingleObject to spinlock (100% of one CPU Core)
1502 // and gtk never enters idle mode.
1503 // also changing timeBeginPeriod(1) does not affect that in
1504 // any beneficial way, so we just limit the max rate for now.
1505 interval = std::max(30u, interval); // at most ~33Hz.
1507 interval = std::max(8u, interval); // at most 120Hz.
1510 fps_connection.disconnect();
1511 Timers::set_fps_interval (interval);
1515 ARDOUR_UI::update_sample_rate (framecnt_t)
1519 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1521 if (!AudioEngine::instance()->connected()) {
1523 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1527 framecnt_t rate = AudioEngine::instance()->sample_rate();
1530 /* no sample rate available */
1531 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1534 if (fmod (rate, 1000.0) != 0.0) {
1535 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1536 (float) rate / 1000.0f,
1537 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1539 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1541 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1545 sample_rate_label.set_markup (buf);
1549 ARDOUR_UI::update_format ()
1552 format_label.set_text ("");
1557 s << _("File:") << X_(" <span foreground=\"green\">");
1559 switch (_session->config.get_native_file_header_format ()) {
1591 switch (_session->config.get_native_file_data_format ()) {
1605 format_label.set_markup (s.str ());
1609 ARDOUR_UI::update_xrun_count ()
1613 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1614 should also be changed.
1618 const unsigned int x = _session->get_xrun_count ();
1620 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1622 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1625 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1627 xrun_label.set_markup (buf);
1628 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1632 ARDOUR_UI::update_cpu_load ()
1636 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1637 should also be changed.
1640 double const c = AudioEngine::instance()->get_dsp_load ();
1641 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1642 cpu_load_label.set_markup (buf);
1646 ARDOUR_UI::update_peak_thread_work ()
1649 const int c = SourceFactory::peak_work_queue_length ();
1651 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1652 peak_thread_work_label.set_markup (buf);
1654 peak_thread_work_label.set_markup (X_(""));
1659 ARDOUR_UI::update_buffer_load ()
1663 uint32_t const playback = _session ? _session->playback_load () : 100;
1664 uint32_t const capture = _session ? _session->capture_load () : 100;
1666 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1667 should also be changed.
1673 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1674 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1675 playback <= 5 ? X_("red") : X_("green"),
1677 capture <= 5 ? X_("red") : X_("green"),
1681 buffer_load_label.set_markup (buf);
1683 buffer_load_label.set_text ("");
1688 ARDOUR_UI::count_recenabled_streams (Route& route)
1690 Track* track = dynamic_cast<Track*>(&route);
1691 if (track && track->rec_enable_control()->get_value()) {
1692 rec_enabled_streams += track->n_inputs().n_total();
1697 ARDOUR_UI::update_disk_space()
1699 if (_session == 0) {
1703 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1705 framecnt_t fr = _session->frame_rate();
1708 /* skip update - no SR available */
1713 /* Available space is unknown */
1714 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1715 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1716 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1718 rec_enabled_streams = 0;
1719 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1721 framecnt_t frames = opt_frames.get_value_or (0);
1723 if (rec_enabled_streams) {
1724 frames /= rec_enabled_streams;
1731 hrs = frames / (fr * 3600);
1734 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1736 frames -= hrs * fr * 3600;
1737 mins = frames / (fr * 60);
1738 frames -= mins * fr * 60;
1741 bool const low = (hrs == 0 && mins <= 30);
1745 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1746 low ? X_("red") : X_("green"),
1752 disk_space_label.set_markup (buf);
1756 ARDOUR_UI::update_timecode_format ()
1762 TimecodeSlave* tcslave;
1763 SyncSource sync_src = Config->get_sync_source();
1765 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1766 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1771 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1772 matching ? X_("green") : X_("red"),
1773 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1775 snprintf (buf, sizeof (buf), "TC: n/a");
1778 timecode_format_label.set_markup (buf);
1782 ARDOUR_UI::update_wall_clock ()
1786 static int last_min = -1;
1789 tm_now = localtime (&now);
1790 if (last_min != tm_now->tm_min) {
1792 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1793 wall_clock_label.set_text (buf);
1794 last_min = tm_now->tm_min;
1801 ARDOUR_UI::open_recent_session ()
1803 bool can_return = (_session != 0);
1805 SessionDialog recent_session_dialog;
1809 ResponseType r = (ResponseType) recent_session_dialog.run ();
1812 case RESPONSE_ACCEPT:
1816 recent_session_dialog.hide();
1823 recent_session_dialog.hide();
1827 std::string path = recent_session_dialog.session_folder();
1828 std::string state = recent_session_dialog.session_name (should_be_new);
1830 if (should_be_new == true) {
1834 _session_is_new = false;
1836 if (load_session (path, state) == 0) {
1842 if (splash && splash->is_visible()) {
1843 // in 1 second, hide the splash screen
1844 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1849 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1851 if (!AudioEngine::instance()->connected()) {
1852 MessageDialog msg (parent, string_compose (
1853 _("%1 is not connected to any audio backend.\n"
1854 "You cannot open or close sessions in this condition"),
1856 pop_back_splash (msg);
1864 ARDOUR_UI::open_session ()
1866 if (!check_audioengine (_main_window)) {
1870 /* ardour sessions are folders */
1871 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1872 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1873 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1874 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1877 string session_parent_dir = Glib::path_get_dirname(_session->path());
1878 open_session_selector.set_current_folder(session_parent_dir);
1880 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1883 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1885 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1886 string default_session_folder = Config->get_default_session_parent_dir();
1887 open_session_selector.add_shortcut_folder (default_session_folder);
1889 catch (Glib::Error & e) {
1890 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1893 FileFilter session_filter;
1894 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1895 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1896 open_session_selector.add_filter (session_filter);
1898 FileFilter archive_filter;
1899 archive_filter.add_pattern (X_("*.tar.xz"));
1900 archive_filter.set_name (_("Session Archives"));
1902 open_session_selector.add_filter (archive_filter);
1904 open_session_selector.set_filter (session_filter);
1906 int response = open_session_selector.run();
1907 open_session_selector.hide ();
1909 if (response == Gtk::RESPONSE_CANCEL) {
1913 string session_path = open_session_selector.get_filename();
1917 if (session_path.length() > 0) {
1918 int rv = ARDOUR::inflate_session (session_path,
1919 Config->get_default_session_parent_dir(), path, name);
1921 _session_is_new = false;
1922 load_session (path, name);
1925 MessageDialog msg (_main_window,
1926 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1929 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1930 _session_is_new = isnew;
1931 load_session (path, name);
1937 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1943 _session->vca_manager().create_vca (n, name_template);
1947 ARDOUR_UI::session_add_mixed_track (
1948 const ChanCount& input,
1949 const ChanCount& output,
1950 RouteGroup* route_group,
1952 const string& name_template,
1954 PluginInfoPtr instrument,
1955 Plugin::PresetRecord* pset,
1956 ARDOUR::PresentationInfo::order_t order)
1958 if (_session == 0) {
1959 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1963 if (Profile->get_mixbus ()) {
1968 list<boost::shared_ptr<MidiTrack> > tracks;
1969 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1971 if (tracks.size() != how_many) {
1972 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1977 display_insufficient_ports_message ();
1983 ARDOUR_UI::session_add_midi_bus (
1984 RouteGroup* route_group,
1986 const string& name_template,
1988 PluginInfoPtr instrument,
1989 Plugin::PresetRecord* pset,
1990 ARDOUR::PresentationInfo::order_t order)
1992 if (_session == 0) {
1993 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1997 if (Profile->get_mixbus ()) {
2003 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2004 if (routes.size() != how_many) {
2005 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2010 display_insufficient_ports_message ();
2016 ARDOUR_UI::session_add_midi_route (
2018 RouteGroup* route_group,
2020 const string& name_template,
2022 PluginInfoPtr instrument,
2023 Plugin::PresetRecord* pset,
2024 ARDOUR::PresentationInfo::order_t order)
2026 ChanCount one_midi_channel;
2027 one_midi_channel.set (DataType::MIDI, 1);
2030 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2032 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2037 ARDOUR_UI::session_add_audio_route (
2039 int32_t input_channels,
2040 int32_t output_channels,
2041 ARDOUR::TrackMode mode,
2042 RouteGroup* route_group,
2044 string const & name_template,
2046 ARDOUR::PresentationInfo::order_t order)
2048 list<boost::shared_ptr<AudioTrack> > tracks;
2051 if (_session == 0) {
2052 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2058 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2060 if (tracks.size() != how_many) {
2061 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2067 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2069 if (routes.size() != how_many) {
2070 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2077 display_insufficient_ports_message ();
2082 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2083 (*i)->set_strict_io (true);
2085 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2086 (*i)->set_strict_io (true);
2092 ARDOUR_UI::display_insufficient_ports_message ()
2094 MessageDialog msg (_main_window,
2095 string_compose (_("There are insufficient ports available\n\
2096 to create a new track or bus.\n\
2097 You should save %1, exit and\n\
2098 restart with more ports."), PROGRAM_NAME));
2099 pop_back_splash (msg);
2104 ARDOUR_UI::transport_goto_start ()
2107 _session->goto_start();
2109 /* force displayed area in editor to start no matter
2110 what "follow playhead" setting is.
2114 editor->center_screen (_session->current_start_frame ());
2120 ARDOUR_UI::transport_goto_zero ()
2123 _session->request_locate (0);
2125 /* force displayed area in editor to start no matter
2126 what "follow playhead" setting is.
2130 editor->reset_x_origin (0);
2136 ARDOUR_UI::transport_goto_wallclock ()
2138 if (_session && editor) {
2145 localtime_r (&now, &tmnow);
2147 framecnt_t frame_rate = _session->frame_rate();
2149 if (frame_rate == 0) {
2150 /* no frame rate available */
2154 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2155 frames += tmnow.tm_min * (60 * frame_rate);
2156 frames += tmnow.tm_sec * frame_rate;
2158 _session->request_locate (frames, _session->transport_rolling ());
2160 /* force displayed area in editor to start no matter
2161 what "follow playhead" setting is.
2165 editor->center_screen (frames);
2171 ARDOUR_UI::transport_goto_end ()
2174 framepos_t const frame = _session->current_end_frame();
2175 _session->request_locate (frame);
2177 /* force displayed area in editor to start no matter
2178 what "follow playhead" setting is.
2182 editor->center_screen (frame);
2188 ARDOUR_UI::transport_stop ()
2194 if (_session->is_auditioning()) {
2195 _session->cancel_audition ();
2199 _session->request_stop (false, true);
2202 /** Check if any tracks are record enabled. If none are, record enable all of them.
2203 * @return true if track record-enabled status was changed, false otherwise.
2206 ARDOUR_UI::trx_record_enable_all_tracks ()
2212 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2213 bool none_record_enabled = true;
2215 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2216 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2219 if (t->rec_enable_control()->get_value()) {
2220 none_record_enabled = false;
2225 if (none_record_enabled) {
2226 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2229 return none_record_enabled;
2233 ARDOUR_UI::transport_record (bool roll)
2236 switch (_session->record_status()) {
2237 case Session::Disabled:
2238 if (_session->ntracks() == 0) {
2239 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."));
2243 if (Profile->get_trx()) {
2244 roll = trx_record_enable_all_tracks ();
2246 _session->maybe_enable_record ();
2251 case Session::Recording:
2253 _session->request_stop();
2255 _session->disable_record (false, true);
2259 case Session::Enabled:
2260 _session->disable_record (false, true);
2266 ARDOUR_UI::transport_roll ()
2272 if (_session->is_auditioning()) {
2277 if (_session->config.get_external_sync()) {
2278 switch (Config->get_sync_source()) {
2282 /* transport controlled by the master */
2288 bool rolling = _session->transport_rolling();
2290 if (_session->get_play_loop()) {
2292 /* If loop playback is not a mode, then we should cancel
2293 it when this action is requested. If it is a mode
2294 we just leave it in place.
2297 if (!Config->get_loop_is_mode()) {
2298 /* XXX it is not possible to just leave seamless loop and keep
2299 playing at present (nov 4th 2009)
2301 if (!Config->get_seamless_loop()) {
2302 /* stop loop playback and stop rolling */
2303 _session->request_play_loop (false, true);
2304 } else if (rolling) {
2305 /* stop loop playback but keep rolling */
2306 _session->request_play_loop (false, false);
2310 } else if (_session->get_play_range () ) {
2311 /* stop playing a range if we currently are */
2312 _session->request_play_range (0, true);
2316 _session->request_transport_speed (1.0f);
2321 ARDOUR_UI::get_smart_mode() const
2323 return ( editor->get_smart_mode() );
2328 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2334 if (_session->is_auditioning()) {
2335 _session->cancel_audition ();
2339 if (_session->config.get_external_sync()) {
2340 switch (Config->get_sync_source()) {
2344 /* transport controlled by the master */
2349 bool rolling = _session->transport_rolling();
2350 bool affect_transport = true;
2352 if (rolling && roll_out_of_bounded_mode) {
2353 /* drop out of loop/range playback but leave transport rolling */
2354 if (_session->get_play_loop()) {
2355 if (_session->actively_recording()) {
2357 /* just stop using the loop, then actually stop
2360 _session->request_play_loop (false, affect_transport);
2363 if (Config->get_seamless_loop()) {
2364 /* the disk buffers contain copies of the loop - we can't
2365 just keep playing, so stop the transport. the user
2366 can restart as they wish.
2368 affect_transport = true;
2370 /* disk buffers are normal, so we can keep playing */
2371 affect_transport = false;
2373 _session->request_play_loop (false, affect_transport);
2375 } else if (_session->get_play_range ()) {
2376 affect_transport = false;
2377 _session->request_play_range (0, true);
2381 if (affect_transport) {
2383 _session->request_stop (with_abort, true);
2385 } else if (!with_abort) { /* with_abort == true means the
2386 * command was intended to stop
2387 * transport, not start.
2390 /* the only external sync condition we can be in here
2391 * would be Engine (JACK) sync, in which case we still
2395 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
2396 _session->request_play_range (&editor->get_selection().time, true);
2397 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2399 _session->request_transport_speed (1.0f);
2405 ARDOUR_UI::toggle_session_auto_loop ()
2411 Location * looploc = _session->locations()->auto_loop_location();
2417 if (_session->get_play_loop()) {
2419 /* looping enabled, our job is to disable it */
2421 _session->request_play_loop (false);
2425 /* looping not enabled, our job is to enable it.
2427 loop-is-NOT-mode: this action always starts the transport rolling.
2428 loop-IS-mode: this action simply sets the loop play mechanism, but
2429 does not start transport.
2431 if (Config->get_loop_is_mode()) {
2432 _session->request_play_loop (true, false);
2434 _session->request_play_loop (true, true);
2438 //show the loop markers
2439 looploc->set_hidden (false, this);
2443 ARDOUR_UI::transport_play_selection ()
2449 editor->play_selection ();
2453 ARDOUR_UI::transport_play_preroll ()
2458 editor->play_with_preroll ();
2462 ARDOUR_UI::transport_rec_preroll ()
2467 editor->rec_with_preroll ();
2471 ARDOUR_UI::transport_rec_count_in ()
2476 editor->rec_with_count_in ();
2480 ARDOUR_UI::transport_rewind (int option)
2482 float current_transport_speed;
2485 current_transport_speed = _session->transport_speed();
2487 if (current_transport_speed >= 0.0f) {
2490 _session->request_transport_speed (-1.0f);
2493 _session->request_transport_speed (-4.0f);
2496 _session->request_transport_speed (-0.5f);
2501 _session->request_transport_speed (current_transport_speed * 1.5f);
2507 ARDOUR_UI::transport_forward (int option)
2513 float current_transport_speed = _session->transport_speed();
2515 if (current_transport_speed <= 0.0f) {
2518 _session->request_transport_speed (1.0f);
2521 _session->request_transport_speed (4.0f);
2524 _session->request_transport_speed (0.5f);
2529 _session->request_transport_speed (current_transport_speed * 1.5f);
2534 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2540 boost::shared_ptr<Route> r;
2542 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2544 boost::shared_ptr<Track> t;
2546 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2547 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2553 ARDOUR_UI::map_transport_state ()
2556 auto_loop_button.unset_active_state ();
2557 play_selection_button.unset_active_state ();
2558 roll_button.unset_active_state ();
2559 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2560 layered_button.set_sensitive (false);
2564 shuttle_box.map_transport_state ();
2566 float sp = _session->transport_speed();
2572 if (_session->get_play_range()) {
2574 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2575 roll_button.unset_active_state ();
2576 auto_loop_button.unset_active_state ();
2578 } else if (_session->get_play_loop ()) {
2580 auto_loop_button.set_active (true);
2581 play_selection_button.set_active (false);
2582 if (Config->get_loop_is_mode()) {
2583 roll_button.set_active (true);
2585 roll_button.set_active (false);
2590 roll_button.set_active (true);
2591 play_selection_button.set_active (false);
2592 auto_loop_button.set_active (false);
2595 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2596 /* light up both roll and play-selection if they are joined */
2597 roll_button.set_active (true);
2598 play_selection_button.set_active (true);
2600 layered_button.set_sensitive (!_session->actively_recording ());
2602 stop_button.set_active (false);
2606 layered_button.set_sensitive (true);
2607 stop_button.set_active (true);
2608 roll_button.set_active (false);
2609 play_selection_button.set_active (false);
2610 if (Config->get_loop_is_mode ()) {
2611 auto_loop_button.set_active (_session->get_play_loop());
2613 auto_loop_button.set_active (false);
2615 update_disk_space ();
2620 ARDOUR_UI::blink_handler (bool blink_on)
2622 transport_rec_enable_blink (blink_on);
2623 sync_blink (blink_on);
2625 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2628 error_blink (blink_on);
2629 solo_blink (blink_on);
2630 audition_blink (blink_on);
2631 feedback_blink (blink_on);
2635 ARDOUR_UI::update_clocks ()
2637 if (!_session) return;
2639 if (editor && !editor->dragging_playhead()) {
2640 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2645 ARDOUR_UI::start_clocking ()
2647 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2648 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2650 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2655 ARDOUR_UI::stop_clocking ()
2657 clock_signal_connection.disconnect ();
2661 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2665 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2667 label->set_text (buf);
2668 bar->set_fraction (fraction);
2670 /* process events, redraws, etc. */
2672 while (gtk_events_pending()) {
2673 gtk_main_iteration ();
2676 return true; /* continue with save-as */
2680 ARDOUR_UI::save_session_as ()
2686 if (!save_as_dialog) {
2687 save_as_dialog = new SaveAsDialog;
2690 save_as_dialog->set_name (_session->name());
2692 int response = save_as_dialog->run ();
2694 save_as_dialog->hide ();
2697 case Gtk::RESPONSE_OK:
2706 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2707 sa.new_name = save_as_dialog->new_name ();
2708 sa.switch_to = save_as_dialog->switch_to();
2709 sa.copy_media = save_as_dialog->copy_media();
2710 sa.copy_external = save_as_dialog->copy_external();
2711 sa.include_media = save_as_dialog->include_media ();
2713 /* Only bother with a progress dialog if we're going to copy
2714 media into the save-as target. Without that choice, this
2715 will be very fast because we're only talking about a few kB's to
2716 perhaps a couple of MB's of data.
2719 ArdourDialog progress_dialog (_("Save As"), true);
2722 if (sa.include_media && sa.copy_media) {
2724 Gtk::Label* label = manage (new Gtk::Label());
2725 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2727 progress_dialog.get_vbox()->pack_start (*label);
2728 progress_dialog.get_vbox()->pack_start (*progress_bar);
2730 progress_bar->show ();
2732 /* this signal will be emitted from within this, the calling thread,
2733 * after every file is copied. It provides information on percentage
2734 * complete (in terms of total data to copy), the number of files
2735 * copied so far, and the total number to copy.
2738 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2740 progress_dialog.show_all ();
2741 progress_dialog.present ();
2744 if (_session->save_as (sa)) {
2746 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2750 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2751 * the trick is this: if the new session was copy with media included,
2752 * then Session::save_as() will have already done a neat trick to avoid
2753 * us having to unload and load the new state. But if the media was not
2754 * included, then this is required (it avoids us having to otherwise
2755 * drop all references to media (sources).
2758 if (!sa.include_media && sa.switch_to) {
2759 unload_session (false);
2760 load_session (sa.final_session_folder_name, sa.new_name);
2766 ARDOUR_UI::archive_session ()
2774 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2776 SessionArchiveDialog sad;
2777 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2778 int response = sad.run ();
2780 if (response != Gtk::RESPONSE_OK) {
2785 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2786 MessageDialog msg (_("Session Archiving failed."));
2792 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2796 struct tm local_time;
2799 localtime_r (&n, &local_time);
2800 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2802 save_state (timebuf, switch_to_it);
2807 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2811 prompter.get_result (snapname);
2813 bool do_save = (snapname.length() != 0);
2816 char illegal = Session::session_name_is_legal(snapname);
2818 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2819 "snapshot names may not contain a '%1' character"), illegal));
2825 vector<std::string> p;
2826 get_state_files_in_directory (_session->session_directory().root_path(), p);
2827 vector<string> n = get_file_names_no_extension (p);
2829 if (find (n.begin(), n.end(), snapname) != n.end()) {
2831 do_save = overwrite_file_dialog (prompter,
2832 _("Confirm Snapshot Overwrite"),
2833 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2837 save_state (snapname, switch_to_it);
2847 /** Ask the user for the name of a new snapshot and then take it.
2851 ARDOUR_UI::snapshot_session (bool switch_to_it)
2853 ArdourPrompter prompter (true);
2855 prompter.set_name ("Prompter");
2856 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2858 prompter.set_title (_("Snapshot and switch"));
2859 prompter.set_prompt (_("New session name"));
2861 prompter.set_title (_("Take Snapshot"));
2862 prompter.set_prompt (_("Name of new snapshot"));
2866 prompter.set_initial_text (_session->snap_name());
2868 Glib::DateTime tm (g_date_time_new_now_local ());
2869 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2872 bool finished = false;
2874 switch (prompter.run()) {
2875 case RESPONSE_ACCEPT:
2877 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2888 /** Ask the user for a new session name and then rename the session to it.
2892 ARDOUR_UI::rename_session ()
2898 ArdourPrompter prompter (true);
2901 prompter.set_name ("Prompter");
2902 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2903 prompter.set_title (_("Rename Session"));
2904 prompter.set_prompt (_("New session name"));
2907 switch (prompter.run()) {
2908 case RESPONSE_ACCEPT:
2910 prompter.get_result (name);
2912 bool do_rename = (name.length() != 0);
2915 char illegal = Session::session_name_is_legal (name);
2918 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2919 "session names may not contain a '%1' character"), illegal));
2924 switch (_session->rename (name)) {
2926 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2927 msg.set_position (WIN_POS_MOUSE);
2935 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2936 msg.set_position (WIN_POS_MOUSE);
2952 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2954 if (!_session || _session->deletion_in_progress()) {
2958 XMLNode* node = new XMLNode (X_("UI"));
2960 WM::Manager::instance().add_state (*node);
2962 node->add_child_nocopy (gui_object_state->get_state());
2964 _session->add_extra_xml (*node);
2966 if (export_video_dialog) {
2967 _session->add_extra_xml (export_video_dialog->get_state());
2970 save_state_canfail (name, switch_to_it);
2974 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2979 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2984 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2989 ARDOUR_UI::primary_clock_value_changed ()
2992 _session->request_locate (primary_clock->current_time ());
2997 ARDOUR_UI::big_clock_value_changed ()
3000 _session->request_locate (big_clock->current_time ());
3005 ARDOUR_UI::secondary_clock_value_changed ()
3008 _session->request_locate (secondary_clock->current_time ());
3013 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3015 if (_session == 0) {
3019 if (_session->step_editing()) {
3023 Session::RecordState const r = _session->record_status ();
3024 bool const h = _session->have_rec_enabled_track ();
3026 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3028 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3030 rec_button.set_active_state (Gtkmm2ext::Off);
3032 } else if (r == Session::Recording && h) {
3033 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3035 rec_button.unset_active_state ();
3040 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3044 prompter.get_result (name);
3046 if (name.length()) {
3047 int failed = _session->save_template (name);
3049 if (failed == -2) { /* file already exists. */
3050 bool overwrite = overwrite_file_dialog (prompter,
3051 _("Confirm Template Overwrite"),
3052 _("A template already exists with that name. Do you want to overwrite it?"));
3055 _session->save_template (name, true);
3067 ARDOUR_UI::save_template ()
3069 ArdourPrompter prompter (true);
3071 if (!check_audioengine (_main_window)) {
3075 prompter.set_name (X_("Prompter"));
3076 prompter.set_title (_("Save Template"));
3077 prompter.set_prompt (_("Name for template:"));
3078 prompter.set_initial_text(_session->name() + _("-template"));
3079 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3081 bool finished = false;
3083 switch (prompter.run()) {
3084 case RESPONSE_ACCEPT:
3085 finished = process_save_template_prompter (prompter);
3096 ARDOUR_UI::edit_metadata ()
3098 SessionMetadataEditor dialog;
3099 dialog.set_session (_session);
3100 dialog.grab_focus ();
3105 ARDOUR_UI::import_metadata ()
3107 SessionMetadataImporter dialog;
3108 dialog.set_session (_session);
3113 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3115 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3117 MessageDialog msg (str,
3119 Gtk::MESSAGE_WARNING,
3120 Gtk::BUTTONS_YES_NO,
3124 msg.set_name (X_("OpenExistingDialog"));
3125 msg.set_title (_("Open Existing Session"));
3126 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3127 msg.set_position (Gtk::WIN_POS_CENTER);
3128 pop_back_splash (msg);
3130 switch (msg.run()) {
3139 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3141 BusProfile bus_profile;
3145 bus_profile.master_out_channels = 2;
3146 bus_profile.input_ac = AutoConnectPhysical;
3147 bus_profile.output_ac = AutoConnectMaster;
3148 bus_profile.requested_physical_in = 0; // use all available
3149 bus_profile.requested_physical_out = 0; // use all available
3153 /* get settings from advanced section of NSD */
3155 if (sd.create_master_bus()) {
3156 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3158 bus_profile.master_out_channels = 0;
3161 if (sd.connect_inputs()) {
3162 bus_profile.input_ac = AutoConnectPhysical;
3164 bus_profile.input_ac = AutoConnectOption (0);
3167 bus_profile.output_ac = AutoConnectOption (0);
3169 if (sd.connect_outputs ()) {
3170 if (sd.connect_outs_to_master()) {
3171 bus_profile.output_ac = AutoConnectMaster;
3172 } else if (sd.connect_outs_to_physical()) {
3173 bus_profile.output_ac = AutoConnectPhysical;
3177 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3178 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3181 if (build_session (session_path, session_name, bus_profile)) {
3189 ARDOUR_UI::load_from_application_api (const std::string& path)
3191 /* OS X El Capitan (and probably later) now somehow passes the command
3192 line arguments to an app via the openFile delegate protocol. Ardour
3193 already does its own command line processing, and having both
3194 pathways active causes crashes. So, if the command line was already
3195 set, do nothing here.
3198 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3202 ARDOUR_COMMAND_LINE::session_name = path;
3204 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3206 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3208 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3209 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3210 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3211 * -> SessionDialog is not displayed
3214 if (_session_dialog) {
3215 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3216 std::string session_path = path;
3217 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3218 session_path = Glib::path_get_dirname (session_path);
3220 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3221 _session_dialog->set_provided_session (session_name, session_path);
3222 _session_dialog->response (RESPONSE_NONE);
3223 _session_dialog->hide();
3228 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3229 /* /path/to/foo => /path/to/foo, foo */
3230 rv = load_session (path, basename_nosuffix (path));
3232 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3233 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3236 // if load_session fails -> pop up SessionDialog.
3238 ARDOUR_COMMAND_LINE::session_name = "";
3240 if (get_session_parameters (true, false)) {
3246 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3248 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3250 string session_name;
3251 string session_path;
3252 string template_name;
3254 bool likely_new = false;
3255 bool cancel_not_quit;
3257 /* deal with any existing DIRTY session now, rather than later. don't
3258 * treat a non-dirty session this way, so that it stays visible
3259 * as we bring up the new session dialog.
3262 if (_session && ARDOUR_UI::instance()->video_timeline) {
3263 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3266 /* if there is already a session, relabel the button
3267 on the SessionDialog so that we don't Quit directly
3269 cancel_not_quit = (_session != 0);
3271 if (_session && _session->dirty()) {
3272 if (unload_session (false)) {
3273 /* unload cancelled by user */
3276 ARDOUR_COMMAND_LINE::session_name = "";
3279 if (!load_template.empty()) {
3280 should_be_new = true;
3281 template_name = load_template;
3284 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3285 session_path = ARDOUR_COMMAND_LINE::session_name;
3287 if (!session_path.empty()) {
3288 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3289 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3290 /* session/snapshot file, change path to be dir */
3291 session_path = Glib::path_get_dirname (session_path);
3296 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3298 _session_dialog = &session_dialog;
3301 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3303 /* if they named a specific statefile, use it, otherwise they are
3304 just giving a session folder, and we want to use it as is
3305 to find the session.
3308 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3310 if (suffix != string::npos) {
3311 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3312 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3313 session_name = Glib::path_get_basename (session_name);
3315 session_path = ARDOUR_COMMAND_LINE::session_name;
3316 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3321 session_dialog.clear_given ();
3324 if (should_be_new || session_name.empty()) {
3325 /* need the dialog to get info from user */
3327 cerr << "run dialog\n";
3329 switch (session_dialog.run()) {
3330 case RESPONSE_ACCEPT:
3333 /* this is used for async * app->ShouldLoad(). */
3334 continue; // while loop
3337 if (quit_on_cancel) {
3338 // JE - Currently (July 2014) this section can only get reached if the
3339 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3340 // point does NOT indicate an abnormal termination). Therefore, let's
3341 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3343 pthread_cancel_all ();
3351 session_dialog.hide ();
3354 /* if we run the startup dialog again, offer more than just "new session" */
3356 should_be_new = false;
3358 session_name = session_dialog.session_name (likely_new);
3359 session_path = session_dialog.session_folder ();
3366 int rv = ARDOUR::inflate_session (session_name,
3367 Config->get_default_session_parent_dir(), session_path, session_name);
3369 MessageDialog msg (session_dialog,
3370 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3375 session_dialog.set_provided_session (session_name, session_path);
3379 // XXX check archive, inflate
3380 string::size_type suffix = session_name.find (statefile_suffix);
3382 if (suffix != string::npos) {
3383 session_name = session_name.substr (0, suffix);
3386 /* this shouldn't happen, but we catch it just in case it does */
3388 if (session_name.empty()) {
3392 if (session_dialog.use_session_template()) {
3393 template_name = session_dialog.session_template_name();
3394 _session_is_new = true;
3397 if (session_name[0] == G_DIR_SEPARATOR ||
3398 #ifdef PLATFORM_WINDOWS
3399 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3401 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3402 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3407 /* absolute path or cwd-relative path specified for session name: infer session folder
3408 from what was given.
3411 session_path = Glib::path_get_dirname (session_name);
3412 session_name = Glib::path_get_basename (session_name);
3416 session_path = session_dialog.session_folder();
3418 char illegal = Session::session_name_is_legal (session_name);
3421 MessageDialog msg (session_dialog,
3422 string_compose (_("To ensure compatibility with various systems\n"
3423 "session names may not contain a '%1' character"),
3426 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3431 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3434 if (likely_new && !nsm) {
3436 std::string existing = Glib::build_filename (session_path, session_name);
3438 if (!ask_about_loading_existing_session (existing)) {
3439 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3444 _session_is_new = false;
3449 pop_back_splash (session_dialog);
3450 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3452 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3456 char illegal = Session::session_name_is_legal(session_name);
3459 pop_back_splash (session_dialog);
3460 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3461 "session names may not contain a '%1' character"), illegal));
3463 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3467 _session_is_new = true;
3470 if (likely_new && template_name.empty()) {
3472 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3476 ret = load_session (session_path, session_name, template_name);
3479 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3483 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3484 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3488 /* clear this to avoid endless attempts to load the
3492 ARDOUR_COMMAND_LINE::session_name = "";
3496 _session_dialog = NULL;
3502 ARDOUR_UI::close_session()
3504 if (!check_audioengine (_main_window)) {
3508 if (unload_session (true)) {
3512 ARDOUR_COMMAND_LINE::session_name = "";
3514 if (get_session_parameters (true, false)) {
3517 if (splash && splash->is_visible()) {
3518 // in 1 second, hide the splash screen
3519 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3523 /** @param snap_name Snapshot name (without .ardour suffix).
3524 * @return -2 if the load failed because we are not connected to the AudioEngine.
3527 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3529 Session *new_session;
3534 unload_status = unload_session ();
3536 if (unload_status < 0) {
3538 } else if (unload_status > 0) {
3544 session_loaded = false;
3546 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3549 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3552 /* this one is special */
3554 catch (AudioEngine::PortRegistrationFailure& err) {
3556 MessageDialog msg (err.what(),
3559 Gtk::BUTTONS_CLOSE);
3561 msg.set_title (_("Port Registration Error"));
3562 msg.set_secondary_text (_("Click the Close button to try again."));
3563 msg.set_position (Gtk::WIN_POS_CENTER);
3564 pop_back_splash (msg);
3567 int response = msg.run ();
3572 case RESPONSE_CANCEL:
3579 catch (SessionException e) {
3580 MessageDialog msg (string_compose(
3581 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3582 path, snap_name, e.what()),
3587 msg.set_title (_("Loading Error"));
3588 msg.set_position (Gtk::WIN_POS_CENTER);
3589 pop_back_splash (msg);
3601 MessageDialog msg (string_compose(
3602 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3608 msg.set_title (_("Loading Error"));
3609 msg.set_position (Gtk::WIN_POS_CENTER);
3610 pop_back_splash (msg);
3622 list<string> const u = new_session->unknown_processors ();
3624 MissingPluginDialog d (_session, u);
3629 if (!new_session->writable()) {
3630 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3635 msg.set_title (_("Read-only Session"));
3636 msg.set_position (Gtk::WIN_POS_CENTER);
3637 pop_back_splash (msg);
3644 /* Now the session been created, add the transport controls */
3645 new_session->add_controllable(roll_controllable);
3646 new_session->add_controllable(stop_controllable);
3647 new_session->add_controllable(goto_start_controllable);
3648 new_session->add_controllable(goto_end_controllable);
3649 new_session->add_controllable(auto_loop_controllable);
3650 new_session->add_controllable(play_selection_controllable);
3651 new_session->add_controllable(rec_controllable);
3653 set_session (new_session);
3655 session_loaded = true;
3658 _session->set_clean ();
3661 #ifdef WINDOWS_VST_SUPPORT
3662 fst_stop_threading();
3666 Timers::TimerSuspender t;
3670 #ifdef WINDOWS_VST_SUPPORT
3671 fst_start_threading();
3680 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3682 Session *new_session;
3685 session_loaded = false;
3686 x = unload_session ();
3694 _session_is_new = true;
3697 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3700 catch (SessionException e) {
3701 cerr << "Here are the errors associated with this failed session:\n";
3703 cerr << "---------\n";
3704 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3705 msg.set_title (_("Loading Error"));
3706 msg.set_position (Gtk::WIN_POS_CENTER);
3707 pop_back_splash (msg);
3712 cerr << "Here are the errors associated with this failed session:\n";
3714 cerr << "---------\n";
3715 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3716 msg.set_title (_("Loading Error"));
3717 msg.set_position (Gtk::WIN_POS_CENTER);
3718 pop_back_splash (msg);
3723 /* Give the new session the default GUI state, if such things exist */
3726 n = Config->instant_xml (X_("Editor"));
3728 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3729 new_session->add_instant_xml (*n, false);
3731 n = Config->instant_xml (X_("Mixer"));
3733 new_session->add_instant_xml (*n, false);
3736 n = Config->instant_xml (X_("Preferences"));
3738 new_session->add_instant_xml (*n, false);
3741 /* Put the playhead at 0 and scroll fully left */
3742 n = new_session->instant_xml (X_("Editor"));
3744 n->set_property (X_("playhead"), X_("0"));
3745 n->set_property (X_("left-frame"), X_("0"));
3748 set_session (new_session);
3750 session_loaded = true;
3752 new_session->save_state(new_session->name());
3758 ARDOUR_UI::launch_chat ()
3760 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3762 dialog.set_title (_("About the Chat"));
3763 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."));
3765 switch (dialog.run()) {
3768 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3769 #elif defined PLATFORM_WINDOWS
3770 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3772 open_uri("http://webchat.freenode.net/?channels=ardour");
3781 ARDOUR_UI::launch_manual ()
3783 PBD::open_uri (Config->get_tutorial_manual_url());
3787 ARDOUR_UI::launch_reference ()
3789 PBD::open_uri (Config->get_reference_manual_url());
3793 ARDOUR_UI::launch_tracker ()
3795 PBD::open_uri ("http://tracker.ardour.org");
3799 ARDOUR_UI::launch_subscribe ()
3801 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3805 ARDOUR_UI::launch_cheat_sheet ()
3808 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3810 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3815 ARDOUR_UI::launch_website ()
3817 PBD::open_uri ("http://ardour.org");
3821 ARDOUR_UI::launch_website_dev ()
3823 PBD::open_uri ("http://ardour.org/development.html");
3827 ARDOUR_UI::launch_forums ()
3829 PBD::open_uri ("https://community.ardour.org/forums");
3833 ARDOUR_UI::launch_howto_report ()
3835 PBD::open_uri ("http://ardour.org/reporting_bugs");
3839 ARDOUR_UI::loading_message (const std::string& msg)
3841 if (ARDOUR_COMMAND_LINE::no_splash) {
3849 splash->message (msg);
3853 ARDOUR_UI::show_splash ()
3857 splash = new Splash;
3867 ARDOUR_UI::hide_splash ()
3874 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3878 removed = rep.paths.size();
3881 MessageDialog msgd (_main_window,
3882 _("No files were ready for clean-up"),
3886 msgd.set_title (_("Clean-up"));
3887 msgd.set_secondary_text (_("If this seems suprising, \n\
3888 check for any existing snapshots.\n\
3889 These may still include regions that\n\
3890 require some unused files to continue to exist."));
3896 ArdourDialog results (_("Clean-up"), true, false);
3898 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3899 CleanupResultsModelColumns() {
3903 Gtk::TreeModelColumn<std::string> visible_name;
3904 Gtk::TreeModelColumn<std::string> fullpath;
3908 CleanupResultsModelColumns results_columns;
3909 Glib::RefPtr<Gtk::ListStore> results_model;
3910 Gtk::TreeView results_display;
3912 results_model = ListStore::create (results_columns);
3913 results_display.set_model (results_model);
3914 results_display.append_column (list_title, results_columns.visible_name);
3916 results_display.set_name ("CleanupResultsList");
3917 results_display.set_headers_visible (true);
3918 results_display.set_headers_clickable (false);
3919 results_display.set_reorderable (false);
3921 Gtk::ScrolledWindow list_scroller;
3924 Gtk::HBox dhbox; // the hbox for the image and text
3925 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3926 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3928 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3930 const string dead_directory = _session->session_directory().dead_path();
3933 %1 - number of files removed
3934 %2 - location of "dead"
3935 %3 - size of files affected
3936 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3939 const char* bprefix;
3940 double space_adjusted = 0;
3942 if (rep.space < 1000) {
3944 space_adjusted = rep.space;
3945 } else if (rep.space < 1000000) {
3946 bprefix = _("kilo");
3947 space_adjusted = floorf((float)rep.space / 1000.0);
3948 } else if (rep.space < 1000000 * 1000) {
3949 bprefix = _("mega");
3950 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3952 bprefix = _("giga");
3953 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3957 txt.set_markup (string_compose (P_("\
3958 The following file was deleted from %2,\n\
3959 releasing %3 %4bytes of disk space", "\
3960 The following %1 files were deleted from %2,\n\
3961 releasing %3 %4bytes of disk space", removed),
3962 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3964 txt.set_markup (string_compose (P_("\
3965 The following file was not in use and \n\
3966 has been moved to: %2\n\n\
3967 After a restart of %5\n\n\
3968 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3969 will release an additional %3 %4bytes of disk space.\n", "\
3970 The following %1 files were not in use and \n\
3971 have been moved to: %2\n\n\
3972 After a restart of %5\n\n\
3973 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3974 will release an additional %3 %4bytes of disk space.\n", removed),
3975 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3978 dhbox.pack_start (*dimage, true, false, 5);
3979 dhbox.pack_start (txt, true, false, 5);
3981 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3982 TreeModel::Row row = *(results_model->append());
3983 row[results_columns.visible_name] = *i;
3984 row[results_columns.fullpath] = *i;
3987 list_scroller.add (results_display);
3988 list_scroller.set_size_request (-1, 150);
3989 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3991 dvbox.pack_start (dhbox, true, false, 5);
3992 dvbox.pack_start (list_scroller, true, false, 5);
3993 ddhbox.pack_start (dvbox, true, false, 5);
3995 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3996 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3997 results.set_default_response (RESPONSE_CLOSE);
3998 results.set_position (Gtk::WIN_POS_MOUSE);
4000 results_display.show();
4001 list_scroller.show();
4008 //results.get_vbox()->show();
4009 results.set_resizable (false);
4016 ARDOUR_UI::cleanup ()
4018 if (_session == 0) {
4019 /* shouldn't happen: menu item is insensitive */
4024 MessageDialog checker (_("Are you sure you want to clean-up?"),
4026 Gtk::MESSAGE_QUESTION,
4029 checker.set_title (_("Clean-up"));
4031 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4032 ALL undo/redo information will be lost if you clean-up.\n\
4033 Clean-up will move all unused files to a \"dead\" location."));
4035 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4036 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4037 checker.set_default_response (RESPONSE_CANCEL);
4039 checker.set_name (_("CleanupDialog"));
4040 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4041 checker.set_position (Gtk::WIN_POS_MOUSE);
4043 switch (checker.run()) {
4044 case RESPONSE_ACCEPT:
4050 ARDOUR::CleanupReport rep;
4052 editor->prepare_for_cleanup ();
4054 /* do not allow flush until a session is reloaded */
4056 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4058 act->set_sensitive (false);
4061 if (_session->cleanup_sources (rep)) {
4062 editor->finish_cleanup ();
4066 editor->finish_cleanup ();
4069 display_cleanup_results (rep, _("Cleaned Files"), false);
4073 ARDOUR_UI::flush_trash ()
4075 if (_session == 0) {
4076 /* shouldn't happen: menu item is insensitive */
4080 ARDOUR::CleanupReport rep;
4082 if (_session->cleanup_trash_sources (rep)) {
4086 display_cleanup_results (rep, _("deleted file"), true);
4090 ARDOUR_UI::cleanup_peakfiles ()
4092 if (_session == 0) {
4093 /* shouldn't happen: menu item is insensitive */
4097 if (! _session->can_cleanup_peakfiles ()) {
4101 // get all region-views in this session
4103 TrackViewList empty;
4105 editor->get_regions_after(rs, (framepos_t) 0, empty);
4106 std::list<RegionView*> views = rs.by_layer();
4108 // remove displayed audio-region-views waveforms
4109 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4110 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4111 if (!arv) { continue ; }
4112 arv->delete_waves();
4115 // cleanup peak files:
4116 // - stop pending peakfile threads
4117 // - close peakfiles if any
4118 // - remove peak dir in session
4119 // - setup peakfiles (background thread)
4120 _session->cleanup_peakfiles ();
4122 // re-add waves to ARV
4123 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4124 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4125 if (!arv) { continue ; }
4126 arv->create_waves();
4130 PresentationInfo::order_t
4131 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4133 if (editor->get_selection().tracks.empty()) {
4134 return PresentationInfo::max_order;
4137 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4140 we want the new routes to have their order keys set starting from
4141 the highest order key in the selection + 1 (if available).
4144 if (place == RouteDialogs::AfterSelection) {
4145 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4147 order_hint = rtav->route()->presentation_info().order();
4150 } else if (place == RouteDialogs::BeforeSelection) {
4151 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4153 order_hint = rtav->route()->presentation_info().order();
4155 } else if (place == RouteDialogs::First) {
4158 /* leave order_hint at max_order */
4165 ARDOUR_UI::start_duplicate_routes ()
4167 if (!duplicate_routes_dialog) {
4168 duplicate_routes_dialog = new DuplicateRouteDialog;
4171 if (duplicate_routes_dialog->restart (_session)) {
4175 duplicate_routes_dialog->present ();
4179 ARDOUR_UI::add_route ()
4181 if (!add_route_dialog.get (false)) {
4182 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4189 if (add_route_dialog->is_visible()) {
4190 /* we're already doing this */
4194 add_route_dialog->set_position (WIN_POS_MOUSE);
4195 add_route_dialog->present();
4199 ARDOUR_UI::add_route_dialog_finished (int r)
4203 add_route_dialog->hide();
4206 case RESPONSE_ACCEPT:
4213 if ((count = add_route_dialog->count()) <= 0) {
4217 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4218 string template_path = add_route_dialog->track_template();
4219 DisplaySuspender ds;
4221 if (!template_path.empty()) {
4222 if (add_route_dialog->name_template_is_default()) {
4223 _session->new_route_from_template (count, order, template_path, string());
4225 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4230 ChanCount input_chan= add_route_dialog->channels ();
4231 ChanCount output_chan;
4232 string name_template = add_route_dialog->name_template ();
4233 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4234 RouteGroup* route_group = add_route_dialog->route_group ();
4235 AutoConnectOption oac = Config->get_output_auto_connect();
4236 bool strict_io = add_route_dialog->use_strict_io ();
4238 if (oac & AutoConnectMaster) {
4239 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4240 output_chan.set (DataType::MIDI, 0);
4242 output_chan = input_chan;
4245 /* XXX do something with name template */
4247 Session::ProcessorChangeBlocker pcb (_session);
4249 switch (add_route_dialog->type_wanted()) {
4250 case AddRouteDialog::AudioTrack:
4251 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4253 case AddRouteDialog::MidiTrack:
4254 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4256 case AddRouteDialog::MixedTrack:
4257 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4259 case AddRouteDialog::AudioBus:
4260 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4262 case AddRouteDialog::MidiBus:
4263 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4265 case AddRouteDialog::VCAMaster:
4266 session_add_vca (name_template, count);
4272 ARDOUR_UI::stop_video_server (bool ask_confirm)
4274 if (!video_server_process && ask_confirm) {
4275 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4277 if (video_server_process) {
4279 ArdourDialog confirm (_("Stop Video-Server"), true);
4280 Label m (_("Do you really want to stop the Video Server?"));
4281 confirm.get_vbox()->pack_start (m, true, true);
4282 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4283 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4284 confirm.show_all ();
4285 if (confirm.run() == RESPONSE_CANCEL) {
4289 delete video_server_process;
4290 video_server_process =0;
4295 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4297 ARDOUR_UI::start_video_server( float_window, true);
4301 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4307 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4308 if (video_server_process) {
4309 popup_error(_("The Video Server is already started."));
4311 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4317 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4319 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4321 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4323 video_server_dialog->set_transient_for (*float_window);
4326 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4327 video_server_dialog->hide();
4329 ResponseType r = (ResponseType) video_server_dialog->run ();
4330 video_server_dialog->hide();
4331 if (r != RESPONSE_ACCEPT) { return false; }
4332 if (video_server_dialog->show_again()) {
4333 Config->set_show_video_server_dialog(false);
4337 std::string icsd_exec = video_server_dialog->get_exec_path();
4338 std::string icsd_docroot = video_server_dialog->get_docroot();
4339 #ifndef PLATFORM_WINDOWS
4340 if (icsd_docroot.empty()) {
4341 icsd_docroot = VideoUtils::video_get_docroot (Config);
4346 #ifdef PLATFORM_WINDOWS
4347 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4348 /* OK, allow all drive letters */
4351 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4352 warning << _("Specified docroot is not an existing directory.") << endmsg;
4355 #ifndef PLATFORM_WINDOWS
4356 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4357 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4358 warning << _("Given Video Server is not an executable file.") << endmsg;
4362 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4363 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4364 warning << _("Given Video Server is not an executable file.") << endmsg;
4370 argp=(char**) calloc(9,sizeof(char*));
4371 argp[0] = strdup(icsd_exec.c_str());
4372 argp[1] = strdup("-P");
4373 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4374 argp[3] = strdup("-p");
4375 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4376 argp[5] = strdup("-C");
4377 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4378 argp[7] = strdup(icsd_docroot.c_str());
4380 stop_video_server();
4382 #ifdef PLATFORM_WINDOWS
4383 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4384 /* OK, allow all drive letters */
4387 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4388 Config->set_video_advanced_setup(false);
4390 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4391 Config->set_video_server_url(url_str);
4392 Config->set_video_server_docroot(icsd_docroot);
4393 Config->set_video_advanced_setup(true);
4396 if (video_server_process) {
4397 delete video_server_process;
4400 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4401 if (video_server_process->start()) {
4402 warning << _("Cannot launch the video-server") << endmsg;
4405 int timeout = 120; // 6 sec
4406 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4407 Glib::usleep (50000);
4409 if (--timeout <= 0 || !video_server_process->is_running()) break;
4412 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4414 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4415 delete video_server_process;
4416 video_server_process = 0;
4424 ARDOUR_UI::add_video (Gtk::Window* float_window)
4430 if (!start_video_server(float_window, false)) {
4431 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4436 add_video_dialog->set_transient_for (*float_window);
4439 if (add_video_dialog->is_visible()) {
4440 /* we're already doing this */
4444 ResponseType r = (ResponseType) add_video_dialog->run ();
4445 add_video_dialog->hide();
4446 if (r != RESPONSE_ACCEPT) { return; }
4448 bool local_file, orig_local_file;
4449 std::string path = add_video_dialog->file_name(local_file);
4451 std::string orig_path = path;
4452 orig_local_file = local_file;
4454 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4456 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4457 warning << string_compose(_("could not open %1"), path) << endmsg;
4460 if (!local_file && path.length() == 0) {
4461 warning << _("no video-file selected") << endmsg;
4465 std::string audio_from_video;
4466 bool detect_ltc = false;
4468 switch (add_video_dialog->import_option()) {
4469 case VTL_IMPORT_TRANSCODE:
4471 TranscodeVideoDialog *transcode_video_dialog;
4472 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4473 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4474 transcode_video_dialog->hide();
4475 if (r != RESPONSE_ACCEPT) {
4476 delete transcode_video_dialog;
4480 audio_from_video = transcode_video_dialog->get_audiofile();
4482 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4485 else if (!audio_from_video.empty()) {
4486 editor->embed_audio_from_video(
4488 video_timeline->get_offset(),
4489 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4492 switch (transcode_video_dialog->import_option()) {
4493 case VTL_IMPORT_TRANSCODED:
4494 path = transcode_video_dialog->get_filename();
4497 case VTL_IMPORT_REFERENCE:
4500 delete transcode_video_dialog;
4503 delete transcode_video_dialog;
4507 case VTL_IMPORT_NONE:
4511 /* strip _session->session_directory().video_path() from video file if possible */
4512 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4513 path=path.substr(_session->session_directory().video_path().size());
4514 if (path.at(0) == G_DIR_SEPARATOR) {
4515 path=path.substr(1);
4519 video_timeline->set_update_session_fps(auto_set_session_fps);
4521 if (video_timeline->video_file_info(path, local_file)) {
4522 XMLNode* node = new XMLNode(X_("Videotimeline"));
4523 node->set_property (X_("Filename"), path);
4524 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4525 node->set_property (X_("LocalFile"), local_file);
4526 if (orig_local_file) {
4527 node->set_property (X_("OriginalVideoFile"), orig_path);
4529 node->remove_property (X_("OriginalVideoFile"));
4531 _session->add_extra_xml (*node);
4532 _session->set_dirty ();
4534 if (!audio_from_video.empty() && detect_ltc) {
4535 std::vector<LTCFileReader::LTCMap> ltc_seq;
4538 /* TODO ask user about TV standard (LTC alignment if any) */
4539 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4540 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4542 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4544 /* TODO seek near end of file, and read LTC until end.
4545 * if it fails to find any LTC frames, scan complete file
4547 * calculate drift of LTC compared to video-duration,
4548 * ask user for reference (timecode from start/mid/end)
4551 // LTCFileReader will have written error messages
4554 ::g_unlink(audio_from_video.c_str());
4556 if (ltc_seq.size() == 0) {
4557 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4559 /* the very first TC in the file is somteimes not aligned properly */
4560 int i = ltc_seq.size() -1;
4561 ARDOUR::frameoffset_t video_start_offset =
4562 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4563 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4564 video_timeline->set_offset(video_start_offset);
4568 _session->maybe_update_session_range(
4569 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4570 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4573 if (add_video_dialog->launch_xjadeo() && local_file) {
4574 editor->set_xjadeo_sensitive(true);
4575 editor->toggle_xjadeo_proc(1);
4577 editor->toggle_xjadeo_proc(0);
4579 editor->toggle_ruler_video(true);
4584 ARDOUR_UI::remove_video ()
4586 video_timeline->close_session();
4587 editor->toggle_ruler_video(false);
4590 video_timeline->set_offset_locked(false);
4591 video_timeline->set_offset(0);
4593 /* delete session state */
4594 XMLNode* node = new XMLNode(X_("Videotimeline"));
4595 _session->add_extra_xml(*node);
4596 node = new XMLNode(X_("Videomonitor"));
4597 _session->add_extra_xml(*node);
4598 node = new XMLNode(X_("Videoexport"));
4599 _session->add_extra_xml(*node);
4600 stop_video_server();
4604 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4606 if (localcacheonly) {
4607 video_timeline->vmon_update();
4609 video_timeline->flush_cache();
4611 editor->queue_visual_videotimeline_update();
4615 ARDOUR_UI::export_video (bool range)
4617 if (ARDOUR::Config->get_show_video_export_info()) {
4618 ExportVideoInfobox infobox (_session);
4619 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4620 if (infobox.show_again()) {
4621 ARDOUR::Config->set_show_video_export_info(false);
4624 case GTK_RESPONSE_YES:
4625 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4631 export_video_dialog->set_session (_session);
4632 export_video_dialog->apply_state(editor->get_selection().time, range);
4633 export_video_dialog->run ();
4634 export_video_dialog->hide ();
4638 ARDOUR_UI::preferences_settings () const
4643 node = _session->instant_xml(X_("Preferences"));
4645 node = Config->instant_xml(X_("Preferences"));
4649 node = new XMLNode (X_("Preferences"));
4656 ARDOUR_UI::mixer_settings () const
4661 node = _session->instant_xml(X_("Mixer"));
4663 node = Config->instant_xml(X_("Mixer"));
4667 node = new XMLNode (X_("Mixer"));
4674 ARDOUR_UI::main_window_settings () const
4679 node = _session->instant_xml(X_("Main"));
4681 node = Config->instant_xml(X_("Main"));
4685 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4686 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4691 node = new XMLNode (X_("Main"));
4698 ARDOUR_UI::editor_settings () const
4703 node = _session->instant_xml(X_("Editor"));
4705 node = Config->instant_xml(X_("Editor"));
4709 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4710 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4715 node = new XMLNode (X_("Editor"));
4722 ARDOUR_UI::keyboard_settings () const
4726 node = Config->extra_xml(X_("Keyboard"));
4729 node = new XMLNode (X_("Keyboard"));
4736 ARDOUR_UI::create_xrun_marker (framepos_t where)
4739 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4740 _session->locations()->add (location);
4745 ARDOUR_UI::halt_on_xrun_message ()
4747 cerr << "HALT on xrun\n";
4748 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4753 ARDOUR_UI::xrun_handler (framepos_t where)
4759 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4761 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4762 create_xrun_marker(where);
4765 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4766 halt_on_xrun_message ();
4771 ARDOUR_UI::disk_overrun_handler ()
4773 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4775 if (!have_disk_speed_dialog_displayed) {
4776 have_disk_speed_dialog_displayed = true;
4777 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4778 The disk system on your computer\n\
4779 was not able to keep up with %1.\n\
4781 Specifically, it failed to write data to disk\n\
4782 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4783 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4789 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4790 static MessageDialog *scan_dlg = NULL;
4791 static ProgressBar *scan_pbar = NULL;
4792 static HBox *scan_tbox = NULL;
4793 static Gtk::Button *scan_timeout_button;
4796 ARDOUR_UI::cancel_plugin_scan ()
4798 PluginManager::instance().cancel_plugin_scan();
4802 ARDOUR_UI::cancel_plugin_timeout ()
4804 PluginManager::instance().cancel_plugin_timeout();
4805 scan_timeout_button->set_sensitive (false);
4809 ARDOUR_UI::plugin_scan_timeout (int timeout)
4811 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4815 scan_pbar->set_sensitive (false);
4816 scan_timeout_button->set_sensitive (true);
4817 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4820 scan_pbar->set_sensitive (false);
4821 scan_timeout_button->set_sensitive (false);
4827 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4829 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4833 const bool cancelled = PluginManager::instance().cancelled();
4834 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4835 if (cancelled && scan_dlg->is_mapped()) {
4840 if (cancelled || !can_cancel) {
4845 static Gtk::Button *cancel_button;
4847 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4848 VBox* vbox = scan_dlg->get_vbox();
4849 vbox->set_size_request(400,-1);
4850 scan_dlg->set_title (_("Scanning for plugins"));
4852 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4853 cancel_button->set_name ("EditorGTKButton");
4854 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4855 cancel_button->show();
4857 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4859 scan_tbox = manage( new HBox() );
4861 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4862 scan_timeout_button->set_name ("EditorGTKButton");
4863 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4864 scan_timeout_button->show();
4866 scan_pbar = manage(new ProgressBar());
4867 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4868 scan_pbar->set_text(_("Scan Timeout"));
4871 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4872 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4874 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4877 assert(scan_dlg && scan_tbox && cancel_button);
4879 if (type == X_("closeme")) {
4883 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4886 if (!can_cancel || !cancelled) {
4887 scan_timeout_button->set_sensitive(false);
4889 cancel_button->set_sensitive(can_cancel && !cancelled);
4895 ARDOUR_UI::gui_idle_handler ()
4898 /* due to idle calls, gtk_events_pending() may always return true */
4899 while (gtk_events_pending() && --timeout) {
4900 gtk_main_iteration ();
4905 ARDOUR_UI::disk_underrun_handler ()
4907 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4909 if (!have_disk_speed_dialog_displayed) {
4910 have_disk_speed_dialog_displayed = true;
4911 MessageDialog* msg = new MessageDialog (
4912 _main_window, string_compose (_("The disk system on your computer\n\
4913 was not able to keep up with %1.\n\
4915 Specifically, it failed to read data from disk\n\
4916 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4917 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4923 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4925 have_disk_speed_dialog_displayed = false;
4930 ARDOUR_UI::session_dialog (std::string msg)
4932 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4936 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4943 ARDOUR_UI::pending_state_dialog ()
4945 HBox* hbox = manage (new HBox());
4946 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4947 ArdourDialog dialog (_("Crash Recovery"), true);
4948 Label message (string_compose (_("\
4949 This session appears to have been in the\n\
4950 middle of recording when %1 or\n\
4951 the computer was shutdown.\n\
4953 %1 can recover any captured audio for\n\
4954 you, or it can ignore it. Please decide\n\
4955 what you would like to do.\n"), PROGRAM_NAME));
4956 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4957 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4958 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4959 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4960 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4961 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4962 dialog.set_default_response (RESPONSE_ACCEPT);
4963 dialog.set_position (WIN_POS_CENTER);
4968 switch (dialog.run ()) {
4969 case RESPONSE_ACCEPT:
4977 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4979 HBox* hbox = new HBox();
4980 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4981 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4982 Label message (string_compose (_("\
4983 This session was created with a sample rate of %1 Hz, but\n\
4984 %2 is currently running at %3 Hz. If you load this session,\n\
4985 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4987 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4988 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4989 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4990 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4991 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4992 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4993 dialog.set_default_response (RESPONSE_ACCEPT);
4994 dialog.set_position (WIN_POS_CENTER);
4999 switch (dialog.run()) {
5000 case RESPONSE_ACCEPT:
5010 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5012 MessageDialog msg (string_compose (_("\
5013 This session was created with a sample rate of %1 Hz, but\n\
5014 %2 is currently running at %3 Hz.\n\
5015 Audio will be recorded and played at the wrong sample rate.\n\
5016 Re-Configure the Audio Engine in\n\
5017 Menu > Window > Audio/Midi Setup"),
5018 desired, PROGRAM_NAME, actual),
5020 Gtk::MESSAGE_WARNING);
5025 ARDOUR_UI::use_config ()
5027 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5029 set_transport_controllable_state (*node);
5034 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5036 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5037 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5039 primary_clock->set (pos);
5042 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5043 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5045 secondary_clock->set (pos);
5048 if (big_clock_window) {
5049 big_clock->set (pos);
5051 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5055 ARDOUR_UI::step_edit_status_change (bool yn)
5057 // XXX should really store pre-step edit status of things
5058 // we make insensitive
5061 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5062 rec_button.set_sensitive (false);
5064 rec_button.unset_active_state ();;
5065 rec_button.set_sensitive (true);
5070 ARDOUR_UI::record_state_changed ()
5072 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5075 /* why bother - the clock isn't visible */
5079 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5081 if (big_clock_window) {
5082 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5083 big_clock->set_active (true);
5085 big_clock->set_active (false);
5092 ARDOUR_UI::first_idle ()
5095 _session->allow_auto_play (true);
5099 editor->first_idle();
5102 Keyboard::set_can_save_keybindings (true);
5107 ARDOUR_UI::store_clock_modes ()
5109 XMLNode* node = new XMLNode(X_("ClockModes"));
5111 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5112 XMLNode* child = new XMLNode (X_("Clock"));
5114 child->set_property (X_("name"), (*x)->name());
5115 child->set_property (X_("mode"), (*x)->mode());
5116 child->set_property (X_("on"), (*x)->on());
5118 node->add_child_nocopy (*child);
5121 _session->add_extra_xml (*node);
5122 _session->set_dirty ();
5125 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5126 : Controllable (name), ui (u), type(tp)
5132 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5135 /* do nothing: these are radio-style actions */
5139 const char *action = 0;
5143 action = X_("Roll");
5146 action = X_("Stop");
5149 action = X_("GotoStart");
5152 action = X_("GotoEnd");
5155 action = X_("Loop");
5158 action = X_("PlaySelection");
5161 action = X_("Record");
5171 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5179 ARDOUR_UI::TransportControllable::get_value (void) const
5206 ARDOUR_UI::setup_profile ()
5208 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5209 Profile->set_small_screen ();
5212 if (g_getenv ("TRX")) {
5213 Profile->set_trx ();
5216 if (g_getenv ("MIXBUS")) {
5217 Profile->set_mixbus ();
5222 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5224 MissingFileDialog dialog (s, str, type);
5229 int result = dialog.run ();
5236 return 1; // quit entire session load
5239 result = dialog.get_action ();
5245 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5247 AmbiguousFileDialog dialog (file, hits);
5254 return dialog.get_which ();
5257 /** Allocate our thread-local buffers */
5259 ARDOUR_UI::get_process_buffers ()
5261 _process_thread->get_buffers ();
5264 /** Drop our thread-local buffers */
5266 ARDOUR_UI::drop_process_buffers ()
5268 _process_thread->drop_buffers ();
5272 ARDOUR_UI::feedback_detected ()
5274 _feedback_exists = true;
5278 ARDOUR_UI::successful_graph_sort ()
5280 _feedback_exists = false;
5284 ARDOUR_UI::midi_panic ()
5287 _session->midi_panic();
5292 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5294 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5295 const char* end_big = "</span>";
5296 const char* start_mono = "<tt>";
5297 const char* end_mono = "</tt>";
5299 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5300 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5301 "From now on, use the backup copy with older versions of %3"),
5302 xml_path, backup_path, PROGRAM_NAME,
5304 start_mono, end_mono), true);
5310 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5312 using namespace Menu_Helpers;
5314 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5315 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5316 i->set_active (editor_meter->meter_type () == type);
5320 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5322 using namespace Gtk::Menu_Helpers;
5324 Gtk::Menu* m = manage (new Menu);
5325 MenuList& items = m->items ();
5327 RadioMenuItem::Group group;
5329 _suspend_editor_meter_callbacks = true;
5330 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5331 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5332 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5333 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5334 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5335 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5336 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5337 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5338 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5339 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5340 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5342 m->popup (ev->button, ev->time);
5343 _suspend_editor_meter_callbacks = false;
5347 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5349 if (ev->button == 3 && editor_meter) {
5350 popup_editor_meter_menu (ev);
5357 ARDOUR_UI::reset_peak_display ()
5359 if (!_session || !_session->master_out() || !editor_meter) return;
5360 editor_meter->clear_meters();
5361 editor_meter_max_peak = -INFINITY;
5362 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5366 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5368 if (!_session || !_session->master_out()) return;
5369 if (group == _session->master_out()->route_group()) {
5370 reset_peak_display ();
5375 ARDOUR_UI::reset_route_peak_display (Route* route)
5377 if (!_session || !_session->master_out()) return;
5378 if (_session->master_out().get() == route) {
5379 reset_peak_display ();
5384 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5386 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5387 audio_midi_setup->set_position (WIN_POS_CENTER);
5389 if (desired_sample_rate != 0) {
5390 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5391 audio_midi_setup->try_autostart ();
5392 if (ARDOUR::AudioEngine::instance()->running()) {
5399 int response = audio_midi_setup->run();
5400 printf("RESPONSE %d\n", response);
5402 case Gtk::RESPONSE_DELETE_EVENT:
5405 if (!AudioEngine::instance()->running()) {
5408 audio_midi_setup->hide ();
5416 ARDOUR_UI::transport_numpad_timeout ()
5418 _numpad_locate_happening = false;
5419 if (_numpad_timeout_connection.connected() )
5420 _numpad_timeout_connection.disconnect();
5425 ARDOUR_UI::transport_numpad_decimal ()
5427 _numpad_timeout_connection.disconnect();
5429 if (_numpad_locate_happening) {
5430 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5431 _numpad_locate_happening = false;
5433 _pending_locate_num = 0;
5434 _numpad_locate_happening = true;
5435 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5440 ARDOUR_UI::transport_numpad_event (int num)
5442 if ( _numpad_locate_happening ) {
5443 _pending_locate_num = _pending_locate_num*10 + num;
5446 case 0: toggle_roll(false, false); break;
5447 case 1: transport_rewind(1); break;
5448 case 2: transport_forward(1); break;
5449 case 3: transport_record(true); break;
5450 case 4: toggle_session_auto_loop(); break;
5451 case 5: transport_record(false); toggle_session_auto_loop(); break;
5452 case 6: toggle_punch(); break;
5453 case 7: toggle_click(); break;
5454 case 8: toggle_auto_return(); break;
5455 case 9: toggle_follow_edits(); break;
5461 ARDOUR_UI::set_flat_buttons ()
5463 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5467 ARDOUR_UI::audioengine_became_silent ()
5469 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5471 Gtk::MESSAGE_WARNING,
5475 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5477 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5478 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5479 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5480 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5481 Gtk::HBox pay_button_box;
5482 Gtk::HBox subscribe_button_box;
5484 pay_button_box.pack_start (pay_button, true, false);
5485 subscribe_button_box.pack_start (subscribe_button, true, false);
5487 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 */
5489 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5490 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5492 msg.get_vbox()->pack_start (pay_label);
5493 msg.get_vbox()->pack_start (pay_button_box);
5494 msg.get_vbox()->pack_start (subscribe_label);
5495 msg.get_vbox()->pack_start (subscribe_button_box);
5497 msg.get_vbox()->show_all ();
5499 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5500 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5501 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5506 case Gtk::RESPONSE_YES:
5507 AudioEngine::instance()->reset_silence_countdown ();
5510 case Gtk::RESPONSE_NO:
5512 save_state_canfail ("");
5516 case Gtk::RESPONSE_CANCEL:
5518 /* don't reset, save session and exit */
5524 ARDOUR_UI::hide_application ()
5526 Application::instance ()-> hide ();
5530 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5532 /* icons, titles, WM stuff */
5534 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5536 if (window_icons.empty()) {
5537 Glib::RefPtr<Gdk::Pixbuf> icon;
5538 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5539 window_icons.push_back (icon);
5541 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5542 window_icons.push_back (icon);
5544 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5545 window_icons.push_back (icon);
5547 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5548 window_icons.push_back (icon);
5552 if (!window_icons.empty()) {
5553 window.set_default_icon_list (window_icons);
5556 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5558 if (!name.empty()) {
5562 window.set_title (title.get_string());
5563 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5565 window.set_flags (CAN_FOCUS);
5566 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5568 /* This is a hack to ensure that GTK-accelerators continue to
5569 * work. Once we switch over to entirely native bindings, this will be
5570 * unnecessary and should be removed
5572 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5574 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5575 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5576 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5577 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5581 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5583 Gtkmm2ext::Bindings* bindings = 0;
5584 Gtk::Window* window = 0;
5586 /* until we get ardour bindings working, we are not handling key
5590 if (ev->type != GDK_KEY_PRESS) {
5594 if (event_window == &_main_window) {
5596 window = event_window;
5598 /* find current tab contents */
5600 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5602 /* see if it uses the ardour binding system */
5605 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5608 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5612 window = event_window;
5614 /* see if window uses ardour binding system */
5616 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5619 /* An empty binding set is treated as if it doesn't exist */
5621 if (bindings && bindings->empty()) {
5625 return key_press_focus_accelerator_handler (*window, ev, bindings);
5628 static Gtkmm2ext::Bindings*
5629 get_bindings_from_widget_heirarchy (GtkWidget** w)
5634 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5637 *w = gtk_widget_get_parent (*w);
5640 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5644 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5646 GtkWindow* win = window.gobj();
5647 GtkWidget* focus = gtk_window_get_focus (win);
5648 GtkWidget* binding_widget = focus;
5649 bool special_handling_of_unmodified_accelerators = false;
5650 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5654 /* some widget has keyboard focus */
5656 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5658 /* A particular kind of focusable widget currently has keyboard
5659 * focus. All unmodified key events should go to that widget
5660 * first and not be used as an accelerator by default
5663 special_handling_of_unmodified_accelerators = true;
5667 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5668 if (focus_bindings) {
5669 bindings = focus_bindings;
5670 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5675 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",
5678 Gtkmm2ext::show_gdk_event_state (ev->state),
5679 special_handling_of_unmodified_accelerators,
5680 Keyboard::some_magic_widget_has_focus(),
5682 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5683 ((ev->state & mask) ? "yes" : "no"),
5684 window.get_title()));
5686 /* This exists to allow us to override the way GTK handles
5687 key events. The normal sequence is:
5689 a) event is delivered to a GtkWindow
5690 b) accelerators/mnemonics are activated
5691 c) if (b) didn't handle the event, propagate to
5692 the focus widget and/or focus chain
5694 The problem with this is that if the accelerators include
5695 keys without modifiers, such as the space bar or the
5696 letter "e", then pressing the key while typing into
5697 a text entry widget results in the accelerator being
5698 activated, instead of the desired letter appearing
5701 There is no good way of fixing this, but this
5702 represents a compromise. The idea is that
5703 key events involving modifiers (not Shift)
5704 get routed into the activation pathway first, then
5705 get propagated to the focus widget if necessary.
5707 If the key event doesn't involve modifiers,
5708 we deliver to the focus widget first, thus allowing
5709 it to get "normal text" without interference
5712 Of course, this can also be problematic: if there
5713 is a widget with focus, then it will swallow
5714 all "normal text" accelerators.
5718 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5720 /* no special handling or there are modifiers in effect: accelerate first */
5722 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5723 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5724 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5726 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5727 KeyboardKey k (ev->state, ev->keyval);
5731 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5733 if (bindings->activate (k, Bindings::Press)) {
5734 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5738 if (binding_widget) {
5739 binding_widget = gtk_widget_get_parent (binding_widget);
5740 if (binding_widget) {
5741 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5750 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5752 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5753 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5757 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5759 if (gtk_window_propagate_key_event (win, ev)) {
5760 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5766 /* no modifiers, propagate first */
5768 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5770 if (gtk_window_propagate_key_event (win, ev)) {
5771 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5775 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5776 KeyboardKey k (ev->state, ev->keyval);
5780 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5783 if (bindings->activate (k, Bindings::Press)) {
5784 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5788 if (binding_widget) {
5789 binding_widget = gtk_widget_get_parent (binding_widget);
5790 if (binding_widget) {
5791 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5800 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5802 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5803 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5808 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5813 ARDOUR_UI::load_bindings ()
5815 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5816 error << _("Global keybindings are missing") << endmsg;
5821 ARDOUR_UI::cancel_solo ()
5824 _session->cancel_all_solo ();
5829 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5831 /* this resets focus to the first focusable parent of the given widget,
5832 * or, if there is no focusable parent, cancels focus in the toplevel
5833 * window that the given widget is packed into (if there is one).
5840 Gtk::Widget* top = w->get_toplevel();
5842 if (!top || !top->is_toplevel()) {
5846 w = w->get_parent ();
5850 if (w->is_toplevel()) {
5851 /* Setting the focus widget to a Gtk::Window causes all
5852 * subsequent calls to ::has_focus() on the nominal
5853 * focus widget in that window to return
5854 * false. Workaround: never set focus to the toplevel
5860 if (w->get_can_focus ()) {
5861 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5862 win->set_focus (*w);
5865 w = w->get_parent ();
5868 if (top == &_main_window) {
5872 /* no focusable parent found, cancel focus in top level window.
5873 C++ API cannot be used for this. Thanks, references.
5876 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);