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/accelmap.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/uimanager.h>
55 #include "pbd/error.h"
56 #include "pbd/basename.h"
57 #include "pbd/compose.h"
58 #include "pbd/convert.h"
59 #include "pbd/failed_constructor.h"
60 #include "pbd/file_archive.h"
61 #include "pbd/enumwriter.h"
62 #include "pbd/memento_command.h"
63 #include "pbd/openuri.h"
64 #include "pbd/stl_delete.h"
65 #include "pbd/types_convert.h"
66 #include "pbd/unwind.h"
67 #include "pbd/file_utils.h"
68 #include "pbd/localtime_r.h"
69 #include "pbd/pthread_utils.h"
70 #include "pbd/replace_all.h"
71 #include "pbd/scoped_file_descriptor.h"
72 #include "pbd/xml++.h"
74 #include "gtkmm2ext/application.h"
75 #include "gtkmm2ext/bindings.h"
76 #include "gtkmm2ext/gtk_ui.h"
77 #include "gtkmm2ext/utils.h"
78 #include "gtkmm2ext/window_title.h"
80 #include "widgets/fastmeter.h"
81 #include "widgets/prompter.h"
82 #include "widgets/tooltips.h"
84 #include "ardour/ardour.h"
85 #include "ardour/audio_backend.h"
86 #include "ardour/audio_track.h"
87 #include "ardour/audioengine.h"
88 #include "ardour/audiofilesource.h"
89 #include "ardour/automation_watch.h"
90 #include "ardour/disk_reader.h"
91 #include "ardour/disk_writer.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/filesystem_paths.h"
94 #include "ardour/ltc_file_reader.h"
95 #include "ardour/midi_track.h"
96 #include "ardour/port.h"
97 #include "ardour/plugin_manager.h"
98 #include "ardour/process_thread.h"
99 #include "ardour/profile.h"
100 #include "ardour/recent_sessions.h"
101 #include "ardour/record_enable_control.h"
102 #include "ardour/revision.h"
103 #include "ardour/session_directory.h"
104 #include "ardour/session_route.h"
105 #include "ardour/session_state_utils.h"
106 #include "ardour/session_utils.h"
107 #include "ardour/source_factory.h"
108 #include "ardour/transport_master.h"
109 #include "ardour/transport_master_manager.h"
110 #include "ardour/system_exec.h"
111 #include "ardour/track.h"
112 #include "ardour/vca_manager.h"
113 #include "ardour/utils.h"
115 #include "LuaBridge/LuaBridge.h"
117 #ifdef WINDOWS_VST_SUPPORT
120 #ifdef AUDIOUNIT_SUPPORT
121 #include "ardour/audio_unit.h"
124 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
129 #include "temporal/time.h"
131 typedef uint64_t microseconds_t;
135 #include "enums_convert.h"
137 #include "add_route_dialog.h"
138 #include "ambiguous_file_dialog.h"
139 #include "ardour_ui.h"
140 #include "audio_clock.h"
141 #include "audio_region_view.h"
142 #include "big_clock_window.h"
143 #include "big_transport_window.h"
144 #include "bundle_manager.h"
145 #include "duplicate_routes_dialog.h"
147 #include "engine_dialog.h"
148 #include "export_video_dialog.h"
149 #include "export_video_infobox.h"
150 #include "gain_meter.h"
151 #include "global_port_matrix.h"
152 #include "gui_object.h"
153 #include "gui_thread.h"
154 #include "idleometer.h"
155 #include "keyboard.h"
156 #include "keyeditor.h"
157 #include "location_ui.h"
158 #include "lua_script_manager.h"
159 #include "luawindow.h"
160 #include "main_clock.h"
161 #include "missing_file_dialog.h"
162 #include "missing_plugin_dialog.h"
163 #include "mixer_ui.h"
164 #include "meterbridge.h"
165 #include "meter_patterns.h"
166 #include "mouse_cursors.h"
169 #include "pingback.h"
170 #include "plugin_dspload_window.h"
171 #include "processor_box.h"
172 #include "public_editor.h"
173 #include "rc_option_editor.h"
174 #include "route_time_axis.h"
175 #include "route_params_ui.h"
176 #include "save_as_dialog.h"
177 #include "save_template_dialog.h"
178 #include "script_selector.h"
179 #include "session_archive_dialog.h"
180 #include "session_dialog.h"
181 #include "session_metadata_dialog.h"
182 #include "session_option_editor.h"
183 #include "speaker_dialog.h"
186 #include "template_dialog.h"
187 #include "time_axis_view_item.h"
188 #include "time_info_box.h"
190 #include "transport_masters_dialog.h"
192 #include "utils_videotl.h"
193 #include "video_server_dialog.h"
194 #include "add_video_dialog.h"
195 #include "transcode_video_dialog.h"
197 #include "pbd/i18n.h"
199 using namespace ARDOUR;
200 using namespace ARDOUR_UI_UTILS;
202 using namespace Gtkmm2ext;
203 using namespace ArdourWidgets;
206 using namespace Editing;
208 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
210 sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
211 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
214 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
216 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
217 "Would you like these files to be copied and used for %1 %2.x?\n\n"
218 "(This will require you to restart %1.)"),
219 PROGRAM_NAME, PROGRAM_VERSION, version),
220 false, /* no markup */
223 true /* modal, though it hardly matters since it is the only window */
226 msg.set_default_response (Gtk::RESPONSE_YES);
229 return (msg.run() == Gtk::RESPONSE_YES);
233 libxml_generic_error_func (void* /* parsing_context*/,
241 vsnprintf (buf, sizeof (buf), msg, ap);
242 error << buf << endmsg;
247 libxml_structured_error_func (void* /* parsing_context*/,
255 replace_all (msg, "\n", "");
258 if (err->file && err->line) {
259 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
262 error << ':' << err->int2;
267 error << X_("XML error: ") << msg << endmsg;
273 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
274 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
275 , session_loaded (false)
276 , session_load_in_progress (false)
277 , gui_object_state (new GUIObjectState)
278 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
279 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
280 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
282 , global_actions (X_("global"))
283 , ignore_dual_punch (false)
284 , main_window_visibility (0)
289 , _mixer_on_top (false)
290 , _initial_verbose_plugin_scan (false)
291 , first_time_engine_run (true)
292 , secondary_clock_spacer (0)
293 , auto_input_button (ArdourButton::led_default_elements)
295 , auto_return_button (ArdourButton::led_default_elements)
296 , follow_edits_button (ArdourButton::led_default_elements)
297 , auditioning_alert_button (_("Audition"))
298 , solo_alert_button (_("Solo"))
299 , feedback_alert_button (_("Feedback"))
300 , error_alert_button ( ArdourButton::just_led_default_elements )
301 , editor_meter_peak_display()
303 , _suspend_editor_meter_callbacks (false)
304 , _numpad_locate_happening (false)
305 , _session_is_new (false)
306 , last_key_press_time (0)
310 , rc_option_editor (0)
311 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
312 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
313 , about (X_("about"), _("About"))
314 , location_ui (X_("locations"), S_("Ranges|Locations"))
315 , route_params (X_("inspector"), _("Tracks and Busses"))
316 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
317 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
318 , lua_script_window (X_("script-manager"), _("Script Manager"))
319 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
320 , plugin_dsp_load_window (X_("plugin-dsp-load"), _("Plugin DSP Load"))
321 , transport_masters_window (X_("transport-masters"), _("Transport Masters"))
322 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
323 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
324 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
325 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
326 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
327 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
328 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
329 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
330 , video_server_process (0)
332 , have_configure_timeout (false)
333 , last_configure_time (0)
335 , have_disk_speed_dialog_displayed (false)
336 , _status_bar_visibility (X_("status-bar"))
337 , _feedback_exists (false)
338 , _log_not_acknowledged (LogLevelNone)
339 , duplicate_routes_dialog (0)
340 , editor_visibility_button (S_("Window|Editor"))
341 , mixer_visibility_button (S_("Window|Mixer"))
342 , prefs_visibility_button (S_("Window|Preferences"))
344 Gtkmm2ext::init (localedir);
346 UIConfiguration::instance().post_gui_init ();
348 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
350 /* "touch" the been-here-before path now that config has been migrated */
351 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
353 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
355 /* configuration was modified, exit immediately */
360 if (string (VERSIONSTRING).find (".pre") != string::npos) {
361 /* check this is not being run from ./ardev etc. */
362 if (!running_from_source_tree ()) {
363 pre_release_dialog ();
367 if (theArdourUI == 0) {
371 /* track main window visibility */
373 main_window_visibility = new VisibilityTracker (_main_window);
375 /* stop libxml from spewing to stdout/stderr */
377 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
378 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
380 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
381 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
382 UIConfiguration::instance().map_parameters (pc);
384 transport_ctrl.setup (this);
386 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
387 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
389 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
391 /* handle dialog requests */
393 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
395 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
397 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
399 /* handle Audio/MIDI setup when session requires it */
401 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
403 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
405 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
407 /* handle sr mismatch with a dialog - cross-thread from engine */
408 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
410 /* handle requests to quit (coming from JACK session) */
412 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
414 /* tell the user about feedback */
416 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
417 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
419 /* handle requests to deal with missing files */
421 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
423 /* and ambiguous files */
425 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
427 /* also plugin scan messages */
428 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
429 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
431 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
433 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
436 /* lets get this party started */
438 setup_gtk_ardour_enums ();
441 SessionEvent::create_per_thread_pool ("GUI", 4096);
443 /* we like keyboards */
445 keyboard = new ArdourKeyboard(*this);
447 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
449 keyboard->set_state (*node, Stateful::loading_state_version);
452 UIConfiguration::instance().reset_dpi ();
454 TimeAxisViewItem::set_constant_heights ();
456 /* Set this up so that our window proxies can register actions */
458 ActionManager::init ();
460 /* The following must happen after ARDOUR::init() so that Config is set up */
462 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
465 key_editor.set_state (*ui_xml, 0);
466 session_option_editor.set_state (*ui_xml, 0);
467 speaker_config_window.set_state (*ui_xml, 0);
468 about.set_state (*ui_xml, 0);
469 add_route_dialog.set_state (*ui_xml, 0);
470 add_video_dialog.set_state (*ui_xml, 0);
471 route_params.set_state (*ui_xml, 0);
472 bundle_manager.set_state (*ui_xml, 0);
473 location_ui.set_state (*ui_xml, 0);
474 big_clock_window.set_state (*ui_xml, 0);
475 big_transport_window.set_state (*ui_xml, 0);
476 audio_port_matrix.set_state (*ui_xml, 0);
477 midi_port_matrix.set_state (*ui_xml, 0);
478 export_video_dialog.set_state (*ui_xml, 0);
479 lua_script_window.set_state (*ui_xml, 0);
480 idleometer.set_state (*ui_xml, 0);
481 plugin_dsp_load_window.set_state (*ui_xml, 0);
482 transport_masters_window.set_state (*ui_xml, 0);
485 /* Separate windows */
487 WM::Manager::instance().register_window (&key_editor);
488 WM::Manager::instance().register_window (&session_option_editor);
489 WM::Manager::instance().register_window (&speaker_config_window);
490 WM::Manager::instance().register_window (&about);
491 WM::Manager::instance().register_window (&add_route_dialog);
492 WM::Manager::instance().register_window (&add_video_dialog);
493 WM::Manager::instance().register_window (&route_params);
494 WM::Manager::instance().register_window (&audio_midi_setup);
495 WM::Manager::instance().register_window (&export_video_dialog);
496 WM::Manager::instance().register_window (&lua_script_window);
497 WM::Manager::instance().register_window (&bundle_manager);
498 WM::Manager::instance().register_window (&location_ui);
499 WM::Manager::instance().register_window (&big_clock_window);
500 WM::Manager::instance().register_window (&big_transport_window);
501 WM::Manager::instance().register_window (&audio_port_matrix);
502 WM::Manager::instance().register_window (&midi_port_matrix);
503 WM::Manager::instance().register_window (&idleometer);
504 WM::Manager::instance().register_window (&plugin_dsp_load_window);
505 WM::Manager::instance().register_window (&transport_masters_window);
507 /* do not retain position for add route dialog */
508 add_route_dialog.set_state_mask (WindowProxy::Size);
510 /* Trigger setting up the color scheme and loading the GTK RC file */
512 UIConfiguration::instance().load_rc_file (false);
514 _process_thread = new ProcessThread ();
515 _process_thread->init ();
517 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
523 ARDOUR_UI::pre_release_dialog ()
525 ArdourDialog d (_("Pre-Release Warning"), true, false);
526 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
528 Label* label = manage (new Label);
529 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
530 There are still several issues and bugs to be worked on,\n\
531 as well as general workflow improvements, before this can be considered\n\
532 release software. So, a few guidelines:\n\
534 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
535 though it may be so, depending on your workflow.\n\
536 2) Please wait for a helpful writeup of new features.\n\
537 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
538 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
539 making sure to note the product version number as 6.0-pre.\n\
540 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
541 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
542 can get there directly from within the program via the Help->Chat menu option.\n\
544 Full information on all the above can be found on the support page at\n\
546 http://ardour.org/support\n\
547 "), PROGRAM_NAME, VERSIONSTRING));
549 d.get_vbox()->set_border_width (12);
550 d.get_vbox()->pack_start (*label, false, false, 12);
551 d.get_vbox()->show_all ();
556 GlobalPortMatrixWindow*
557 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
562 return new GlobalPortMatrixWindow (_session, type);
566 ARDOUR_UI::attach_to_engine ()
568 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
569 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
573 ARDOUR_UI::engine_stopped ()
575 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
576 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
577 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
578 update_sample_rate (0);
583 ARDOUR_UI::engine_running ()
585 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
586 if (first_time_engine_run) {
588 first_time_engine_run = false;
592 _session->reset_xrun_count ();
594 update_disk_space ();
596 update_sample_rate (AudioEngine::instance()->sample_rate());
597 update_timecode_format ();
598 update_peak_thread_work ();
599 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
600 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
604 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
606 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
607 /* we can't rely on the original string continuing to exist when we are called
608 again in the GUI thread, so make a copy and note that we need to
611 char *copy = strdup (reason);
612 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
616 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
617 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
619 update_sample_rate (0);
623 /* if the reason is a non-empty string, it means that the backend was shutdown
624 rather than just Ardour.
627 if (strlen (reason)) {
628 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
630 msgstr = string_compose (_("\
631 The audio backend has either been shutdown or it\n\
632 disconnected %1 because %1\n\
633 was not fast enough. Try to restart\n\
634 the audio backend and save the session."), PROGRAM_NAME);
637 MessageDialog msg (_main_window, msgstr);
638 pop_back_splash (msg);
642 free (const_cast<char*> (reason));
647 ARDOUR_UI::post_engine ()
649 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
651 #ifdef AUDIOUNIT_SUPPORT
653 if (AUPluginInfo::au_get_crashlog(au_msg)) {
654 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
655 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
656 info << au_msg << endmsg;
660 ARDOUR::init_post_engine ();
662 /* connect to important signals */
664 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
665 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
666 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
667 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
668 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
670 if (setup_windows ()) {
671 throw failed_constructor ();
674 transport_ctrl.map_actions ();
676 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
677 XMLNode* n = Config->extra_xml (X_("UI"));
679 _status_bar_visibility.set_state (*n);
682 check_memory_locking();
684 /* this is the first point at which all the possible actions are
685 * available, because some of the available actions are dependent on
686 * aspects of the engine/backend.
689 if (ARDOUR_COMMAND_LINE::show_key_actions) {
691 Bindings::save_all_bindings_as_html (sstr);
693 if (sstr.str().empty()) {
700 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
702 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
708 #ifdef PLATFORM_WINDOWS
714 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
715 #ifndef PLATFORM_WINDOWS
718 g_unlink (file_name);
720 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
726 #ifndef PLATFORM_WINDOWS
730 PBD::open_uri (string_compose ("file:///%1", file_name));
732 halt_connection.disconnect ();
733 AudioEngine::instance()->stop ();
738 if (ARDOUR_COMMAND_LINE::show_actions) {
741 vector<string> paths;
742 vector<string> labels;
743 vector<string> tooltips;
745 vector<Glib::RefPtr<Gtk::Action> > actions;
746 string ver_in = revision;
747 string ver = ver_in.substr(0, ver_in.find("-"));
750 output << "\n<h2>Menu actions</h2>" << endl;
751 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
752 output << " surfaces or scripts.\n</p>\n" << endl;
753 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
754 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
755 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
756 output << "<table class=\"dl\">\n <thead>" << endl;
757 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
758 output << " </thead>\n <tbody>" << endl;
760 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
762 vector<string>::iterator p;
763 vector<string>::iterator l;
765 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
766 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (10, string::npos);
767 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
769 output << " </tbody>\n </table>" << endl;
771 // output this mess to a browser for easiest X-platform use
772 // it is not pretty HTML, but it works and it's main purpose
773 // is to create raw html to fit in Ardour's manual with no editing
778 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
780 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
786 #ifdef PLATFORM_WINDOWS
792 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
793 #ifndef PLATFORM_WINDOWS
796 g_unlink (file_name);
798 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
804 #ifndef PLATFORM_WINDOWS
808 PBD::open_uri (string_compose ("file:///%1", file_name));
810 halt_connection.disconnect ();
811 AudioEngine::instance()->stop ();
815 /* this being a GUI and all, we want peakfiles */
817 AudioFileSource::set_build_peakfiles (true);
818 AudioFileSource::set_build_missing_peakfiles (true);
820 /* set default clock modes */
822 primary_clock->set_mode (AudioClock::Timecode);
823 secondary_clock->set_mode (AudioClock::BBT);
825 /* start the time-of-day-clock */
828 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
829 update_wall_clock ();
830 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
835 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
836 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
837 Config->map_parameters (pc);
839 UIConfiguration::instance().map_parameters (pc);
843 ARDOUR_UI::~ARDOUR_UI ()
845 UIConfiguration::instance().save_state();
849 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
850 // don't bother at 'real' exit. the OS cleans up for us.
851 delete big_clock; big_clock = 0;
852 delete primary_clock; primary_clock = 0;
853 delete secondary_clock; secondary_clock = 0;
854 delete _process_thread; _process_thread = 0;
855 delete time_info_box; time_info_box = 0;
856 delete meterbridge; meterbridge = 0;
857 delete luawindow; luawindow = 0;
858 delete editor; editor = 0;
859 delete mixer; mixer = 0;
860 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
862 delete gui_object_state; gui_object_state = 0;
863 delete main_window_visibility;
864 FastMeter::flush_pattern_cache ();
865 ArdourFader::flush_pattern_cache ();
869 /* Small trick to flush main-thread event pool.
870 * Other thread-pools are destroyed at pthread_exit(),
871 * but tmain thread termination is too late to trigger Pool::~Pool()
873 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.
874 delete ev->event_pool();
879 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
881 if (Splash::instance()) {
882 Splash::instance()->pop_back_for (win);
887 ARDOUR_UI::configure_timeout ()
889 if (last_configure_time == 0) {
890 /* no configure events yet */
894 /* force a gap of 0.5 seconds since the last configure event
897 if (get_microseconds() - last_configure_time < 500000) {
900 have_configure_timeout = false;
901 save_ardour_state ();
907 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
909 if (have_configure_timeout) {
910 last_configure_time = get_microseconds();
912 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
913 have_configure_timeout = true;
920 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
924 if (node.get_property ("roll", str)){
925 roll_controllable->set_id (str);
927 if (node.get_property ("stop", str)) {
928 stop_controllable->set_id (str);
930 if (node.get_property ("goto-start", str)) {
931 goto_start_controllable->set_id (str);
933 if (node.get_property ("goto-end", str)) {
934 goto_end_controllable->set_id (str);
936 if (node.get_property ("auto-loop", str)) {
937 auto_loop_controllable->set_id (str);
939 if (node.get_property ("play-selection", str)) {
940 play_selection_controllable->set_id (str);
942 if (node.get_property ("rec", str)) {
943 rec_controllable->set_id (str);
945 if (node.get_property ("shuttle", str)) {
946 shuttle_box.controllable()->set_id (str);
951 ARDOUR_UI::get_transport_controllable_state ()
953 XMLNode* node = new XMLNode(X_("TransportControllables"));
955 node->set_property (X_("roll"), roll_controllable->id());
956 node->set_property (X_("stop"), stop_controllable->id());
957 node->set_property (X_("goto-start"), goto_start_controllable->id());
958 node->set_property (X_("goto-end"), goto_end_controllable->id());
959 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
960 node->set_property (X_("play-selection"), play_selection_controllable->id());
961 node->set_property (X_("rec"), rec_controllable->id());
962 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
968 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
971 _session->save_state (snapshot_name);
976 ARDOUR_UI::autosave_session ()
978 if (g_main_depth() > 1) {
979 /* inside a recursive main loop,
980 give up because we may not be able to
986 if (!Config->get_periodic_safety_backups()) {
991 _session->maybe_write_autosave();
998 ARDOUR_UI::session_dirty_changed ()
1005 ARDOUR_UI::update_autosave ()
1007 if (_session && _session->dirty()) {
1008 if (_autosave_connection.connected()) {
1009 _autosave_connection.disconnect();
1012 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1013 Config->get_periodic_safety_backup_interval() * 1000);
1016 if (_autosave_connection.connected()) {
1017 _autosave_connection.disconnect();
1023 ARDOUR_UI::check_announcements ()
1026 string _annc_filename;
1029 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1030 #elif defined PLATFORM_WINDOWS
1031 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1033 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1035 _annc_filename.append (VERSIONSTRING);
1037 _announce_string = "";
1039 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1040 FILE* fin = g_fopen (path.c_str(), "rb");
1042 while (!feof (fin)) {
1045 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1048 _announce_string.append (tmp, len);
1053 pingback (VERSIONSTRING, path);
1058 _hide_splash (gpointer arg)
1060 ((ARDOUR_UI*)arg)->hide_splash();
1065 ARDOUR_UI::starting ()
1067 Application* app = Application::instance ();
1068 const char *nsm_url;
1069 bool brand_new_user = ArdourStartup::required ();
1071 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1072 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1074 if (ARDOUR_COMMAND_LINE::check_announcements) {
1075 check_announcements ();
1080 /* we need to create this early because it may need to set the
1081 * audio backend end up.
1085 audio_midi_setup.get (true);
1087 std::cerr << "audio-midi engine setup failed."<< std::endl;
1091 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1092 nsm = new NSM_Client;
1093 if (!nsm->init (nsm_url)) {
1094 /* the ardour executable may have different names:
1096 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1097 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1098 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1100 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1102 const char *process_name = g_getenv ("ARDOUR_SELF");
1103 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1106 // wait for announce reply from nsm server
1107 for ( i = 0; i < 5000; ++i) {
1111 if (nsm->is_active()) {
1116 error << _("NSM server did not announce itself") << endmsg;
1119 // wait for open command from nsm server
1120 for ( i = 0; i < 5000; ++i) {
1122 Glib::usleep (1000);
1123 if (nsm->client_id ()) {
1129 error << _("NSM: no client ID provided") << endmsg;
1133 if (_session && nsm) {
1134 _session->set_nsm_state( nsm->is_active() );
1136 error << _("NSM: no session created") << endmsg;
1140 // nsm requires these actions disabled
1141 vector<string> action_names;
1142 action_names.push_back("SaveAs");
1143 action_names.push_back("Rename");
1144 action_names.push_back("New");
1145 action_names.push_back("Open");
1146 action_names.push_back("Recent");
1147 action_names.push_back("Close");
1149 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1150 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1152 act->set_sensitive (false);
1159 error << _("NSM: initialization failed") << endmsg;
1165 if (brand_new_user) {
1166 _initial_verbose_plugin_scan = true;
1171 _initial_verbose_plugin_scan = false;
1172 switch (s.response ()) {
1173 case Gtk::RESPONSE_OK:
1180 // TODO: maybe IFF brand_new_user
1181 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1182 std::string dspd (Config->get_default_session_parent_dir());
1183 Searchpath ds (ARDOUR::ardour_data_search_path());
1184 ds.add_subdirectory_to_paths ("sessions");
1185 vector<string> demos;
1186 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1188 ARDOUR::RecentSessions rs;
1189 ARDOUR::read_recent_sessions (rs);
1191 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1192 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1193 std::string name = basename_nosuffix (basename_nosuffix (*i));
1194 std::string path = Glib::build_filename (dspd, name);
1195 /* skip if session-dir already exists */
1196 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1199 /* skip sessions that are already in 'recent'.
1200 * eg. a new user changed <session-default-dir> shorly after installation
1202 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1203 if ((*r).first == name) {
1208 PBD::FileArchive ar (*i);
1209 if (0 == ar.inflate (dspd)) {
1210 store_recent_sessions (name, path);
1211 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1217 #ifdef NO_PLUGIN_STATE
1219 ARDOUR::RecentSessions rs;
1220 ARDOUR::read_recent_sessions (rs);
1222 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1224 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1226 /* already used Ardour, have sessions ... warn about plugin state */
1228 ArdourDialog d (_("Free/Demo Version Warning"), true);
1230 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1231 CheckButton c (_("Don't warn me about this again"));
1233 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"),
1234 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1235 _("It will not restore OR save any plugin settings"),
1236 _("If you load an existing session with plugin settings\n"
1237 "they will not be used and will be lost."),
1238 _("To get full access to updates without this limitation\n"
1239 "consider becoming a subscriber for a low cost every month.")));
1240 l.set_justify (JUSTIFY_CENTER);
1242 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1244 d.get_vbox()->pack_start (l, true, true);
1245 d.get_vbox()->pack_start (b, false, false, 12);
1246 d.get_vbox()->pack_start (c, false, false, 12);
1248 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1249 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1253 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1255 if (d.run () != RESPONSE_OK) {
1261 /* go get a session */
1263 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1265 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1266 std::cerr << "Cannot get session parameters."<< std::endl;
1273 WM::Manager::instance().show_visible ();
1275 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1276 * editor window, and we may want stuff to be hidden.
1278 _status_bar_visibility.update ();
1280 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1282 /* all other dialogs are created conditionally */
1288 ARDOUR_UI::check_memory_locking ()
1290 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1291 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1295 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1297 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1299 struct rlimit limits;
1301 long pages, page_size;
1303 size_t pages_len=sizeof(pages);
1304 if ((page_size = getpagesize()) < 0 ||
1305 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1307 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1312 ram = (int64_t) pages * (int64_t) page_size;
1315 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1319 if (limits.rlim_cur != RLIM_INFINITY) {
1321 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1325 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1326 "This might cause %1 to run out of memory before your system "
1327 "runs out of memory. \n\n"
1328 "You can view the memory limit with 'ulimit -l', "
1329 "and it is normally controlled by %2"),
1332 X_("/etc/login.conf")
1334 X_(" /etc/security/limits.conf")
1338 msg.set_default_response (RESPONSE_OK);
1340 VBox* vbox = msg.get_vbox();
1342 CheckButton cb (_("Do not show this window again"));
1343 hbox.pack_start (cb, true, false);
1344 vbox->pack_start (hbox);
1349 pop_back_splash (msg);
1353 if (cb.get_active()) {
1354 XMLNode node (X_("no-memory-warning"));
1355 Config->add_instant_xml (node);
1360 #endif // !__APPLE__
1365 ARDOUR_UI::queue_finish ()
1367 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1371 ARDOUR_UI::idle_finish ()
1374 return false; /* do not call again */
1381 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1383 if (_session->dirty()) {
1384 vector<string> actions;
1385 actions.push_back (_("Don't quit"));
1386 actions.push_back (_("Just quit"));
1387 actions.push_back (_("Save and quit"));
1388 switch (ask_about_saving_session(actions)) {
1393 /* use the default name */
1394 if (save_state_canfail ("")) {
1395 /* failed - don't quit */
1396 MessageDialog msg (_main_window,
1397 string_compose (_("\
1398 %1 was unable to save your session.\n\n\
1399 If you still wish to quit, please use the\n\n\
1400 \"Just quit\" option."), PROGRAM_NAME));
1401 pop_back_splash(msg);
1411 second_connection.disconnect ();
1412 point_one_second_connection.disconnect ();
1413 point_zero_something_second_connection.disconnect();
1414 fps_connection.disconnect();
1417 delete ARDOUR_UI::instance()->video_timeline;
1418 ARDOUR_UI::instance()->video_timeline = NULL;
1419 stop_video_server();
1421 /* Save state before deleting the session, as that causes some
1422 windows to be destroyed before their visible state can be
1425 save_ardour_state ();
1427 if (key_editor.get (false)) {
1428 key_editor->disconnect ();
1431 close_all_dialogs ();
1434 _session->set_clean ();
1435 _session->remove_pending_capture_state ();
1440 halt_connection.disconnect ();
1441 AudioEngine::instance()->stop ();
1442 #ifdef WINDOWS_VST_SUPPORT
1443 fst_stop_threading();
1449 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1451 ArdourDialog window (_("Unsaved Session"));
1452 Gtk::HBox dhbox; // the hbox for the image and text
1453 Gtk::Label prompt_label;
1454 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1458 assert (actions.size() >= 3);
1460 window.add_button (actions[0], RESPONSE_REJECT);
1461 window.add_button (actions[1], RESPONSE_APPLY);
1462 window.add_button (actions[2], RESPONSE_ACCEPT);
1464 window.set_default_response (RESPONSE_ACCEPT);
1466 Gtk::Button noquit_button (msg);
1467 noquit_button.set_name ("EditorGTKButton");
1471 if (_session->snap_name() == _session->name()) {
1472 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?"),
1473 _session->snap_name());
1475 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?"),
1476 _session->snap_name());
1479 prompt_label.set_text (prompt);
1480 prompt_label.set_name (X_("PrompterLabel"));
1481 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1483 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1484 dhbox.set_homogeneous (false);
1485 dhbox.pack_start (*dimage, false, false, 5);
1486 dhbox.pack_start (prompt_label, true, false, 5);
1487 window.get_vbox()->pack_start (dhbox);
1489 window.set_name (_("Prompter"));
1490 window.set_modal (true);
1491 window.set_resizable (false);
1494 prompt_label.show();
1499 ResponseType r = (ResponseType) window.run();
1504 case RESPONSE_ACCEPT: // save and get out of here
1506 case RESPONSE_APPLY: // get out of here
1517 ARDOUR_UI::every_second ()
1520 update_disk_space ();
1521 update_timecode_format ();
1522 update_peak_thread_work ();
1524 if (nsm && nsm->is_active ()) {
1527 if (!_was_dirty && _session->dirty ()) {
1531 else if (_was_dirty && !_session->dirty ()){
1539 ARDOUR_UI::every_point_one_seconds ()
1541 if (editor) editor->build_region_boundary_cache();
1545 ARDOUR_UI::every_point_zero_something_seconds ()
1547 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1549 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1550 float mpeak = editor_meter->update_meters();
1551 if (mpeak > editor_meter_max_peak) {
1552 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1553 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1560 ARDOUR_UI::set_fps_timeout_connection ()
1562 unsigned int interval = 40;
1563 if (!_session) return;
1564 if (_session->timecode_frames_per_second() != 0) {
1565 /* ideally we'll use a select() to sleep and not accumulate
1566 * idle time to provide a regular periodic signal.
1567 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1568 * However, that'll require a dedicated thread and cross-thread
1569 * signals to the GUI Thread..
1571 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1572 * _session->sample_rate() / _session->nominal_sample_rate()
1573 / _session->timecode_frames_per_second()
1575 #ifdef PLATFORM_WINDOWS
1576 // the smallest windows scheduler time-slice is ~15ms.
1577 // periodic GUI timeouts shorter than that will cause
1578 // WaitForSingleObject to spinlock (100% of one CPU Core)
1579 // and gtk never enters idle mode.
1580 // also changing timeBeginPeriod(1) does not affect that in
1581 // any beneficial way, so we just limit the max rate for now.
1582 interval = std::max(30u, interval); // at most ~33Hz.
1584 interval = std::max(8u, interval); // at most 120Hz.
1587 fps_connection.disconnect();
1588 Timers::set_fps_interval (interval);
1592 ARDOUR_UI::update_sample_rate (samplecnt_t)
1596 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1598 if (!AudioEngine::instance()->connected()) {
1600 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1604 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1607 /* no sample rate available */
1608 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1611 if (fmod (rate, 1000.0) != 0.0) {
1612 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1613 (float) rate / 1000.0f,
1614 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1616 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1618 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1622 sample_rate_label.set_markup (buf);
1626 ARDOUR_UI::update_format ()
1629 format_label.set_text ("");
1634 s << _("File:") << X_(" <span foreground=\"green\">");
1636 switch (_session->config.get_native_file_header_format ()) {
1668 switch (_session->config.get_native_file_data_format ()) {
1682 format_label.set_markup (s.str ());
1686 ARDOUR_UI::update_cpu_load ()
1688 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1689 double const c = AudioEngine::instance()->get_dsp_load ();
1691 const char* const bg = c > 90 ? " background=\"red\"" : "";
1695 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1697 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1699 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1702 dsp_load_label.set_markup (buf);
1705 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1707 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1709 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1712 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1716 ARDOUR_UI::update_peak_thread_work ()
1719 const int c = SourceFactory::peak_work_queue_length ();
1721 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1722 peak_thread_work_label.set_markup (buf);
1724 peak_thread_work_label.set_markup (X_(""));
1729 ARDOUR_UI::count_recenabled_streams (Route& route)
1731 Track* track = dynamic_cast<Track*>(&route);
1732 if (track && track->rec_enable_control()->get_value()) {
1733 rec_enabled_streams += track->n_inputs().n_total();
1738 ARDOUR_UI::format_disk_space_label (float remain_sec)
1740 if (remain_sec < 0) {
1741 disk_space_label.set_text (_("N/A"));
1742 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1748 int sec = floor (remain_sec);
1749 int hrs = sec / 3600;
1750 int mins = (sec / 60) % 60;
1751 int secs = sec % 60;
1752 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1753 ArdourWidgets::set_tooltip (disk_space_label, buf);
1755 if (remain_sec > 86400) {
1756 disk_space_label.set_text (_("Rec: >24h"));
1758 } else if (remain_sec > 32400 /* 9 hours */) {
1759 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1760 } else if (remain_sec > 5940 /* 99 mins */) {
1761 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1763 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1765 disk_space_label.set_text (buf);
1770 ARDOUR_UI::update_disk_space()
1772 if (_session == 0) {
1773 format_disk_space_label (-1);
1777 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1778 samplecnt_t fr = _session->sample_rate();
1781 /* skip update - no SR available */
1782 format_disk_space_label (-1);
1787 /* Available space is unknown */
1788 format_disk_space_label (-1);
1789 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1790 format_disk_space_label (max_samplecnt);
1792 rec_enabled_streams = 0;
1793 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1795 samplecnt_t samples = opt_samples.get_value_or (0);
1797 if (rec_enabled_streams) {
1798 samples /= rec_enabled_streams;
1801 format_disk_space_label (samples / (float)fr);
1807 ARDOUR_UI::update_timecode_format ()
1813 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1814 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1816 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1817 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1822 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1823 matching ? X_("green") : X_("red"),
1824 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1826 snprintf (buf, sizeof (buf), "TC: n/a");
1829 timecode_format_label.set_markup (buf);
1833 ARDOUR_UI::update_wall_clock ()
1837 static int last_min = -1;
1840 tm_now = localtime (&now);
1841 if (last_min != tm_now->tm_min) {
1843 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1844 wall_clock_label.set_text (buf);
1845 last_min = tm_now->tm_min;
1852 ARDOUR_UI::open_recent_session ()
1854 bool can_return = (_session != 0);
1856 SessionDialog recent_session_dialog;
1860 ResponseType r = (ResponseType) recent_session_dialog.run ();
1863 case RESPONSE_ACCEPT:
1867 recent_session_dialog.hide();
1874 recent_session_dialog.hide();
1878 std::string path = recent_session_dialog.session_folder();
1879 std::string state = recent_session_dialog.session_name (should_be_new);
1881 if (should_be_new == true) {
1885 _session_is_new = false;
1887 if (load_session (path, state) == 0) {
1896 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1898 if (!AudioEngine::instance()->connected()) {
1899 MessageDialog msg (parent, string_compose (
1900 _("%1 is not connected to any audio backend.\n"
1901 "You cannot open or close sessions in this condition"),
1903 pop_back_splash (msg);
1911 ARDOUR_UI::open_session ()
1913 if (!check_audioengine (_main_window)) {
1917 /* ardour sessions are folders */
1918 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1919 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1920 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1921 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1924 string session_parent_dir = Glib::path_get_dirname(_session->path());
1925 open_session_selector.set_current_folder(session_parent_dir);
1927 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1930 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1932 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1933 string default_session_folder = Config->get_default_session_parent_dir();
1934 open_session_selector.add_shortcut_folder (default_session_folder);
1936 catch (Glib::Error const& e) {
1937 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1940 FileFilter session_filter;
1941 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1942 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1943 open_session_selector.add_filter (session_filter);
1945 FileFilter archive_filter;
1946 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1947 archive_filter.set_name (_("Session Archives"));
1949 open_session_selector.add_filter (archive_filter);
1951 open_session_selector.set_filter (session_filter);
1953 int response = open_session_selector.run();
1954 open_session_selector.hide ();
1956 if (response == Gtk::RESPONSE_CANCEL) {
1960 string session_path = open_session_selector.get_filename();
1964 if (session_path.length() > 0) {
1965 int rv = ARDOUR::inflate_session (session_path,
1966 Config->get_default_session_parent_dir(), path, name);
1968 _session_is_new = false;
1969 load_session (path, name);
1972 MessageDialog msg (_main_window,
1973 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1976 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1977 _session_is_new = isnew;
1978 load_session (path, name);
1984 ARDOUR_UI::session_add_mixed_track (
1985 const ChanCount& input,
1986 const ChanCount& output,
1987 RouteGroup* route_group,
1989 const string& name_template,
1991 PluginInfoPtr instrument,
1992 Plugin::PresetRecord* pset,
1993 ARDOUR::PresentationInfo::order_t order)
1997 if (Profile->get_mixbus ()) {
2002 list<boost::shared_ptr<MidiTrack> > tracks;
2003 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2005 if (tracks.size() != how_many) {
2006 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2011 display_insufficient_ports_message ();
2017 ARDOUR_UI::session_add_midi_bus (
2018 RouteGroup* route_group,
2020 const string& name_template,
2022 PluginInfoPtr instrument,
2023 Plugin::PresetRecord* pset,
2024 ARDOUR::PresentationInfo::order_t order)
2026 if (_session == 0) {
2027 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2031 if (Profile->get_mixbus ()) {
2037 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2038 if (routes.size() != how_many) {
2039 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2044 display_insufficient_ports_message ();
2050 ARDOUR_UI::session_add_midi_route (
2052 RouteGroup* route_group,
2054 const string& name_template,
2056 PluginInfoPtr instrument,
2057 Plugin::PresetRecord* pset,
2058 ARDOUR::PresentationInfo::order_t order)
2060 ChanCount one_midi_channel;
2061 one_midi_channel.set (DataType::MIDI, 1);
2064 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2066 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2071 ARDOUR_UI::session_add_audio_route (
2073 int32_t input_channels,
2074 int32_t output_channels,
2075 ARDOUR::TrackMode mode,
2076 RouteGroup* route_group,
2078 string const & name_template,
2080 ARDOUR::PresentationInfo::order_t order)
2082 list<boost::shared_ptr<AudioTrack> > tracks;
2089 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2091 if (tracks.size() != how_many) {
2092 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2098 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2100 if (routes.size() != how_many) {
2101 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2108 display_insufficient_ports_message ();
2113 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2114 (*i)->set_strict_io (true);
2116 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2117 (*i)->set_strict_io (true);
2123 ARDOUR_UI::display_insufficient_ports_message ()
2125 MessageDialog msg (_main_window,
2126 string_compose (_("There are insufficient ports available\n\
2127 to create a new track or bus.\n\
2128 You should save %1, exit and\n\
2129 restart with more ports."), PROGRAM_NAME));
2130 pop_back_splash (msg);
2135 ARDOUR_UI::transport_goto_start ()
2138 _session->goto_start();
2140 /* force displayed area in editor to start no matter
2141 what "follow playhead" setting is.
2145 editor->center_screen (_session->current_start_sample ());
2151 ARDOUR_UI::transport_goto_zero ()
2154 _session->request_locate (0);
2156 /* force displayed area in editor to start no matter
2157 what "follow playhead" setting is.
2161 editor->reset_x_origin (0);
2167 ARDOUR_UI::transport_goto_wallclock ()
2169 if (_session && editor) {
2173 samplepos_t samples;
2176 localtime_r (&now, &tmnow);
2178 samplecnt_t sample_rate = _session->sample_rate();
2180 if (sample_rate == 0) {
2181 /* no frame rate available */
2185 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2186 samples += tmnow.tm_min * (60 * sample_rate);
2187 samples += tmnow.tm_sec * sample_rate;
2189 _session->request_locate (samples, _session->transport_rolling ());
2191 /* force displayed area in editor to start no matter
2192 what "follow playhead" setting is.
2196 editor->center_screen (samples);
2202 ARDOUR_UI::transport_goto_end ()
2205 samplepos_t const sample = _session->current_end_sample();
2206 _session->request_locate (sample);
2208 /* force displayed area in editor to start no matter
2209 what "follow playhead" setting is.
2213 editor->center_screen (sample);
2219 ARDOUR_UI::transport_stop ()
2225 if (_session->is_auditioning()) {
2226 _session->cancel_audition ();
2230 _session->request_stop (false, true);
2233 /** Check if any tracks are record enabled. If none are, record enable all of them.
2234 * @return true if track record-enabled status was changed, false otherwise.
2237 ARDOUR_UI::trx_record_enable_all_tracks ()
2243 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2244 bool none_record_enabled = true;
2246 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2247 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2250 if (t->rec_enable_control()->get_value()) {
2251 none_record_enabled = false;
2256 if (none_record_enabled) {
2257 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2260 return none_record_enabled;
2264 ARDOUR_UI::transport_record (bool roll)
2267 switch (_session->record_status()) {
2268 case Session::Disabled:
2269 if (_session->ntracks() == 0) {
2270 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."));
2274 if (Profile->get_trx()) {
2275 roll = trx_record_enable_all_tracks ();
2277 _session->maybe_enable_record ();
2282 case Session::Recording:
2284 _session->request_stop();
2286 _session->disable_record (false, true);
2290 case Session::Enabled:
2291 _session->disable_record (false, true);
2297 ARDOUR_UI::transport_roll ()
2303 if (_session->is_auditioning()) {
2307 if (_session->config.get_external_sync()) {
2308 switch (TransportMasterManager::instance().current()->type()) {
2312 /* transport controlled by the master */
2317 bool rolling = _session->transport_rolling();
2319 if (_session->get_play_loop()) {
2321 /* If loop playback is not a mode, then we should cancel
2322 it when this action is requested. If it is a mode
2323 we just leave it in place.
2326 if (!Config->get_loop_is_mode()) {
2327 /* XXX it is not possible to just leave seamless loop and keep
2328 playing at present (nov 4th 2009)
2330 if (!Config->get_seamless_loop()) {
2331 /* stop loop playback and stop rolling */
2332 _session->request_play_loop (false, true);
2333 } else if (rolling) {
2334 /* stop loop playback but keep rolling */
2335 _session->request_play_loop (false, false);
2339 } else if (_session->get_play_range () ) {
2340 /* stop playing a range if we currently are */
2341 _session->request_play_range (0, true);
2345 _session->request_transport_speed (1.0f);
2350 ARDOUR_UI::get_smart_mode() const
2352 return ( editor->get_smart_mode() );
2357 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2363 if (_session->is_auditioning()) {
2364 _session->cancel_audition ();
2368 if (_session->config.get_external_sync()) {
2369 switch (TransportMasterManager::instance().current()->type()) {
2373 /* transport controlled by the master */
2378 bool rolling = _session->transport_rolling();
2379 bool affect_transport = true;
2381 if (rolling && roll_out_of_bounded_mode) {
2382 /* drop out of loop/range playback but leave transport rolling */
2383 if (_session->get_play_loop()) {
2384 if (_session->actively_recording()) {
2386 /* just stop using the loop, then actually stop
2389 _session->request_play_loop (false, affect_transport);
2392 if (Config->get_seamless_loop()) {
2393 /* the disk buffers contain copies of the loop - we can't
2394 just keep playing, so stop the transport. the user
2395 can restart as they wish.
2397 affect_transport = true;
2399 /* disk buffers are normal, so we can keep playing */
2400 affect_transport = false;
2402 _session->request_play_loop (false, affect_transport);
2404 } else if (_session->get_play_range ()) {
2405 affect_transport = false;
2406 _session->request_play_range (0, true);
2410 if (affect_transport) {
2412 _session->request_stop (with_abort, true);
2414 } else if (!with_abort) { /* with_abort == true means the
2415 * command was intended to stop
2416 * transport, not start.
2419 /* the only external sync condition we can be in here
2420 * would be Engine (JACK) sync, in which case we still
2424 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_sample() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2425 _session->request_play_range (&editor->get_selection().time, true);
2426 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2428 _session->request_transport_speed (1.0f);
2434 ARDOUR_UI::toggle_session_auto_loop ()
2440 Location * looploc = _session->locations()->auto_loop_location();
2446 if (_session->get_play_loop()) {
2448 /* looping enabled, our job is to disable it */
2450 _session->request_play_loop (false);
2454 /* looping not enabled, our job is to enable it.
2456 loop-is-NOT-mode: this action always starts the transport rolling.
2457 loop-IS-mode: this action simply sets the loop play mechanism, but
2458 does not start transport.
2460 if (Config->get_loop_is_mode()) {
2461 _session->request_play_loop (true, false);
2463 _session->request_play_loop (true, true);
2467 //show the loop markers
2468 looploc->set_hidden (false, this);
2472 ARDOUR_UI::transport_play_selection ()
2478 editor->play_selection ();
2482 ARDOUR_UI::transport_play_preroll ()
2487 editor->play_with_preroll ();
2491 ARDOUR_UI::transport_rec_preroll ()
2496 editor->rec_with_preroll ();
2500 ARDOUR_UI::transport_rec_count_in ()
2505 editor->rec_with_count_in ();
2509 ARDOUR_UI::transport_rewind (int option)
2511 float current_transport_speed;
2514 current_transport_speed = _session->transport_speed();
2516 if (current_transport_speed >= 0.0f) {
2519 _session->request_transport_speed (-1.0f);
2522 _session->request_transport_speed (-4.0f);
2525 _session->request_transport_speed (-0.5f);
2530 _session->request_transport_speed (current_transport_speed * 1.5f);
2536 ARDOUR_UI::transport_forward (int option)
2542 float current_transport_speed = _session->transport_speed();
2544 if (current_transport_speed <= 0.0f) {
2547 _session->request_transport_speed (1.0f);
2550 _session->request_transport_speed (4.0f);
2553 _session->request_transport_speed (0.5f);
2558 _session->request_transport_speed (current_transport_speed * 1.5f);
2563 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2569 boost::shared_ptr<Route> r;
2571 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2573 boost::shared_ptr<Track> t;
2575 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2576 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2582 ARDOUR_UI::map_transport_state ()
2585 layered_button.set_sensitive (false);
2589 shuttle_box.map_transport_state ();
2591 float sp = _session->transport_speed();
2594 layered_button.set_sensitive (!_session->actively_recording ());
2596 layered_button.set_sensitive (true);
2597 update_disk_space ();
2602 ARDOUR_UI::blink_handler (bool blink_on)
2604 sync_blink (blink_on);
2606 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2609 error_blink (blink_on);
2610 solo_blink (blink_on);
2611 audition_blink (blink_on);
2612 feedback_blink (blink_on);
2616 ARDOUR_UI::update_clocks ()
2618 if (!_session) return;
2620 if (editor && !editor->dragging_playhead()) {
2621 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2626 ARDOUR_UI::start_clocking ()
2628 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2629 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2631 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2636 ARDOUR_UI::stop_clocking ()
2638 clock_signal_connection.disconnect ();
2642 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2646 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2648 label->set_text (buf);
2649 bar->set_fraction (fraction);
2651 /* process events, redraws, etc. */
2653 while (gtk_events_pending()) {
2654 gtk_main_iteration ();
2657 return true; /* continue with save-as */
2661 ARDOUR_UI::save_session_as ()
2667 if (_session->dirty()) {
2668 vector<string> actions;
2669 actions.push_back (_("Abort save-as"));
2670 actions.push_back (_("Don't save now, just save-as"));
2671 actions.push_back (_("Save it first"));
2672 switch (ask_about_saving_session(actions)) {
2677 if (save_state_canfail ("")) {
2678 MessageDialog msg (_main_window,
2679 string_compose (_("\
2680 %1 was unable to save your session.\n\n\
2681 If you still wish to proceed, please use the\n\n\
2682 \"Don't save now\" option."), PROGRAM_NAME));
2683 pop_back_splash(msg);
2689 _session->remove_pending_capture_state ();
2694 if (!save_as_dialog) {
2695 save_as_dialog = new SaveAsDialog;
2698 save_as_dialog->set_name (_session->name());
2700 int response = save_as_dialog->run ();
2702 save_as_dialog->hide ();
2705 case Gtk::RESPONSE_OK:
2714 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2715 sa.new_name = save_as_dialog->new_name ();
2716 sa.switch_to = save_as_dialog->switch_to();
2717 sa.copy_media = save_as_dialog->copy_media();
2718 sa.copy_external = save_as_dialog->copy_external();
2719 sa.include_media = save_as_dialog->include_media ();
2721 /* Only bother with a progress dialog if we're going to copy
2722 media into the save-as target. Without that choice, this
2723 will be very fast because we're only talking about a few kB's to
2724 perhaps a couple of MB's of data.
2727 ArdourDialog progress_dialog (_("Save As"), true);
2730 if (sa.include_media && sa.copy_media) {
2732 Gtk::Label* label = manage (new Gtk::Label());
2733 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2735 progress_dialog.get_vbox()->pack_start (*label);
2736 progress_dialog.get_vbox()->pack_start (*progress_bar);
2738 progress_bar->show ();
2740 /* this signal will be emitted from within this, the calling thread,
2741 * after every file is copied. It provides information on percentage
2742 * complete (in terms of total data to copy), the number of files
2743 * copied so far, and the total number to copy.
2746 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2748 progress_dialog.show_all ();
2749 progress_dialog.present ();
2752 if (_session->save_as (sa)) {
2754 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2758 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2759 * the trick is this: if the new session was copy with media included,
2760 * then Session::save_as() will have already done a neat trick to avoid
2761 * us having to unload and load the new state. But if the media was not
2762 * included, then this is required (it avoids us having to otherwise
2763 * drop all references to media (sources).
2766 if (!sa.include_media && sa.switch_to) {
2767 unload_session (false);
2768 load_session (sa.final_session_folder_name, sa.new_name);
2773 ARDOUR_UI::archive_session ()
2781 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2783 SessionArchiveDialog sad;
2784 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2785 int response = sad.run ();
2787 if (response != Gtk::RESPONSE_OK) {
2792 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2793 MessageDialog msg (_("Session Archiving failed."));
2799 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2803 struct tm local_time;
2806 localtime_r (&n, &local_time);
2807 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2808 if (switch_to_it && _session->dirty ()) {
2809 save_state_canfail ("");
2812 save_state (timebuf, switch_to_it);
2817 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2821 prompter.get_result (snapname);
2823 bool do_save = (snapname.length() != 0);
2826 char illegal = Session::session_name_is_legal(snapname);
2828 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2829 "snapshot names may not contain a '%1' character"), illegal));
2835 vector<std::string> p;
2836 get_state_files_in_directory (_session->session_directory().root_path(), p);
2837 vector<string> n = get_file_names_no_extension (p);
2839 if (find (n.begin(), n.end(), snapname) != n.end()) {
2841 do_save = overwrite_file_dialog (prompter,
2842 _("Confirm Snapshot Overwrite"),
2843 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2847 save_state (snapname, switch_to_it);
2857 /** Ask the user for the name of a new snapshot and then take it.
2861 ARDOUR_UI::snapshot_session (bool switch_to_it)
2863 if (switch_to_it && _session->dirty()) {
2864 vector<string> actions;
2865 actions.push_back (_("Abort saving snapshot"));
2866 actions.push_back (_("Don't save now, just snapshot"));
2867 actions.push_back (_("Save it first"));
2868 switch (ask_about_saving_session(actions)) {
2873 if (save_state_canfail ("")) {
2874 MessageDialog msg (_main_window,
2875 string_compose (_("\
2876 %1 was unable to save your session.\n\n\
2877 If you still wish to proceed, please use the\n\n\
2878 \"Don't save now\" option."), PROGRAM_NAME));
2879 pop_back_splash(msg);
2885 _session->remove_pending_capture_state ();
2890 Prompter prompter (true);
2891 prompter.set_name ("Prompter");
2892 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2894 prompter.set_title (_("Snapshot and switch"));
2895 prompter.set_prompt (_("New session name"));
2897 prompter.set_title (_("Take Snapshot"));
2898 prompter.set_prompt (_("Name of new snapshot"));
2902 prompter.set_initial_text (_session->snap_name());
2904 Glib::DateTime tm (g_date_time_new_now_local ());
2905 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2908 bool finished = false;
2910 switch (prompter.run()) {
2911 case RESPONSE_ACCEPT:
2913 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2924 /** Ask the user for a new session name and then rename the session to it.
2928 ARDOUR_UI::rename_session ()
2934 Prompter prompter (true);
2937 prompter.set_name ("Prompter");
2938 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2939 prompter.set_title (_("Rename Session"));
2940 prompter.set_prompt (_("New session name"));
2943 switch (prompter.run()) {
2944 case RESPONSE_ACCEPT:
2946 prompter.get_result (name);
2948 bool do_rename = (name.length() != 0);
2951 char illegal = Session::session_name_is_legal (name);
2954 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2955 "session names may not contain a '%1' character"), illegal));
2960 switch (_session->rename (name)) {
2962 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2963 msg.set_position (WIN_POS_MOUSE);
2971 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2972 msg.set_position (WIN_POS_MOUSE);
2988 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2990 if (!_session || _session->deletion_in_progress()) {
2994 XMLNode* node = new XMLNode (X_("UI"));
2996 WM::Manager::instance().add_state (*node);
2998 node->add_child_nocopy (gui_object_state->get_state());
3000 _session->add_extra_xml (*node);
3002 if (export_video_dialog) {
3003 _session->add_extra_xml (export_video_dialog->get_state());
3006 save_state_canfail (name, switch_to_it);
3010 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3015 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3020 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3025 ARDOUR_UI::primary_clock_value_changed ()
3028 _session->request_locate (primary_clock->current_time ());
3033 ARDOUR_UI::big_clock_value_changed ()
3036 _session->request_locate (big_clock->current_time ());
3041 ARDOUR_UI::secondary_clock_value_changed ()
3044 _session->request_locate (secondary_clock->current_time ());
3048 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3050 if (response == RESPONSE_ACCEPT) {
3051 const string name = d->get_template_name ();
3052 const string desc = d->get_description ();
3054 int failed = _session->save_template (name, desc);
3056 if (failed == -2) { /* file already exists. */
3057 bool overwrite = overwrite_file_dialog (*d,
3058 _("Confirm Template Overwrite"),
3059 _("A template already exists with that name. Do you want to overwrite it?"));
3062 _session->save_template (name, desc, true);
3074 ARDOUR_UI::save_template ()
3076 if (!check_audioengine (_main_window)) {
3080 const std::string desc = SessionMetadata::Metadata()->description ();
3081 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3082 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3086 void ARDOUR_UI::manage_templates ()
3093 ARDOUR_UI::edit_metadata ()
3095 SessionMetadataEditor dialog;
3096 dialog.set_session (_session);
3097 dialog.grab_focus ();
3102 ARDOUR_UI::import_metadata ()
3104 SessionMetadataImporter dialog;
3105 dialog.set_session (_session);
3110 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3112 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3114 MessageDialog msg (str,
3116 Gtk::MESSAGE_WARNING,
3117 Gtk::BUTTONS_YES_NO,
3121 msg.set_name (X_("OpenExistingDialog"));
3122 msg.set_title (_("Open Existing Session"));
3123 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3124 msg.set_position (Gtk::WIN_POS_CENTER);
3125 pop_back_splash (msg);
3127 switch (msg.run()) {
3136 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3138 BusProfile bus_profile;
3141 bus_profile.master_out_channels = 2;
3143 /* get settings from advanced section of NSD */
3144 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3147 // NULL profile: no master, no monitor
3148 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3156 ARDOUR_UI::load_from_application_api (const std::string& path)
3158 /* OS X El Capitan (and probably later) now somehow passes the command
3159 line arguments to an app via the openFile delegate protocol. Ardour
3160 already does its own command line processing, and having both
3161 pathways active causes crashes. So, if the command line was already
3162 set, do nothing here.
3165 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3169 ARDOUR_COMMAND_LINE::session_name = path;
3171 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3173 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3175 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3176 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3177 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3178 * -> SessionDialog is not displayed
3181 if (_session_dialog) {
3182 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3183 std::string session_path = path;
3184 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3185 session_path = Glib::path_get_dirname (session_path);
3187 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3188 _session_dialog->set_provided_session (session_name, session_path);
3189 _session_dialog->response (RESPONSE_NONE);
3190 _session_dialog->hide();
3195 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3196 /* /path/to/foo => /path/to/foo, foo */
3197 rv = load_session (path, basename_nosuffix (path));
3199 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3200 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3203 // if load_session fails -> pop up SessionDialog.
3205 ARDOUR_COMMAND_LINE::session_name = "";
3207 if (get_session_parameters (true, false)) {
3213 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3215 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3217 string session_name;
3218 string session_path;
3219 string template_name;
3221 bool likely_new = false;
3222 bool cancel_not_quit;
3224 /* deal with any existing DIRTY session now, rather than later. don't
3225 * treat a non-dirty session this way, so that it stays visible
3226 * as we bring up the new session dialog.
3229 if (_session && ARDOUR_UI::instance()->video_timeline) {
3230 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3233 /* if there is already a session, relabel the button
3234 on the SessionDialog so that we don't Quit directly
3236 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3238 if (_session && _session->dirty()) {
3239 if (unload_session (false)) {
3240 /* unload cancelled by user */
3243 ARDOUR_COMMAND_LINE::session_name = "";
3246 if (!load_template.empty()) {
3247 should_be_new = true;
3248 template_name = load_template;
3251 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3252 session_path = ARDOUR_COMMAND_LINE::session_name;
3254 if (!session_path.empty()) {
3255 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3256 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3257 /* session/snapshot file, change path to be dir */
3258 session_path = Glib::path_get_dirname (session_path);
3263 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3265 _session_dialog = &session_dialog;
3268 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3270 /* if they named a specific statefile, use it, otherwise they are
3271 just giving a session folder, and we want to use it as is
3272 to find the session.
3275 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3277 if (suffix != string::npos) {
3278 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3279 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3280 session_name = Glib::path_get_basename (session_name);
3282 session_path = ARDOUR_COMMAND_LINE::session_name;
3283 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3288 session_dialog.clear_given ();
3291 if (should_be_new || session_name.empty()) {
3292 /* need the dialog to get info from user */
3294 cerr << "run dialog\n";
3296 switch (session_dialog.run()) {
3297 case RESPONSE_ACCEPT:
3300 /* this is used for async * app->ShouldLoad(). */
3301 continue; // while loop
3304 if (quit_on_cancel) {
3305 ARDOUR_UI::finish ();
3306 Gtkmm2ext::Application::instance()->cleanup();
3308 pthread_cancel_all ();
3309 return -1; // caller is responsible to call exit()
3315 session_dialog.hide ();
3318 /* if we run the startup dialog again, offer more than just "new session" */
3320 should_be_new = false;
3322 session_name = session_dialog.session_name (likely_new);
3323 session_path = session_dialog.session_folder ();
3330 int rv = ARDOUR::inflate_session (session_name,
3331 Config->get_default_session_parent_dir(), session_path, session_name);
3333 MessageDialog msg (session_dialog,
3334 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3339 session_dialog.set_provided_session (session_name, session_path);
3343 // XXX check archive, inflate
3344 string::size_type suffix = session_name.find (statefile_suffix);
3346 if (suffix != string::npos) {
3347 session_name = session_name.substr (0, suffix);
3350 /* this shouldn't happen, but we catch it just in case it does */
3352 if (session_name.empty()) {
3356 if (session_dialog.use_session_template()) {
3357 template_name = session_dialog.session_template_name();
3358 _session_is_new = true;
3361 if (session_name[0] == G_DIR_SEPARATOR ||
3362 #ifdef PLATFORM_WINDOWS
3363 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3365 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3366 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3371 /* absolute path or cwd-relative path specified for session name: infer session folder
3372 from what was given.
3375 session_path = Glib::path_get_dirname (session_name);
3376 session_name = Glib::path_get_basename (session_name);
3380 session_path = session_dialog.session_folder();
3382 char illegal = Session::session_name_is_legal (session_name);
3385 MessageDialog msg (session_dialog,
3386 string_compose (_("To ensure compatibility with various systems\n"
3387 "session names may not contain a '%1' character"),
3390 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3395 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3398 if (likely_new && !nsm) {
3400 std::string existing = Glib::build_filename (session_path, session_name);
3402 if (!ask_about_loading_existing_session (existing)) {
3403 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3408 _session_is_new = false;
3413 pop_back_splash (session_dialog);
3414 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3416 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3420 char illegal = Session::session_name_is_legal(session_name);
3423 pop_back_splash (session_dialog);
3424 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3425 "session names may not contain a '%1' character"), illegal));
3427 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3431 _session_is_new = true;
3434 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3436 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3437 meta_session_setup (template_name.substr (11));
3439 } else if (likely_new && template_name.empty()) {
3441 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3445 ret = load_session (session_path, session_name, template_name);
3448 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3452 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3453 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3457 /* clear this to avoid endless attempts to load the
3461 ARDOUR_COMMAND_LINE::session_name = "";
3465 _session_dialog = NULL;
3471 ARDOUR_UI::close_session()
3473 if (!check_audioengine (_main_window)) {
3477 if (unload_session (true)) {
3481 ARDOUR_COMMAND_LINE::session_name = "";
3483 if (get_session_parameters (true, false)) {
3488 /** @param snap_name Snapshot name (without .ardour suffix).
3489 * @return -2 if the load failed because we are not connected to the AudioEngine.
3492 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3494 /* load_session calls flush_pending() which allows
3495 * GUI interaction and potentially loading another session
3496 * (that was easy via snapshot sidebar).
3497 * Recursing into load_session() from load_session() and recusive
3498 * event loops causes all kind of crashes.
3500 assert (!session_load_in_progress);
3501 if (session_load_in_progress) {
3504 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3506 Session *new_session;
3511 unload_status = unload_session ();
3513 if (unload_status < 0) {
3515 } else if (unload_status > 0) {
3521 session_loaded = false;
3523 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3526 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3529 /* this one is special */
3531 catch (AudioEngine::PortRegistrationFailure const& err) {
3533 MessageDialog msg (err.what(),
3536 Gtk::BUTTONS_CLOSE);
3538 msg.set_title (_("Port Registration Error"));
3539 msg.set_secondary_text (_("Click the Close button to try again."));
3540 msg.set_position (Gtk::WIN_POS_CENTER);
3541 pop_back_splash (msg);
3544 int response = msg.run ();
3549 case RESPONSE_CANCEL:
3556 catch (SessionException const& e) {
3557 MessageDialog msg (string_compose(
3558 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3559 path, snap_name, e.what()),
3564 msg.set_title (_("Loading Error"));
3565 msg.set_position (Gtk::WIN_POS_CENTER);
3566 pop_back_splash (msg);
3578 MessageDialog msg (string_compose(
3579 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3585 msg.set_title (_("Loading Error"));
3586 msg.set_position (Gtk::WIN_POS_CENTER);
3587 pop_back_splash (msg);
3599 list<string> const u = new_session->unknown_processors ();
3601 MissingPluginDialog d (_session, u);
3606 if (!new_session->writable()) {
3607 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3612 msg.set_title (_("Read-only Session"));
3613 msg.set_position (Gtk::WIN_POS_CENTER);
3614 pop_back_splash (msg);
3621 /* Now the session been created, add the transport controls */
3622 new_session->add_controllable(roll_controllable);
3623 new_session->add_controllable(stop_controllable);
3624 new_session->add_controllable(goto_start_controllable);
3625 new_session->add_controllable(goto_end_controllable);
3626 new_session->add_controllable(auto_loop_controllable);
3627 new_session->add_controllable(play_selection_controllable);
3628 new_session->add_controllable(rec_controllable);
3630 set_session (new_session);
3632 session_loaded = true;
3635 _session->set_clean ();
3638 #ifdef WINDOWS_VST_SUPPORT
3639 fst_stop_threading();
3643 Timers::TimerSuspender t;
3647 #ifdef WINDOWS_VST_SUPPORT
3648 fst_start_threading();
3652 if (!mix_template.empty ()) {
3653 /* if mix_template is given, assume this is a new session */
3654 string metascript = Glib::build_filename (mix_template, "template.lua");
3655 meta_session_setup (metascript);
3660 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3661 * which is queued by set_session().
3662 * If session-loading fails we hide it explicitly.
3663 * This covers both cases in a central place.
3672 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3674 Session *new_session;
3677 session_loaded = false;
3678 x = unload_session ();
3686 _session_is_new = true;
3689 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3692 catch (SessionException const& e) {
3693 cerr << "Here are the errors associated with this failed session:\n";
3695 cerr << "---------\n";
3696 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3697 msg.set_title (_("Loading Error"));
3698 msg.set_position (Gtk::WIN_POS_CENTER);
3699 pop_back_splash (msg);
3704 cerr << "Here are the errors associated with this failed session:\n";
3706 cerr << "---------\n";
3707 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3708 msg.set_title (_("Loading Error"));
3709 msg.set_position (Gtk::WIN_POS_CENTER);
3710 pop_back_splash (msg);
3715 /* Give the new session the default GUI state, if such things exist */
3718 n = Config->instant_xml (X_("Editor"));
3720 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3721 new_session->add_instant_xml (*n, false);
3723 n = Config->instant_xml (X_("Mixer"));
3725 new_session->add_instant_xml (*n, false);
3728 n = Config->instant_xml (X_("Preferences"));
3730 new_session->add_instant_xml (*n, false);
3733 /* Put the playhead at 0 and scroll fully left */
3734 n = new_session->instant_xml (X_("Editor"));
3736 n->set_property (X_("playhead"), X_("0"));
3737 n->set_property (X_("left-frame"), X_("0"));
3740 set_session (new_session);
3742 session_loaded = true;
3744 new_session->save_state(new_session->name());
3750 static void _lua_print (std::string s) {
3752 std::cout << "LuaInstance: " << s << "\n";
3754 PBD::info << "LuaInstance: " << s << endmsg;
3757 std::map<std::string, std::string>
3758 ARDOUR_UI::route_setup_info (const std::string& script_path)
3760 std::map<std::string, std::string> rv;
3762 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3767 lua.Print.connect (&_lua_print);
3770 lua_State* L = lua.getState();
3771 LuaInstance::register_classes (L);
3772 LuaBindings::set_session (L, _session);
3773 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3774 lua_setglobal (L, "Editor");
3776 lua.do_command ("function ardour () end");
3777 lua.do_file (script_path);
3780 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3781 if (!fn.isFunction ()) {
3784 luabridge::LuaRef rs = fn ();
3785 if (!rs.isTable ()) {
3788 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3789 if (!i.key().isString()) {
3792 std::string key = i.key().tostring();
3793 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3794 rv[key] = i.value().tostring();
3797 } catch (luabridge::LuaException const& e) {
3798 cerr << "LuaException:" << e.what () << endl;
3804 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3806 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3809 assert (add_route_dialog);
3812 if ((count = add_route_dialog->count()) <= 0) {
3817 lua.Print.connect (&_lua_print);
3820 lua_State* L = lua.getState();
3821 LuaInstance::register_classes (L);
3822 LuaBindings::set_session (L, _session);
3823 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3824 lua_setglobal (L, "Editor");
3826 lua.do_command ("function ardour () end");
3827 lua.do_file (script_path);
3829 luabridge::LuaRef args (luabridge::newTable (L));
3831 args["name"] = add_route_dialog->name_template ();
3832 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3833 args["group"] = add_route_dialog->route_group ();
3834 args["strict_io"] = add_route_dialog->use_strict_io ();
3835 args["instrument"] = add_route_dialog->requested_instrument ();
3836 args["track_mode"] = add_route_dialog->mode ();
3837 args["channels"] = add_route_dialog->channel_count ();
3838 args["how_many"] = count;
3841 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3842 if (fn.isFunction()) {
3845 } catch (luabridge::LuaException const& e) {
3846 cerr << "LuaException:" << e.what () << endl;
3848 display_insufficient_ports_message ();
3853 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3855 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3860 lua.Print.connect (&_lua_print);
3863 lua_State* L = lua.getState();
3864 LuaInstance::register_classes (L);
3865 LuaBindings::set_session (L, _session);
3866 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3867 lua_setglobal (L, "Editor");
3869 lua.do_command ("function ardour () end");
3870 lua.do_file (script_path);
3873 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3874 if (fn.isFunction()) {
3877 } catch (luabridge::LuaException const& e) {
3878 cerr << "LuaException:" << e.what () << endl;
3880 display_insufficient_ports_message ();
3885 ARDOUR_UI::launch_chat ()
3887 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3889 dialog.set_title (_("About the Chat"));
3890 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."));
3892 switch (dialog.run()) {
3894 open_uri("http://webchat.freenode.net/?channels=ardour");
3902 ARDOUR_UI::launch_manual ()
3904 PBD::open_uri (Config->get_tutorial_manual_url());
3908 ARDOUR_UI::launch_reference ()
3910 PBD::open_uri (Config->get_reference_manual_url());
3914 ARDOUR_UI::launch_tracker ()
3916 PBD::open_uri ("http://tracker.ardour.org");
3920 ARDOUR_UI::launch_subscribe ()
3922 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3926 ARDOUR_UI::launch_cheat_sheet ()
3929 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3931 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3936 ARDOUR_UI::launch_website ()
3938 PBD::open_uri ("http://ardour.org");
3942 ARDOUR_UI::launch_website_dev ()
3944 PBD::open_uri ("http://ardour.org/development.html");
3948 ARDOUR_UI::launch_forums ()
3950 PBD::open_uri ("https://community.ardour.org/forums");
3954 ARDOUR_UI::launch_howto_report ()
3956 PBD::open_uri ("http://ardour.org/reporting_bugs");
3960 ARDOUR_UI::loading_message (const std::string& msg)
3962 if (ARDOUR_COMMAND_LINE::no_splash) {
3970 splash->message (msg);
3974 ARDOUR_UI::show_splash ()
3978 splash = new Splash;
3988 ARDOUR_UI::hide_splash ()
3995 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3999 removed = rep.paths.size();
4002 MessageDialog msgd (_main_window,
4003 _("No files were ready for clean-up"),
4007 msgd.set_title (_("Clean-up"));
4008 msgd.set_secondary_text (_("If this seems surprising, \n\
4009 check for any existing snapshots.\n\
4010 These may still include regions that\n\
4011 require some unused files to continue to exist."));
4017 ArdourDialog results (_("Clean-up"), true, false);
4019 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4020 CleanupResultsModelColumns() {
4024 Gtk::TreeModelColumn<std::string> visible_name;
4025 Gtk::TreeModelColumn<std::string> fullpath;
4029 CleanupResultsModelColumns results_columns;
4030 Glib::RefPtr<Gtk::ListStore> results_model;
4031 Gtk::TreeView results_display;
4033 results_model = ListStore::create (results_columns);
4034 results_display.set_model (results_model);
4035 results_display.append_column (list_title, results_columns.visible_name);
4037 results_display.set_name ("CleanupResultsList");
4038 results_display.set_headers_visible (true);
4039 results_display.set_headers_clickable (false);
4040 results_display.set_reorderable (false);
4042 Gtk::ScrolledWindow list_scroller;
4045 Gtk::HBox dhbox; // the hbox for the image and text
4046 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4047 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4049 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4051 const string dead_directory = _session->session_directory().dead_path();
4054 %1 - number of files removed
4055 %2 - location of "dead"
4056 %3 - size of files affected
4057 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4060 const char* bprefix;
4061 double space_adjusted = 0;
4063 if (rep.space < 1000) {
4065 space_adjusted = rep.space;
4066 } else if (rep.space < 1000000) {
4067 bprefix = _("kilo");
4068 space_adjusted = floorf((float)rep.space / 1000.0);
4069 } else if (rep.space < 1000000 * 1000) {
4070 bprefix = _("mega");
4071 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4073 bprefix = _("giga");
4074 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4078 txt.set_markup (string_compose (P_("\
4079 The following file was deleted from %2,\n\
4080 releasing %3 %4bytes of disk space", "\
4081 The following %1 files were deleted from %2,\n\
4082 releasing %3 %4bytes of disk space", removed),
4083 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4085 txt.set_markup (string_compose (P_("\
4086 The following file was not in use and \n\
4087 has been moved to: %2\n\n\
4088 After a restart of %5\n\n\
4089 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4090 will release an additional %3 %4bytes of disk space.\n", "\
4091 The following %1 files were not in use and \n\
4092 have been moved to: %2\n\n\
4093 After a restart of %5\n\n\
4094 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4095 will release an additional %3 %4bytes of disk space.\n", removed),
4096 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4099 dhbox.pack_start (*dimage, true, false, 5);
4100 dhbox.pack_start (txt, true, false, 5);
4102 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4103 TreeModel::Row row = *(results_model->append());
4104 row[results_columns.visible_name] = *i;
4105 row[results_columns.fullpath] = *i;
4108 list_scroller.add (results_display);
4109 list_scroller.set_size_request (-1, 150);
4110 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4112 dvbox.pack_start (dhbox, true, false, 5);
4113 dvbox.pack_start (list_scroller, true, false, 5);
4114 ddhbox.pack_start (dvbox, true, false, 5);
4116 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4117 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4118 results.set_default_response (RESPONSE_CLOSE);
4119 results.set_position (Gtk::WIN_POS_MOUSE);
4121 results_display.show();
4122 list_scroller.show();
4129 //results.get_vbox()->show();
4130 results.set_resizable (false);
4137 ARDOUR_UI::cleanup ()
4139 if (_session == 0) {
4140 /* shouldn't happen: menu item is insensitive */
4145 MessageDialog checker (_("Are you sure you want to clean-up?"),
4147 Gtk::MESSAGE_QUESTION,
4150 checker.set_title (_("Clean-up"));
4152 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4153 ALL undo/redo information will be lost if you clean-up.\n\
4154 Clean-up will move all unused files to a \"dead\" location."));
4156 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4157 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4158 checker.set_default_response (RESPONSE_CANCEL);
4160 checker.set_name (_("CleanupDialog"));
4161 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4162 checker.set_position (Gtk::WIN_POS_MOUSE);
4164 switch (checker.run()) {
4165 case RESPONSE_ACCEPT:
4171 ARDOUR::CleanupReport rep;
4173 editor->prepare_for_cleanup ();
4175 /* do not allow flush until a session is reloaded */
4177 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4179 act->set_sensitive (false);
4182 if (_session->cleanup_sources (rep)) {
4183 editor->finish_cleanup ();
4187 editor->finish_cleanup ();
4190 display_cleanup_results (rep, _("Cleaned Files"), false);
4194 ARDOUR_UI::flush_trash ()
4196 if (_session == 0) {
4197 /* shouldn't happen: menu item is insensitive */
4201 ARDOUR::CleanupReport rep;
4203 if (_session->cleanup_trash_sources (rep)) {
4207 display_cleanup_results (rep, _("deleted file"), true);
4211 ARDOUR_UI::cleanup_peakfiles ()
4213 if (_session == 0) {
4214 /* shouldn't happen: menu item is insensitive */
4218 if (! _session->can_cleanup_peakfiles ()) {
4222 // get all region-views in this session
4224 TrackViewList empty;
4226 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4227 std::list<RegionView*> views = rs.by_layer();
4229 // remove displayed audio-region-views waveforms
4230 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4231 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4232 if (!arv) { continue ; }
4233 arv->delete_waves();
4236 // cleanup peak files:
4237 // - stop pending peakfile threads
4238 // - close peakfiles if any
4239 // - remove peak dir in session
4240 // - setup peakfiles (background thread)
4241 _session->cleanup_peakfiles ();
4243 // re-add waves to ARV
4244 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4245 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4246 if (!arv) { continue ; }
4247 arv->create_waves();
4251 PresentationInfo::order_t
4252 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4254 if (editor->get_selection().tracks.empty()) {
4255 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4258 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4261 we want the new routes to have their order keys set starting from
4262 the highest order key in the selection + 1 (if available).
4265 if (place == RouteDialogs::AfterSelection) {
4266 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4268 order_hint = rtav->route()->presentation_info().order();
4271 } else if (place == RouteDialogs::BeforeSelection) {
4272 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4274 order_hint = rtav->route()->presentation_info().order();
4276 } else if (place == RouteDialogs::First) {
4279 /* leave order_hint at max_order */
4286 ARDOUR_UI::start_duplicate_routes ()
4288 if (!duplicate_routes_dialog) {
4289 duplicate_routes_dialog = new DuplicateRouteDialog;
4292 if (duplicate_routes_dialog->restart (_session)) {
4296 duplicate_routes_dialog->present ();
4300 ARDOUR_UI::add_route ()
4302 if (!add_route_dialog.get (false)) {
4303 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4310 if (add_route_dialog->is_visible()) {
4311 /* we're already doing this */
4315 add_route_dialog->set_position (WIN_POS_MOUSE);
4316 add_route_dialog->present();
4320 ARDOUR_UI::add_route_dialog_response (int r)
4323 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4330 case AddRouteDialog::Add:
4331 add_route_dialog->reset_name_edited ();
4333 case AddRouteDialog::AddAndClose:
4334 add_route_dialog->ArdourDialog::on_response (r);
4337 add_route_dialog->ArdourDialog::on_response (r);
4341 std::string template_path = add_route_dialog->get_template_path();
4342 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4343 meta_route_setup (template_path.substr (11));
4347 if ((count = add_route_dialog->count()) <= 0) {
4351 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4352 const string name_template = add_route_dialog->name_template ();
4353 DisplaySuspender ds;
4355 if (!template_path.empty ()) {
4356 if (add_route_dialog->name_template_is_default ()) {
4357 _session->new_route_from_template (count, order, template_path, string ());
4359 _session->new_route_from_template (count, order, template_path, name_template);
4364 ChanCount input_chan= add_route_dialog->channels ();
4365 ChanCount output_chan;
4366 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4367 RouteGroup* route_group = add_route_dialog->route_group ();
4368 AutoConnectOption oac = Config->get_output_auto_connect();
4369 bool strict_io = add_route_dialog->use_strict_io ();
4371 if (oac & AutoConnectMaster) {
4372 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4373 output_chan.set (DataType::MIDI, 0);
4375 output_chan = input_chan;
4378 /* XXX do something with name template */
4380 Session::ProcessorChangeBlocker pcb (_session);
4382 switch (add_route_dialog->type_wanted()) {
4383 case AddRouteDialog::AudioTrack:
4384 session_add_audio_route (true, input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4386 case AddRouteDialog::MidiTrack:
4387 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4389 case AddRouteDialog::MixedTrack:
4390 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4392 case AddRouteDialog::AudioBus:
4393 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4395 case AddRouteDialog::MidiBus:
4396 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4398 case AddRouteDialog::VCAMaster:
4399 _session->vca_manager().create_vca (count, name_template);
4405 ARDOUR_UI::stop_video_server (bool ask_confirm)
4407 if (!video_server_process && ask_confirm) {
4408 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4410 if (video_server_process) {
4412 ArdourDialog confirm (_("Stop Video-Server"), true);
4413 Label m (_("Do you really want to stop the Video Server?"));
4414 confirm.get_vbox()->pack_start (m, true, true);
4415 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4416 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4417 confirm.show_all ();
4418 if (confirm.run() == RESPONSE_CANCEL) {
4422 delete video_server_process;
4423 video_server_process =0;
4428 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4430 ARDOUR_UI::start_video_server( float_window, true);
4434 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4440 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4441 if (video_server_process) {
4442 popup_error(_("The Video Server is already started."));
4444 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4450 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4452 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4454 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4456 video_server_dialog->set_transient_for (*float_window);
4459 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4460 video_server_dialog->hide();
4462 ResponseType r = (ResponseType) video_server_dialog->run ();
4463 video_server_dialog->hide();
4464 if (r != RESPONSE_ACCEPT) { return false; }
4465 if (video_server_dialog->show_again()) {
4466 Config->set_show_video_server_dialog(false);
4470 std::string icsd_exec = video_server_dialog->get_exec_path();
4471 std::string icsd_docroot = video_server_dialog->get_docroot();
4472 #ifndef PLATFORM_WINDOWS
4473 if (icsd_docroot.empty()) {
4474 icsd_docroot = VideoUtils::video_get_docroot (Config);
4479 #ifdef PLATFORM_WINDOWS
4480 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4481 /* OK, allow all drive letters */
4484 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4485 warning << _("Specified docroot is not an existing directory.") << endmsg;
4488 #ifndef PLATFORM_WINDOWS
4489 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4490 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4491 warning << _("Given Video Server is not an executable file.") << endmsg;
4495 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4496 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4497 warning << _("Given Video Server is not an executable file.") << endmsg;
4503 argp=(char**) calloc(9,sizeof(char*));
4504 argp[0] = strdup(icsd_exec.c_str());
4505 argp[1] = strdup("-P");
4506 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4507 argp[3] = strdup("-p");
4508 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4509 argp[5] = strdup("-C");
4510 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4511 argp[7] = strdup(icsd_docroot.c_str());
4513 stop_video_server();
4515 #ifdef PLATFORM_WINDOWS
4516 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4517 /* OK, allow all drive letters */
4520 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4521 Config->set_video_advanced_setup(false);
4523 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4524 Config->set_video_server_url(url_str);
4525 Config->set_video_server_docroot(icsd_docroot);
4526 Config->set_video_advanced_setup(true);
4529 if (video_server_process) {
4530 delete video_server_process;
4533 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4534 if (video_server_process->start()) {
4535 warning << _("Cannot launch the video-server") << endmsg;
4538 int timeout = 120; // 6 sec
4539 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4540 Glib::usleep (50000);
4542 if (--timeout <= 0 || !video_server_process->is_running()) break;
4545 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4547 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4548 delete video_server_process;
4549 video_server_process = 0;
4557 ARDOUR_UI::add_video (Gtk::Window* float_window)
4563 if (!start_video_server(float_window, false)) {
4564 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4569 add_video_dialog->set_transient_for (*float_window);
4572 if (add_video_dialog->is_visible()) {
4573 /* we're already doing this */
4577 ResponseType r = (ResponseType) add_video_dialog->run ();
4578 add_video_dialog->hide();
4579 if (r != RESPONSE_ACCEPT) { return; }
4581 bool local_file, orig_local_file;
4582 std::string path = add_video_dialog->file_name(local_file);
4584 std::string orig_path = path;
4585 orig_local_file = local_file;
4587 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4589 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4590 warning << string_compose(_("could not open %1"), path) << endmsg;
4593 if (!local_file && path.length() == 0) {
4594 warning << _("no video-file selected") << endmsg;
4598 std::string audio_from_video;
4599 bool detect_ltc = false;
4601 switch (add_video_dialog->import_option()) {
4602 case VTL_IMPORT_TRANSCODE:
4604 TranscodeVideoDialog *transcode_video_dialog;
4605 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4606 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4607 transcode_video_dialog->hide();
4608 if (r != RESPONSE_ACCEPT) {
4609 delete transcode_video_dialog;
4613 audio_from_video = transcode_video_dialog->get_audiofile();
4615 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4618 else if (!audio_from_video.empty()) {
4619 editor->embed_audio_from_video(
4621 video_timeline->get_offset(),
4622 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4625 switch (transcode_video_dialog->import_option()) {
4626 case VTL_IMPORT_TRANSCODED:
4627 path = transcode_video_dialog->get_filename();
4630 case VTL_IMPORT_REFERENCE:
4633 delete transcode_video_dialog;
4636 delete transcode_video_dialog;
4640 case VTL_IMPORT_NONE:
4644 /* strip _session->session_directory().video_path() from video file if possible */
4645 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4646 path=path.substr(_session->session_directory().video_path().size());
4647 if (path.at(0) == G_DIR_SEPARATOR) {
4648 path=path.substr(1);
4652 video_timeline->set_update_session_fps(auto_set_session_fps);
4654 if (video_timeline->video_file_info(path, local_file)) {
4655 XMLNode* node = new XMLNode(X_("Videotimeline"));
4656 node->set_property (X_("Filename"), path);
4657 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4658 node->set_property (X_("LocalFile"), local_file);
4659 if (orig_local_file) {
4660 node->set_property (X_("OriginalVideoFile"), orig_path);
4662 node->remove_property (X_("OriginalVideoFile"));
4664 _session->add_extra_xml (*node);
4665 _session->set_dirty ();
4667 if (!audio_from_video.empty() && detect_ltc) {
4668 std::vector<LTCFileReader::LTCMap> ltc_seq;
4671 /* TODO ask user about TV standard (LTC alignment if any) */
4672 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4673 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4675 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4677 /* TODO seek near end of file, and read LTC until end.
4678 * if it fails to find any LTC samples, scan complete file
4680 * calculate drift of LTC compared to video-duration,
4681 * ask user for reference (timecode from start/mid/end)
4684 // LTCFileReader will have written error messages
4687 ::g_unlink(audio_from_video.c_str());
4689 if (ltc_seq.size() == 0) {
4690 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4692 /* the very first TC in the file is somteimes not aligned properly */
4693 int i = ltc_seq.size() -1;
4694 ARDOUR::sampleoffset_t video_start_offset =
4695 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4696 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4697 video_timeline->set_offset(video_start_offset);
4701 _session->maybe_update_session_range(
4702 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4703 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4706 if (add_video_dialog->launch_xjadeo() && local_file) {
4707 editor->set_xjadeo_sensitive(true);
4708 editor->toggle_xjadeo_proc(1);
4710 editor->toggle_xjadeo_proc(0);
4712 editor->toggle_ruler_video(true);
4717 ARDOUR_UI::remove_video ()
4719 video_timeline->close_session();
4720 editor->toggle_ruler_video(false);
4723 video_timeline->set_offset_locked(false);
4724 video_timeline->set_offset(0);
4726 /* delete session state */
4727 XMLNode* node = new XMLNode(X_("Videotimeline"));
4728 _session->add_extra_xml(*node);
4729 node = new XMLNode(X_("Videomonitor"));
4730 _session->add_extra_xml(*node);
4731 node = new XMLNode(X_("Videoexport"));
4732 _session->add_extra_xml(*node);
4733 stop_video_server();
4737 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4739 if (localcacheonly) {
4740 video_timeline->vmon_update();
4742 video_timeline->flush_cache();
4744 editor->queue_visual_videotimeline_update();
4748 ARDOUR_UI::export_video (bool range)
4750 if (ARDOUR::Config->get_show_video_export_info()) {
4751 ExportVideoInfobox infobox (_session);
4752 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4753 if (infobox.show_again()) {
4754 ARDOUR::Config->set_show_video_export_info(false);
4757 case GTK_RESPONSE_YES:
4758 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4764 export_video_dialog->set_session (_session);
4765 export_video_dialog->apply_state(editor->get_selection().time, range);
4766 export_video_dialog->run ();
4767 export_video_dialog->hide ();
4771 ARDOUR_UI::preferences_settings () const
4776 node = _session->instant_xml(X_("Preferences"));
4778 node = Config->instant_xml(X_("Preferences"));
4782 node = new XMLNode (X_("Preferences"));
4789 ARDOUR_UI::mixer_settings () const
4794 node = _session->instant_xml(X_("Mixer"));
4796 node = Config->instant_xml(X_("Mixer"));
4800 node = new XMLNode (X_("Mixer"));
4807 ARDOUR_UI::main_window_settings () const
4812 node = _session->instant_xml(X_("Main"));
4814 node = Config->instant_xml(X_("Main"));
4818 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4819 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4824 node = new XMLNode (X_("Main"));
4831 ARDOUR_UI::editor_settings () const
4836 node = _session->instant_xml(X_("Editor"));
4838 node = Config->instant_xml(X_("Editor"));
4842 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4843 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4848 node = new XMLNode (X_("Editor"));
4855 ARDOUR_UI::keyboard_settings () const
4859 node = Config->extra_xml(X_("Keyboard"));
4862 node = new XMLNode (X_("Keyboard"));
4869 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4872 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4873 _session->locations()->add (location);
4878 ARDOUR_UI::halt_on_xrun_message ()
4880 cerr << "HALT on xrun\n";
4881 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4886 ARDOUR_UI::xrun_handler (samplepos_t where)
4892 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4894 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4895 create_xrun_marker(where);
4898 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4899 halt_on_xrun_message ();
4904 ARDOUR_UI::disk_overrun_handler ()
4906 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4908 if (!have_disk_speed_dialog_displayed) {
4909 have_disk_speed_dialog_displayed = true;
4910 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4911 The disk system on your computer\n\
4912 was not able to keep up with %1.\n\
4914 Specifically, it failed to write data to disk\n\
4915 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4916 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4922 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4923 static MessageDialog *scan_dlg = NULL;
4924 static ProgressBar *scan_pbar = NULL;
4925 static HBox *scan_tbox = NULL;
4926 static Gtk::Button *scan_timeout_button;
4929 ARDOUR_UI::cancel_plugin_scan ()
4931 PluginManager::instance().cancel_plugin_scan();
4935 ARDOUR_UI::cancel_plugin_timeout ()
4937 PluginManager::instance().cancel_plugin_timeout();
4938 scan_timeout_button->set_sensitive (false);
4942 ARDOUR_UI::plugin_scan_timeout (int timeout)
4944 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4948 scan_pbar->set_sensitive (false);
4949 scan_timeout_button->set_sensitive (true);
4950 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4953 scan_pbar->set_sensitive (false);
4954 scan_timeout_button->set_sensitive (false);
4960 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4962 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4966 const bool cancelled = PluginManager::instance().cancelled();
4967 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4968 if (cancelled && scan_dlg->is_mapped()) {
4973 if (cancelled || !can_cancel) {
4978 static Gtk::Button *cancel_button;
4980 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4981 VBox* vbox = scan_dlg->get_vbox();
4982 vbox->set_size_request(400,-1);
4983 scan_dlg->set_title (_("Scanning for plugins"));
4985 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4986 cancel_button->set_name ("EditorGTKButton");
4987 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4988 cancel_button->show();
4990 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4992 scan_tbox = manage( new HBox() );
4994 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4995 scan_timeout_button->set_name ("EditorGTKButton");
4996 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4997 scan_timeout_button->show();
4999 scan_pbar = manage(new ProgressBar());
5000 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5001 scan_pbar->set_text(_("Scan Timeout"));
5004 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5005 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5007 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5010 assert(scan_dlg && scan_tbox && cancel_button);
5012 if (type == X_("closeme")) {
5016 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5019 if (!can_cancel || !cancelled) {
5020 scan_timeout_button->set_sensitive(false);
5022 cancel_button->set_sensitive(can_cancel && !cancelled);
5028 ARDOUR_UI::gui_idle_handler ()
5031 /* due to idle calls, gtk_events_pending() may always return true */
5032 while (gtk_events_pending() && --timeout) {
5033 gtk_main_iteration ();
5038 ARDOUR_UI::disk_underrun_handler ()
5040 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5042 if (!have_disk_speed_dialog_displayed) {
5043 have_disk_speed_dialog_displayed = true;
5044 MessageDialog* msg = new MessageDialog (
5045 _main_window, string_compose (_("The disk system on your computer\n\
5046 was not able to keep up with %1.\n\
5048 Specifically, it failed to read data from disk\n\
5049 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5050 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5056 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5058 have_disk_speed_dialog_displayed = false;
5063 ARDOUR_UI::session_dialog (std::string msg)
5065 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5069 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5076 ARDOUR_UI::pending_state_dialog ()
5078 HBox* hbox = manage (new HBox());
5079 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5080 ArdourDialog dialog (_("Crash Recovery"), true);
5081 Label message (string_compose (_("\
5082 This session appears to have been in the\n\
5083 middle of recording when %1 or\n\
5084 the computer was shutdown.\n\
5086 %1 can recover any captured audio for\n\
5087 you, or it can ignore it. Please decide\n\
5088 what you would like to do.\n"), PROGRAM_NAME));
5089 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5090 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5091 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5092 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5093 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5094 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5095 dialog.set_default_response (RESPONSE_ACCEPT);
5096 dialog.set_position (WIN_POS_CENTER);
5101 switch (dialog.run ()) {
5102 case RESPONSE_ACCEPT:
5110 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5112 HBox* hbox = new HBox();
5113 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5114 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5115 Label message (string_compose (_("\
5116 This session was created with a sample rate of %1 Hz, but\n\
5117 %2 is currently running at %3 Hz. If you load this session,\n\
5118 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5120 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5121 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5122 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5123 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5124 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5125 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5126 dialog.set_default_response (RESPONSE_ACCEPT);
5127 dialog.set_position (WIN_POS_CENTER);
5132 switch (dialog.run()) {
5133 case RESPONSE_ACCEPT:
5143 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5145 MessageDialog msg (string_compose (_("\
5146 This session was created with a sample rate of %1 Hz, but\n\
5147 %2 is currently running at %3 Hz.\n\
5148 Audio will be recorded and played at the wrong sample rate.\n\
5149 Re-Configure the Audio Engine in\n\
5150 Menu > Window > Audio/Midi Setup"),
5151 desired, PROGRAM_NAME, actual),
5153 Gtk::MESSAGE_WARNING);
5158 ARDOUR_UI::use_config ()
5160 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5162 set_transport_controllable_state (*node);
5167 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5169 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5171 primary_clock->set (pos);
5173 case DeltaEditPoint:
5174 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5176 case DeltaOriginMarker:
5178 Location* loc = _session->locations()->clock_origin_location ();
5179 primary_clock->set (pos, false, loc ? loc->start() : 0);
5184 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5186 secondary_clock->set (pos);
5188 case DeltaEditPoint:
5189 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5191 case DeltaOriginMarker:
5193 Location* loc = _session->locations()->clock_origin_location ();
5194 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5199 if (big_clock_window) {
5200 big_clock->set (pos);
5202 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5207 ARDOUR_UI::record_state_changed ()
5209 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5212 /* why bother - the clock isn't visible */
5216 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5218 if (big_clock_window) {
5219 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5220 big_clock->set_active (true);
5222 big_clock->set_active (false);
5229 ARDOUR_UI::first_idle ()
5232 _session->allow_auto_play (true);
5236 editor->first_idle();
5239 /* in 1 second, hide the splash screen
5241 * Consider hiding it *now*. If a user opens opens a dialog
5242 * during that one second while the splash is still visible,
5243 * the dialog will push-back the splash.
5244 * Closing the dialog later will pop it back.
5246 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5248 Keyboard::set_can_save_keybindings (true);
5253 ARDOUR_UI::store_clock_modes ()
5255 XMLNode* node = new XMLNode(X_("ClockModes"));
5257 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5258 XMLNode* child = new XMLNode (X_("Clock"));
5260 child->set_property (X_("name"), (*x)->name());
5261 child->set_property (X_("mode"), (*x)->mode());
5262 child->set_property (X_("on"), (*x)->on());
5264 node->add_child_nocopy (*child);
5267 _session->add_extra_xml (*node);
5268 _session->set_dirty ();
5272 ARDOUR_UI::setup_profile ()
5274 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5275 Profile->set_small_screen ();
5278 if (g_getenv ("TRX")) {
5279 Profile->set_trx ();
5282 if (g_getenv ("MIXBUS")) {
5283 Profile->set_mixbus ();
5288 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5290 MissingFileDialog dialog (s, str, type);
5295 int result = dialog.run ();
5302 return 1; // quit entire session load
5305 result = dialog.get_action ();
5311 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5313 AmbiguousFileDialog dialog (file, hits);
5320 return dialog.get_which ();
5323 /** Allocate our thread-local buffers */
5325 ARDOUR_UI::get_process_buffers ()
5327 _process_thread->get_buffers ();
5330 /** Drop our thread-local buffers */
5332 ARDOUR_UI::drop_process_buffers ()
5334 _process_thread->drop_buffers ();
5338 ARDOUR_UI::feedback_detected ()
5340 _feedback_exists = true;
5344 ARDOUR_UI::successful_graph_sort ()
5346 _feedback_exists = false;
5350 ARDOUR_UI::midi_panic ()
5353 _session->midi_panic();
5358 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5360 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5361 const char* end_big = "</span>";
5362 const char* start_mono = "<tt>";
5363 const char* end_mono = "</tt>";
5365 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5366 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5367 "From now on, use the backup copy with older versions of %3"),
5368 xml_path, backup_path, PROGRAM_NAME,
5370 start_mono, end_mono), true);
5376 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5378 using namespace Menu_Helpers;
5380 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5381 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5382 i->set_active (editor_meter->meter_type () == type);
5386 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5388 using namespace Gtk::Menu_Helpers;
5390 Gtk::Menu* m = manage (new Menu);
5391 MenuList& items = m->items ();
5393 RadioMenuItem::Group group;
5395 _suspend_editor_meter_callbacks = true;
5396 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5397 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5398 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5399 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5400 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5401 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5402 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5403 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5404 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5405 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5406 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5408 m->popup (ev->button, ev->time);
5409 _suspend_editor_meter_callbacks = false;
5413 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5415 if (ev->button == 3 && editor_meter) {
5416 popup_editor_meter_menu (ev);
5423 ARDOUR_UI::reset_peak_display ()
5425 if (!_session || !_session->master_out() || !editor_meter) return;
5426 editor_meter->clear_meters();
5427 editor_meter_max_peak = -INFINITY;
5428 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5432 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5434 if (!_session || !_session->master_out()) return;
5435 if (group == _session->master_out()->route_group()) {
5436 reset_peak_display ();
5441 ARDOUR_UI::reset_route_peak_display (Route* route)
5443 if (!_session || !_session->master_out()) return;
5444 if (_session->master_out().get() == route) {
5445 reset_peak_display ();
5450 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5452 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5453 audio_midi_setup->set_position (WIN_POS_CENTER);
5455 if (desired_sample_rate != 0) {
5456 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5457 audio_midi_setup->try_autostart ();
5458 if (ARDOUR::AudioEngine::instance()->running()) {
5465 int response = audio_midi_setup->run();
5467 case Gtk::RESPONSE_DELETE_EVENT:
5468 // after latency callibration engine may run,
5469 // Running() signal was emitted, but dialog will not
5470 // have emitted a response. The user needs to close
5471 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5472 if (!AudioEngine::instance()->running()) {
5477 if (!AudioEngine::instance()->running()) {
5480 audio_midi_setup->hide ();
5488 ARDOUR_UI::transport_numpad_timeout ()
5490 _numpad_locate_happening = false;
5491 if (_numpad_timeout_connection.connected() )
5492 _numpad_timeout_connection.disconnect();
5497 ARDOUR_UI::transport_numpad_decimal ()
5499 _numpad_timeout_connection.disconnect();
5501 if (_numpad_locate_happening) {
5502 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5503 _numpad_locate_happening = false;
5505 _pending_locate_num = 0;
5506 _numpad_locate_happening = true;
5507 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5512 ARDOUR_UI::transport_numpad_event (int num)
5514 if ( _numpad_locate_happening ) {
5515 _pending_locate_num = _pending_locate_num*10 + num;
5518 case 0: toggle_roll(false, false); break;
5519 case 1: transport_rewind(1); break;
5520 case 2: transport_forward(1); break;
5521 case 3: transport_record(true); break;
5522 case 4: toggle_session_auto_loop(); break;
5523 case 5: transport_record(false); toggle_session_auto_loop(); break;
5524 case 6: toggle_punch(); break;
5525 case 7: toggle_click(); break;
5526 case 8: toggle_auto_return(); break;
5527 case 9: toggle_follow_edits(); break;
5533 ARDOUR_UI::set_flat_buttons ()
5535 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5539 ARDOUR_UI::audioengine_became_silent ()
5541 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5543 Gtk::MESSAGE_WARNING,
5547 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5549 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5550 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5551 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5552 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5553 Gtk::HBox pay_button_box;
5554 Gtk::HBox subscribe_button_box;
5556 pay_button_box.pack_start (pay_button, true, false);
5557 subscribe_button_box.pack_start (subscribe_button, true, false);
5559 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 */
5561 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5562 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5564 msg.get_vbox()->pack_start (pay_label);
5565 msg.get_vbox()->pack_start (pay_button_box);
5566 msg.get_vbox()->pack_start (subscribe_label);
5567 msg.get_vbox()->pack_start (subscribe_button_box);
5569 msg.get_vbox()->show_all ();
5571 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5572 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5573 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5578 case Gtk::RESPONSE_YES:
5579 AudioEngine::instance()->reset_silence_countdown ();
5582 case Gtk::RESPONSE_NO:
5584 save_state_canfail ("");
5588 case Gtk::RESPONSE_CANCEL:
5590 /* don't reset, save session and exit */
5596 ARDOUR_UI::hide_application ()
5598 Application::instance ()-> hide ();
5602 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5604 /* icons, titles, WM stuff */
5606 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5608 if (window_icons.empty()) {
5609 Glib::RefPtr<Gdk::Pixbuf> icon;
5610 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5611 window_icons.push_back (icon);
5613 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5614 window_icons.push_back (icon);
5616 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5617 window_icons.push_back (icon);
5619 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5620 window_icons.push_back (icon);
5624 if (!window_icons.empty()) {
5625 window.set_default_icon_list (window_icons);
5628 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5630 if (!name.empty()) {
5634 window.set_title (title.get_string());
5635 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5637 window.set_flags (CAN_FOCUS);
5638 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5640 /* This is a hack to ensure that GTK-accelerators continue to
5641 * work. Once we switch over to entirely native bindings, this will be
5642 * unnecessary and should be removed
5644 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5646 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5647 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5648 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5649 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5653 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5655 Gtkmm2ext::Bindings* bindings = 0;
5656 Gtk::Window* window = 0;
5658 /* until we get ardour bindings working, we are not handling key
5662 if (ev->type != GDK_KEY_PRESS) {
5666 if (event_window == &_main_window) {
5668 window = event_window;
5670 /* find current tab contents */
5672 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5674 /* see if it uses the ardour binding system */
5677 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5680 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5684 window = event_window;
5686 /* see if window uses ardour binding system */
5688 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5691 /* An empty binding set is treated as if it doesn't exist */
5693 if (bindings && bindings->empty()) {
5697 return key_press_focus_accelerator_handler (*window, ev, bindings);
5700 static Gtkmm2ext::Bindings*
5701 get_bindings_from_widget_heirarchy (GtkWidget** w)
5706 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5709 *w = gtk_widget_get_parent (*w);
5712 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5716 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5718 GtkWindow* win = window.gobj();
5719 GtkWidget* focus = gtk_window_get_focus (win);
5720 GtkWidget* binding_widget = focus;
5721 bool special_handling_of_unmodified_accelerators = false;
5722 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5726 /* some widget has keyboard focus */
5728 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5730 /* A particular kind of focusable widget currently has keyboard
5731 * focus. All unmodified key events should go to that widget
5732 * first and not be used as an accelerator by default
5735 special_handling_of_unmodified_accelerators = true;
5739 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5740 if (focus_bindings) {
5741 bindings = focus_bindings;
5742 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5747 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",
5750 Gtkmm2ext::show_gdk_event_state (ev->state),
5751 special_handling_of_unmodified_accelerators,
5752 Keyboard::some_magic_widget_has_focus(),
5754 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5755 ((ev->state & mask) ? "yes" : "no"),
5756 window.get_title()));
5758 /* This exists to allow us to override the way GTK handles
5759 key events. The normal sequence is:
5761 a) event is delivered to a GtkWindow
5762 b) accelerators/mnemonics are activated
5763 c) if (b) didn't handle the event, propagate to
5764 the focus widget and/or focus chain
5766 The problem with this is that if the accelerators include
5767 keys without modifiers, such as the space bar or the
5768 letter "e", then pressing the key while typing into
5769 a text entry widget results in the accelerator being
5770 activated, instead of the desired letter appearing
5773 There is no good way of fixing this, but this
5774 represents a compromise. The idea is that
5775 key events involving modifiers (not Shift)
5776 get routed into the activation pathway first, then
5777 get propagated to the focus widget if necessary.
5779 If the key event doesn't involve modifiers,
5780 we deliver to the focus widget first, thus allowing
5781 it to get "normal text" without interference
5784 Of course, this can also be problematic: if there
5785 is a widget with focus, then it will swallow
5786 all "normal text" accelerators.
5790 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5792 /* no special handling or there are modifiers in effect: accelerate first */
5794 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5795 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5796 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5798 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5799 KeyboardKey k (ev->state, ev->keyval);
5803 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5805 if (bindings->activate (k, Bindings::Press)) {
5806 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5810 if (binding_widget) {
5811 binding_widget = gtk_widget_get_parent (binding_widget);
5812 if (binding_widget) {
5813 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5822 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5824 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5825 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5829 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5831 if (gtk_window_propagate_key_event (win, ev)) {
5832 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5838 /* no modifiers, propagate first */
5840 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5842 if (gtk_window_propagate_key_event (win, ev)) {
5843 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5847 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5848 KeyboardKey k (ev->state, ev->keyval);
5852 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5855 if (bindings->activate (k, Bindings::Press)) {
5856 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5860 if (binding_widget) {
5861 binding_widget = gtk_widget_get_parent (binding_widget);
5862 if (binding_widget) {
5863 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5872 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5874 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5875 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5880 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5885 ARDOUR_UI::load_bindings ()
5887 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5888 error << _("Global keybindings are missing") << endmsg;
5893 ARDOUR_UI::cancel_solo ()
5896 _session->cancel_all_solo ();
5901 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5903 /* this resets focus to the first focusable parent of the given widget,
5904 * or, if there is no focusable parent, cancels focus in the toplevel
5905 * window that the given widget is packed into (if there is one).
5912 Gtk::Widget* top = w->get_toplevel();
5914 if (!top || !top->is_toplevel()) {
5918 w = w->get_parent ();
5922 if (w->is_toplevel()) {
5923 /* Setting the focus widget to a Gtk::Window causes all
5924 * subsequent calls to ::has_focus() on the nominal
5925 * focus widget in that window to return
5926 * false. Workaround: never set focus to the toplevel
5932 if (w->get_can_focus ()) {
5933 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5934 win->set_focus (*w);
5937 w = w->get_parent ();
5940 if (top == &_main_window) {
5944 /* no focusable parent found, cancel focus in top level window.
5945 C++ API cannot be used for this. Thanks, references.
5948 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);