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::session_add_listen_bus (uint32_t how_many, string const & name_template)
2130 routes = _session->new_audio_route (2, 2, 0, how_many, name_template, PresentationInfo::ListenBus, -1);
2132 if (routes.size() != how_many) {
2133 error << string_compose (P_("could not create %1 new listen bus", "could not create %1 new listen busses", how_many), how_many)
2139 display_insufficient_ports_message ();
2143 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2144 (*i)->set_strict_io (true);
2149 ARDOUR_UI::display_insufficient_ports_message ()
2151 MessageDialog msg (_main_window,
2152 string_compose (_("There are insufficient ports available\n\
2153 to create a new track or bus.\n\
2154 You should save %1, exit and\n\
2155 restart with more ports."), PROGRAM_NAME));
2156 pop_back_splash (msg);
2161 ARDOUR_UI::transport_goto_start ()
2164 _session->goto_start();
2166 /* force displayed area in editor to start no matter
2167 what "follow playhead" setting is.
2171 editor->center_screen (_session->current_start_sample ());
2177 ARDOUR_UI::transport_goto_zero ()
2180 _session->request_locate (0);
2182 /* force displayed area in editor to start no matter
2183 what "follow playhead" setting is.
2187 editor->reset_x_origin (0);
2193 ARDOUR_UI::transport_goto_wallclock ()
2195 if (_session && editor) {
2199 samplepos_t samples;
2202 localtime_r (&now, &tmnow);
2204 samplecnt_t sample_rate = _session->sample_rate();
2206 if (sample_rate == 0) {
2207 /* no frame rate available */
2211 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2212 samples += tmnow.tm_min * (60 * sample_rate);
2213 samples += tmnow.tm_sec * sample_rate;
2215 _session->request_locate (samples, _session->transport_rolling ());
2217 /* force displayed area in editor to start no matter
2218 what "follow playhead" setting is.
2222 editor->center_screen (samples);
2228 ARDOUR_UI::transport_goto_end ()
2231 samplepos_t const sample = _session->current_end_sample();
2232 _session->request_locate (sample);
2234 /* force displayed area in editor to start no matter
2235 what "follow playhead" setting is.
2239 editor->center_screen (sample);
2245 ARDOUR_UI::transport_stop ()
2251 if (_session->is_auditioning()) {
2252 _session->cancel_audition ();
2256 _session->request_stop (false, true);
2259 /** Check if any tracks are record enabled. If none are, record enable all of them.
2260 * @return true if track record-enabled status was changed, false otherwise.
2263 ARDOUR_UI::trx_record_enable_all_tracks ()
2269 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2270 bool none_record_enabled = true;
2272 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2273 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2276 if (t->rec_enable_control()->get_value()) {
2277 none_record_enabled = false;
2282 if (none_record_enabled) {
2283 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2286 return none_record_enabled;
2290 ARDOUR_UI::transport_record (bool roll)
2293 switch (_session->record_status()) {
2294 case Session::Disabled:
2295 if (_session->ntracks() == 0) {
2296 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."));
2300 if (Profile->get_trx()) {
2301 roll = trx_record_enable_all_tracks ();
2303 _session->maybe_enable_record ();
2308 case Session::Recording:
2310 _session->request_stop();
2312 _session->disable_record (false, true);
2316 case Session::Enabled:
2317 _session->disable_record (false, true);
2323 ARDOUR_UI::transport_roll ()
2329 if (_session->is_auditioning()) {
2333 if (_session->config.get_external_sync()) {
2334 switch (TransportMasterManager::instance().current()->type()) {
2338 /* transport controlled by the master */
2343 bool rolling = _session->transport_rolling();
2345 if (_session->get_play_loop()) {
2347 /* If loop playback is not a mode, then we should cancel
2348 it when this action is requested. If it is a mode
2349 we just leave it in place.
2352 if (!Config->get_loop_is_mode()) {
2353 /* XXX it is not possible to just leave seamless loop and keep
2354 playing at present (nov 4th 2009)
2356 if (!Config->get_seamless_loop()) {
2357 /* stop loop playback and stop rolling */
2358 _session->request_play_loop (false, true);
2359 } else if (rolling) {
2360 /* stop loop playback but keep rolling */
2361 _session->request_play_loop (false, false);
2365 } else if (_session->get_play_range () ) {
2366 /* stop playing a range if we currently are */
2367 _session->request_play_range (0, true);
2371 _session->request_transport_speed (1.0f);
2376 ARDOUR_UI::get_smart_mode() const
2378 return ( editor->get_smart_mode() );
2383 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2389 if (_session->is_auditioning()) {
2390 _session->cancel_audition ();
2394 if (_session->config.get_external_sync()) {
2395 switch (TransportMasterManager::instance().current()->type()) {
2399 /* transport controlled by the master */
2404 bool rolling = _session->transport_rolling();
2405 bool affect_transport = true;
2407 if (rolling && roll_out_of_bounded_mode) {
2408 /* drop out of loop/range playback but leave transport rolling */
2409 if (_session->get_play_loop()) {
2410 if (_session->actively_recording()) {
2412 /* just stop using the loop, then actually stop
2415 _session->request_play_loop (false, affect_transport);
2418 if (Config->get_seamless_loop()) {
2419 /* the disk buffers contain copies of the loop - we can't
2420 just keep playing, so stop the transport. the user
2421 can restart as they wish.
2423 affect_transport = true;
2425 /* disk buffers are normal, so we can keep playing */
2426 affect_transport = false;
2428 _session->request_play_loop (false, affect_transport);
2430 } else if (_session->get_play_range ()) {
2431 affect_transport = false;
2432 _session->request_play_range (0, true);
2436 if (affect_transport) {
2438 _session->request_stop (with_abort, true);
2440 } else if (!with_abort) { /* with_abort == true means the
2441 * command was intended to stop
2442 * transport, not start.
2445 /* the only external sync condition we can be in here
2446 * would be Engine (JACK) sync, in which case we still
2450 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
2451 _session->request_play_range (&editor->get_selection().time, true);
2452 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2454 _session->request_transport_speed (1.0f);
2460 ARDOUR_UI::toggle_session_auto_loop ()
2466 Location * looploc = _session->locations()->auto_loop_location();
2472 if (_session->get_play_loop()) {
2474 /* looping enabled, our job is to disable it */
2476 _session->request_play_loop (false);
2480 /* looping not enabled, our job is to enable it.
2482 loop-is-NOT-mode: this action always starts the transport rolling.
2483 loop-IS-mode: this action simply sets the loop play mechanism, but
2484 does not start transport.
2486 if (Config->get_loop_is_mode()) {
2487 _session->request_play_loop (true, false);
2489 _session->request_play_loop (true, true);
2493 //show the loop markers
2494 looploc->set_hidden (false, this);
2498 ARDOUR_UI::transport_play_selection ()
2504 editor->play_selection ();
2508 ARDOUR_UI::transport_play_preroll ()
2513 editor->play_with_preroll ();
2517 ARDOUR_UI::transport_rec_preroll ()
2522 editor->rec_with_preroll ();
2526 ARDOUR_UI::transport_rec_count_in ()
2531 editor->rec_with_count_in ();
2535 ARDOUR_UI::transport_rewind (int option)
2537 float current_transport_speed;
2540 current_transport_speed = _session->transport_speed();
2542 if (current_transport_speed >= 0.0f) {
2545 _session->request_transport_speed (-1.0f);
2548 _session->request_transport_speed (-4.0f);
2551 _session->request_transport_speed (-0.5f);
2556 _session->request_transport_speed (current_transport_speed * 1.5f);
2562 ARDOUR_UI::transport_forward (int option)
2568 float current_transport_speed = _session->transport_speed();
2570 if (current_transport_speed <= 0.0f) {
2573 _session->request_transport_speed (1.0f);
2576 _session->request_transport_speed (4.0f);
2579 _session->request_transport_speed (0.5f);
2584 _session->request_transport_speed (current_transport_speed * 1.5f);
2589 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2595 boost::shared_ptr<Route> r;
2597 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2599 boost::shared_ptr<Track> t;
2601 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2602 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2608 ARDOUR_UI::map_transport_state ()
2611 layered_button.set_sensitive (false);
2615 shuttle_box.map_transport_state ();
2617 float sp = _session->transport_speed();
2620 layered_button.set_sensitive (!_session->actively_recording ());
2622 layered_button.set_sensitive (true);
2623 update_disk_space ();
2628 ARDOUR_UI::blink_handler (bool blink_on)
2630 sync_blink (blink_on);
2632 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2635 error_blink (blink_on);
2636 solo_blink (blink_on);
2637 audition_blink (blink_on);
2638 feedback_blink (blink_on);
2642 ARDOUR_UI::update_clocks ()
2644 if (!_session) return;
2646 if (editor && !editor->dragging_playhead()) {
2647 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2652 ARDOUR_UI::start_clocking ()
2654 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2655 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2657 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2662 ARDOUR_UI::stop_clocking ()
2664 clock_signal_connection.disconnect ();
2668 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2672 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2674 label->set_text (buf);
2675 bar->set_fraction (fraction);
2677 /* process events, redraws, etc. */
2679 while (gtk_events_pending()) {
2680 gtk_main_iteration ();
2683 return true; /* continue with save-as */
2687 ARDOUR_UI::save_session_as ()
2693 if (_session->dirty()) {
2694 vector<string> actions;
2695 actions.push_back (_("Abort save-as"));
2696 actions.push_back (_("Don't save now, just save-as"));
2697 actions.push_back (_("Save it first"));
2698 switch (ask_about_saving_session(actions)) {
2703 if (save_state_canfail ("")) {
2704 MessageDialog msg (_main_window,
2705 string_compose (_("\
2706 %1 was unable to save your session.\n\n\
2707 If you still wish to proceed, please use the\n\n\
2708 \"Don't save now\" option."), PROGRAM_NAME));
2709 pop_back_splash(msg);
2715 _session->remove_pending_capture_state ();
2720 if (!save_as_dialog) {
2721 save_as_dialog = new SaveAsDialog;
2724 save_as_dialog->set_name (_session->name());
2726 int response = save_as_dialog->run ();
2728 save_as_dialog->hide ();
2731 case Gtk::RESPONSE_OK:
2740 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2741 sa.new_name = save_as_dialog->new_name ();
2742 sa.switch_to = save_as_dialog->switch_to();
2743 sa.copy_media = save_as_dialog->copy_media();
2744 sa.copy_external = save_as_dialog->copy_external();
2745 sa.include_media = save_as_dialog->include_media ();
2747 /* Only bother with a progress dialog if we're going to copy
2748 media into the save-as target. Without that choice, this
2749 will be very fast because we're only talking about a few kB's to
2750 perhaps a couple of MB's of data.
2753 ArdourDialog progress_dialog (_("Save As"), true);
2756 if (sa.include_media && sa.copy_media) {
2758 Gtk::Label* label = manage (new Gtk::Label());
2759 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2761 progress_dialog.get_vbox()->pack_start (*label);
2762 progress_dialog.get_vbox()->pack_start (*progress_bar);
2764 progress_bar->show ();
2766 /* this signal will be emitted from within this, the calling thread,
2767 * after every file is copied. It provides information on percentage
2768 * complete (in terms of total data to copy), the number of files
2769 * copied so far, and the total number to copy.
2772 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2774 progress_dialog.show_all ();
2775 progress_dialog.present ();
2778 if (_session->save_as (sa)) {
2780 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2784 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2785 * the trick is this: if the new session was copy with media included,
2786 * then Session::save_as() will have already done a neat trick to avoid
2787 * us having to unload and load the new state. But if the media was not
2788 * included, then this is required (it avoids us having to otherwise
2789 * drop all references to media (sources).
2792 if (!sa.include_media && sa.switch_to) {
2793 unload_session (false);
2794 load_session (sa.final_session_folder_name, sa.new_name);
2799 ARDOUR_UI::archive_session ()
2807 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2809 SessionArchiveDialog sad;
2810 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2811 int response = sad.run ();
2813 if (response != Gtk::RESPONSE_OK) {
2818 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2819 MessageDialog msg (_("Session Archiving failed."));
2825 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2829 struct tm local_time;
2832 localtime_r (&n, &local_time);
2833 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2834 if (switch_to_it && _session->dirty ()) {
2835 save_state_canfail ("");
2838 save_state (timebuf, switch_to_it);
2843 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2847 prompter.get_result (snapname);
2849 bool do_save = (snapname.length() != 0);
2852 char illegal = Session::session_name_is_legal(snapname);
2854 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2855 "snapshot names may not contain a '%1' character"), illegal));
2861 vector<std::string> p;
2862 get_state_files_in_directory (_session->session_directory().root_path(), p);
2863 vector<string> n = get_file_names_no_extension (p);
2865 if (find (n.begin(), n.end(), snapname) != n.end()) {
2867 do_save = overwrite_file_dialog (prompter,
2868 _("Confirm Snapshot Overwrite"),
2869 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2873 save_state (snapname, switch_to_it);
2883 /** Ask the user for the name of a new snapshot and then take it.
2887 ARDOUR_UI::snapshot_session (bool switch_to_it)
2889 if (switch_to_it && _session->dirty()) {
2890 vector<string> actions;
2891 actions.push_back (_("Abort saving snapshot"));
2892 actions.push_back (_("Don't save now, just snapshot"));
2893 actions.push_back (_("Save it first"));
2894 switch (ask_about_saving_session(actions)) {
2899 if (save_state_canfail ("")) {
2900 MessageDialog msg (_main_window,
2901 string_compose (_("\
2902 %1 was unable to save your session.\n\n\
2903 If you still wish to proceed, please use the\n\n\
2904 \"Don't save now\" option."), PROGRAM_NAME));
2905 pop_back_splash(msg);
2911 _session->remove_pending_capture_state ();
2916 Prompter prompter (true);
2917 prompter.set_name ("Prompter");
2918 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2920 prompter.set_title (_("Snapshot and switch"));
2921 prompter.set_prompt (_("New session name"));
2923 prompter.set_title (_("Take Snapshot"));
2924 prompter.set_prompt (_("Name of new snapshot"));
2928 prompter.set_initial_text (_session->snap_name());
2930 Glib::DateTime tm (g_date_time_new_now_local ());
2931 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2934 bool finished = false;
2936 switch (prompter.run()) {
2937 case RESPONSE_ACCEPT:
2939 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2950 /** Ask the user for a new session name and then rename the session to it.
2954 ARDOUR_UI::rename_session ()
2960 Prompter prompter (true);
2963 prompter.set_name ("Prompter");
2964 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2965 prompter.set_title (_("Rename Session"));
2966 prompter.set_prompt (_("New session name"));
2969 switch (prompter.run()) {
2970 case RESPONSE_ACCEPT:
2972 prompter.get_result (name);
2974 bool do_rename = (name.length() != 0);
2977 char illegal = Session::session_name_is_legal (name);
2980 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2981 "session names may not contain a '%1' character"), illegal));
2986 switch (_session->rename (name)) {
2988 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2989 msg.set_position (WIN_POS_MOUSE);
2997 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2998 msg.set_position (WIN_POS_MOUSE);
3014 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3016 if (!_session || _session->deletion_in_progress()) {
3020 XMLNode* node = new XMLNode (X_("UI"));
3022 WM::Manager::instance().add_state (*node);
3024 node->add_child_nocopy (gui_object_state->get_state());
3026 _session->add_extra_xml (*node);
3028 if (export_video_dialog) {
3029 _session->add_extra_xml (export_video_dialog->get_state());
3032 save_state_canfail (name, switch_to_it);
3036 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3041 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3046 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3051 ARDOUR_UI::primary_clock_value_changed ()
3054 _session->request_locate (primary_clock->current_time ());
3059 ARDOUR_UI::big_clock_value_changed ()
3062 _session->request_locate (big_clock->current_time ());
3067 ARDOUR_UI::secondary_clock_value_changed ()
3070 _session->request_locate (secondary_clock->current_time ());
3074 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3076 if (response == RESPONSE_ACCEPT) {
3077 const string name = d->get_template_name ();
3078 const string desc = d->get_description ();
3080 int failed = _session->save_template (name, desc);
3082 if (failed == -2) { /* file already exists. */
3083 bool overwrite = overwrite_file_dialog (*d,
3084 _("Confirm Template Overwrite"),
3085 _("A template already exists with that name. Do you want to overwrite it?"));
3088 _session->save_template (name, desc, true);
3100 ARDOUR_UI::save_template ()
3102 if (!check_audioengine (_main_window)) {
3106 const std::string desc = SessionMetadata::Metadata()->description ();
3107 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3108 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3112 void ARDOUR_UI::manage_templates ()
3119 ARDOUR_UI::edit_metadata ()
3121 SessionMetadataEditor dialog;
3122 dialog.set_session (_session);
3123 dialog.grab_focus ();
3128 ARDOUR_UI::import_metadata ()
3130 SessionMetadataImporter dialog;
3131 dialog.set_session (_session);
3136 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3138 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3140 MessageDialog msg (str,
3142 Gtk::MESSAGE_WARNING,
3143 Gtk::BUTTONS_YES_NO,
3147 msg.set_name (X_("OpenExistingDialog"));
3148 msg.set_title (_("Open Existing Session"));
3149 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3150 msg.set_position (Gtk::WIN_POS_CENTER);
3151 pop_back_splash (msg);
3153 switch (msg.run()) {
3162 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3164 BusProfile bus_profile;
3167 bus_profile.master_out_channels = 2;
3169 /* get settings from advanced section of NSD */
3170 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3173 // NULL profile: no master, no monitor
3174 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3182 ARDOUR_UI::load_from_application_api (const std::string& path)
3184 /* OS X El Capitan (and probably later) now somehow passes the command
3185 line arguments to an app via the openFile delegate protocol. Ardour
3186 already does its own command line processing, and having both
3187 pathways active causes crashes. So, if the command line was already
3188 set, do nothing here.
3191 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3195 ARDOUR_COMMAND_LINE::session_name = path;
3197 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3199 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3201 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3202 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3203 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3204 * -> SessionDialog is not displayed
3207 if (_session_dialog) {
3208 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3209 std::string session_path = path;
3210 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3211 session_path = Glib::path_get_dirname (session_path);
3213 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3214 _session_dialog->set_provided_session (session_name, session_path);
3215 _session_dialog->response (RESPONSE_NONE);
3216 _session_dialog->hide();
3221 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3222 /* /path/to/foo => /path/to/foo, foo */
3223 rv = load_session (path, basename_nosuffix (path));
3225 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3226 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3229 // if load_session fails -> pop up SessionDialog.
3231 ARDOUR_COMMAND_LINE::session_name = "";
3233 if (get_session_parameters (true, false)) {
3239 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3241 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3243 string session_name;
3244 string session_path;
3245 string template_name;
3247 bool likely_new = false;
3248 bool cancel_not_quit;
3250 /* deal with any existing DIRTY session now, rather than later. don't
3251 * treat a non-dirty session this way, so that it stays visible
3252 * as we bring up the new session dialog.
3255 if (_session && ARDOUR_UI::instance()->video_timeline) {
3256 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3259 /* if there is already a session, relabel the button
3260 on the SessionDialog so that we don't Quit directly
3262 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3264 if (_session && _session->dirty()) {
3265 if (unload_session (false)) {
3266 /* unload cancelled by user */
3269 ARDOUR_COMMAND_LINE::session_name = "";
3272 if (!load_template.empty()) {
3273 should_be_new = true;
3274 template_name = load_template;
3277 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3278 session_path = ARDOUR_COMMAND_LINE::session_name;
3280 if (!session_path.empty()) {
3281 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3282 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3283 /* session/snapshot file, change path to be dir */
3284 session_path = Glib::path_get_dirname (session_path);
3289 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3291 _session_dialog = &session_dialog;
3294 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3296 /* if they named a specific statefile, use it, otherwise they are
3297 just giving a session folder, and we want to use it as is
3298 to find the session.
3301 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3303 if (suffix != string::npos) {
3304 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3305 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3306 session_name = Glib::path_get_basename (session_name);
3308 session_path = ARDOUR_COMMAND_LINE::session_name;
3309 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3314 session_dialog.clear_given ();
3317 if (should_be_new || session_name.empty()) {
3318 /* need the dialog to get info from user */
3320 cerr << "run dialog\n";
3322 switch (session_dialog.run()) {
3323 case RESPONSE_ACCEPT:
3326 /* this is used for async * app->ShouldLoad(). */
3327 continue; // while loop
3330 if (quit_on_cancel) {
3331 ARDOUR_UI::finish ();
3332 Gtkmm2ext::Application::instance()->cleanup();
3334 pthread_cancel_all ();
3335 return -1; // caller is responsible to call exit()
3341 session_dialog.hide ();
3344 /* if we run the startup dialog again, offer more than just "new session" */
3346 should_be_new = false;
3348 session_name = session_dialog.session_name (likely_new);
3349 session_path = session_dialog.session_folder ();
3356 int rv = ARDOUR::inflate_session (session_name,
3357 Config->get_default_session_parent_dir(), session_path, session_name);
3359 MessageDialog msg (session_dialog,
3360 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3365 session_dialog.set_provided_session (session_name, session_path);
3369 // XXX check archive, inflate
3370 string::size_type suffix = session_name.find (statefile_suffix);
3372 if (suffix != string::npos) {
3373 session_name = session_name.substr (0, suffix);
3376 /* this shouldn't happen, but we catch it just in case it does */
3378 if (session_name.empty()) {
3382 if (session_dialog.use_session_template()) {
3383 template_name = session_dialog.session_template_name();
3384 _session_is_new = true;
3387 if (session_name[0] == G_DIR_SEPARATOR ||
3388 #ifdef PLATFORM_WINDOWS
3389 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3391 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3392 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3397 /* absolute path or cwd-relative path specified for session name: infer session folder
3398 from what was given.
3401 session_path = Glib::path_get_dirname (session_name);
3402 session_name = Glib::path_get_basename (session_name);
3406 session_path = session_dialog.session_folder();
3408 char illegal = Session::session_name_is_legal (session_name);
3411 MessageDialog msg (session_dialog,
3412 string_compose (_("To ensure compatibility with various systems\n"
3413 "session names may not contain a '%1' character"),
3416 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3421 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3424 if (likely_new && !nsm) {
3426 std::string existing = Glib::build_filename (session_path, session_name);
3428 if (!ask_about_loading_existing_session (existing)) {
3429 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3434 _session_is_new = false;
3439 pop_back_splash (session_dialog);
3440 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3442 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3446 char illegal = Session::session_name_is_legal(session_name);
3449 pop_back_splash (session_dialog);
3450 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3451 "session names may not contain a '%1' character"), illegal));
3453 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3457 _session_is_new = true;
3460 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3462 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3463 meta_session_setup (template_name.substr (11));
3465 } else if (likely_new && template_name.empty()) {
3467 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3471 ret = load_session (session_path, session_name, template_name);
3474 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3478 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3479 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3483 /* clear this to avoid endless attempts to load the
3487 ARDOUR_COMMAND_LINE::session_name = "";
3491 _session_dialog = NULL;
3497 ARDOUR_UI::close_session()
3499 if (!check_audioengine (_main_window)) {
3503 if (unload_session (true)) {
3507 ARDOUR_COMMAND_LINE::session_name = "";
3509 if (get_session_parameters (true, false)) {
3514 /** @param snap_name Snapshot name (without .ardour suffix).
3515 * @return -2 if the load failed because we are not connected to the AudioEngine.
3518 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3520 /* load_session calls flush_pending() which allows
3521 * GUI interaction and potentially loading another session
3522 * (that was easy via snapshot sidebar).
3523 * Recursing into load_session() from load_session() and recusive
3524 * event loops causes all kind of crashes.
3526 assert (!session_load_in_progress);
3527 if (session_load_in_progress) {
3530 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3532 Session *new_session;
3537 unload_status = unload_session ();
3539 if (unload_status < 0) {
3541 } else if (unload_status > 0) {
3547 session_loaded = false;
3549 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3552 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3555 /* this one is special */
3557 catch (AudioEngine::PortRegistrationFailure const& err) {
3559 MessageDialog msg (err.what(),
3562 Gtk::BUTTONS_CLOSE);
3564 msg.set_title (_("Port Registration Error"));
3565 msg.set_secondary_text (_("Click the Close button to try again."));
3566 msg.set_position (Gtk::WIN_POS_CENTER);
3567 pop_back_splash (msg);
3570 int response = msg.run ();
3575 case RESPONSE_CANCEL:
3582 catch (SessionException const& e) {
3583 MessageDialog msg (string_compose(
3584 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3585 path, snap_name, e.what()),
3590 msg.set_title (_("Loading Error"));
3591 msg.set_position (Gtk::WIN_POS_CENTER);
3592 pop_back_splash (msg);
3604 MessageDialog msg (string_compose(
3605 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3611 msg.set_title (_("Loading Error"));
3612 msg.set_position (Gtk::WIN_POS_CENTER);
3613 pop_back_splash (msg);
3625 list<string> const u = new_session->unknown_processors ();
3627 MissingPluginDialog d (_session, u);
3632 if (!new_session->writable()) {
3633 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3638 msg.set_title (_("Read-only Session"));
3639 msg.set_position (Gtk::WIN_POS_CENTER);
3640 pop_back_splash (msg);
3647 /* Now the session been created, add the transport controls */
3648 new_session->add_controllable(roll_controllable);
3649 new_session->add_controllable(stop_controllable);
3650 new_session->add_controllable(goto_start_controllable);
3651 new_session->add_controllable(goto_end_controllable);
3652 new_session->add_controllable(auto_loop_controllable);
3653 new_session->add_controllable(play_selection_controllable);
3654 new_session->add_controllable(rec_controllable);
3656 set_session (new_session);
3658 session_loaded = true;
3661 _session->set_clean ();
3664 #ifdef WINDOWS_VST_SUPPORT
3665 fst_stop_threading();
3669 Timers::TimerSuspender t;
3673 #ifdef WINDOWS_VST_SUPPORT
3674 fst_start_threading();
3678 if (!mix_template.empty ()) {
3679 /* if mix_template is given, assume this is a new session */
3680 string metascript = Glib::build_filename (mix_template, "template.lua");
3681 meta_session_setup (metascript);
3686 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3687 * which is queued by set_session().
3688 * If session-loading fails we hide it explicitly.
3689 * This covers both cases in a central place.
3698 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3700 Session *new_session;
3703 session_loaded = false;
3704 x = unload_session ();
3712 _session_is_new = true;
3715 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3718 catch (SessionException const& e) {
3719 cerr << "Here are the errors associated with this failed session:\n";
3721 cerr << "---------\n";
3722 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3723 msg.set_title (_("Loading Error"));
3724 msg.set_position (Gtk::WIN_POS_CENTER);
3725 pop_back_splash (msg);
3730 cerr << "Here are the errors associated with this failed session:\n";
3732 cerr << "---------\n";
3733 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3734 msg.set_title (_("Loading Error"));
3735 msg.set_position (Gtk::WIN_POS_CENTER);
3736 pop_back_splash (msg);
3741 /* Give the new session the default GUI state, if such things exist */
3744 n = Config->instant_xml (X_("Editor"));
3746 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3747 new_session->add_instant_xml (*n, false);
3749 n = Config->instant_xml (X_("Mixer"));
3751 new_session->add_instant_xml (*n, false);
3754 n = Config->instant_xml (X_("Preferences"));
3756 new_session->add_instant_xml (*n, false);
3759 /* Put the playhead at 0 and scroll fully left */
3760 n = new_session->instant_xml (X_("Editor"));
3762 n->set_property (X_("playhead"), X_("0"));
3763 n->set_property (X_("left-frame"), X_("0"));
3766 set_session (new_session);
3768 session_loaded = true;
3770 new_session->save_state(new_session->name());
3776 static void _lua_print (std::string s) {
3778 std::cout << "LuaInstance: " << s << "\n";
3780 PBD::info << "LuaInstance: " << s << endmsg;
3783 std::map<std::string, std::string>
3784 ARDOUR_UI::route_setup_info (const std::string& script_path)
3786 std::map<std::string, std::string> rv;
3788 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3793 lua.Print.connect (&_lua_print);
3796 lua_State* L = lua.getState();
3797 LuaInstance::register_classes (L);
3798 LuaBindings::set_session (L, _session);
3799 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3800 lua_setglobal (L, "Editor");
3802 lua.do_command ("function ardour () end");
3803 lua.do_file (script_path);
3806 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3807 if (!fn.isFunction ()) {
3810 luabridge::LuaRef rs = fn ();
3811 if (!rs.isTable ()) {
3814 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3815 if (!i.key().isString()) {
3818 std::string key = i.key().tostring();
3819 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3820 rv[key] = i.value().tostring();
3823 } catch (luabridge::LuaException const& e) {
3824 cerr << "LuaException:" << e.what () << endl;
3830 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3832 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3835 assert (add_route_dialog);
3838 if ((count = add_route_dialog->count()) <= 0) {
3843 lua.Print.connect (&_lua_print);
3846 lua_State* L = lua.getState();
3847 LuaInstance::register_classes (L);
3848 LuaBindings::set_session (L, _session);
3849 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3850 lua_setglobal (L, "Editor");
3852 lua.do_command ("function ardour () end");
3853 lua.do_file (script_path);
3855 luabridge::LuaRef args (luabridge::newTable (L));
3857 args["name"] = add_route_dialog->name_template ();
3858 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3859 args["group"] = add_route_dialog->route_group ();
3860 args["strict_io"] = add_route_dialog->use_strict_io ();
3861 args["instrument"] = add_route_dialog->requested_instrument ();
3862 args["track_mode"] = add_route_dialog->mode ();
3863 args["channels"] = add_route_dialog->channel_count ();
3864 args["how_many"] = count;
3867 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3868 if (fn.isFunction()) {
3871 } catch (luabridge::LuaException const& e) {
3872 cerr << "LuaException:" << e.what () << endl;
3874 display_insufficient_ports_message ();
3879 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3881 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3886 lua.Print.connect (&_lua_print);
3889 lua_State* L = lua.getState();
3890 LuaInstance::register_classes (L);
3891 LuaBindings::set_session (L, _session);
3892 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3893 lua_setglobal (L, "Editor");
3895 lua.do_command ("function ardour () end");
3896 lua.do_file (script_path);
3899 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3900 if (fn.isFunction()) {
3903 } catch (luabridge::LuaException const& e) {
3904 cerr << "LuaException:" << e.what () << endl;
3906 display_insufficient_ports_message ();
3911 ARDOUR_UI::launch_chat ()
3913 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3915 dialog.set_title (_("About the Chat"));
3916 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."));
3918 switch (dialog.run()) {
3920 open_uri("http://webchat.freenode.net/?channels=ardour");
3928 ARDOUR_UI::launch_manual ()
3930 PBD::open_uri (Config->get_tutorial_manual_url());
3934 ARDOUR_UI::launch_reference ()
3936 PBD::open_uri (Config->get_reference_manual_url());
3940 ARDOUR_UI::launch_tracker ()
3942 PBD::open_uri ("http://tracker.ardour.org");
3946 ARDOUR_UI::launch_subscribe ()
3948 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3952 ARDOUR_UI::launch_cheat_sheet ()
3955 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3957 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3962 ARDOUR_UI::launch_website ()
3964 PBD::open_uri ("http://ardour.org");
3968 ARDOUR_UI::launch_website_dev ()
3970 PBD::open_uri ("http://ardour.org/development.html");
3974 ARDOUR_UI::launch_forums ()
3976 PBD::open_uri ("https://community.ardour.org/forums");
3980 ARDOUR_UI::launch_howto_report ()
3982 PBD::open_uri ("http://ardour.org/reporting_bugs");
3986 ARDOUR_UI::loading_message (const std::string& msg)
3988 if (ARDOUR_COMMAND_LINE::no_splash) {
3996 splash->message (msg);
4000 ARDOUR_UI::show_splash ()
4004 splash = new Splash;
4014 ARDOUR_UI::hide_splash ()
4021 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4025 removed = rep.paths.size();
4028 MessageDialog msgd (_main_window,
4029 _("No files were ready for clean-up"),
4033 msgd.set_title (_("Clean-up"));
4034 msgd.set_secondary_text (_("If this seems surprising, \n\
4035 check for any existing snapshots.\n\
4036 These may still include regions that\n\
4037 require some unused files to continue to exist."));
4043 ArdourDialog results (_("Clean-up"), true, false);
4045 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4046 CleanupResultsModelColumns() {
4050 Gtk::TreeModelColumn<std::string> visible_name;
4051 Gtk::TreeModelColumn<std::string> fullpath;
4055 CleanupResultsModelColumns results_columns;
4056 Glib::RefPtr<Gtk::ListStore> results_model;
4057 Gtk::TreeView results_display;
4059 results_model = ListStore::create (results_columns);
4060 results_display.set_model (results_model);
4061 results_display.append_column (list_title, results_columns.visible_name);
4063 results_display.set_name ("CleanupResultsList");
4064 results_display.set_headers_visible (true);
4065 results_display.set_headers_clickable (false);
4066 results_display.set_reorderable (false);
4068 Gtk::ScrolledWindow list_scroller;
4071 Gtk::HBox dhbox; // the hbox for the image and text
4072 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4073 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4075 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4077 const string dead_directory = _session->session_directory().dead_path();
4080 %1 - number of files removed
4081 %2 - location of "dead"
4082 %3 - size of files affected
4083 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4086 const char* bprefix;
4087 double space_adjusted = 0;
4089 if (rep.space < 1000) {
4091 space_adjusted = rep.space;
4092 } else if (rep.space < 1000000) {
4093 bprefix = _("kilo");
4094 space_adjusted = floorf((float)rep.space / 1000.0);
4095 } else if (rep.space < 1000000 * 1000) {
4096 bprefix = _("mega");
4097 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4099 bprefix = _("giga");
4100 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4104 txt.set_markup (string_compose (P_("\
4105 The following file was deleted from %2,\n\
4106 releasing %3 %4bytes of disk space", "\
4107 The following %1 files were deleted from %2,\n\
4108 releasing %3 %4bytes of disk space", removed),
4109 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4111 txt.set_markup (string_compose (P_("\
4112 The following file was not in use and \n\
4113 has been moved to: %2\n\n\
4114 After a restart of %5\n\n\
4115 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4116 will release an additional %3 %4bytes of disk space.\n", "\
4117 The following %1 files were not in use and \n\
4118 have been moved to: %2\n\n\
4119 After a restart of %5\n\n\
4120 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4121 will release an additional %3 %4bytes of disk space.\n", removed),
4122 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4125 dhbox.pack_start (*dimage, true, false, 5);
4126 dhbox.pack_start (txt, true, false, 5);
4128 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4129 TreeModel::Row row = *(results_model->append());
4130 row[results_columns.visible_name] = *i;
4131 row[results_columns.fullpath] = *i;
4134 list_scroller.add (results_display);
4135 list_scroller.set_size_request (-1, 150);
4136 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4138 dvbox.pack_start (dhbox, true, false, 5);
4139 dvbox.pack_start (list_scroller, true, false, 5);
4140 ddhbox.pack_start (dvbox, true, false, 5);
4142 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4143 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4144 results.set_default_response (RESPONSE_CLOSE);
4145 results.set_position (Gtk::WIN_POS_MOUSE);
4147 results_display.show();
4148 list_scroller.show();
4155 //results.get_vbox()->show();
4156 results.set_resizable (false);
4163 ARDOUR_UI::cleanup ()
4165 if (_session == 0) {
4166 /* shouldn't happen: menu item is insensitive */
4171 MessageDialog checker (_("Are you sure you want to clean-up?"),
4173 Gtk::MESSAGE_QUESTION,
4176 checker.set_title (_("Clean-up"));
4178 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4179 ALL undo/redo information will be lost if you clean-up.\n\
4180 Clean-up will move all unused files to a \"dead\" location."));
4182 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4183 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4184 checker.set_default_response (RESPONSE_CANCEL);
4186 checker.set_name (_("CleanupDialog"));
4187 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4188 checker.set_position (Gtk::WIN_POS_MOUSE);
4190 switch (checker.run()) {
4191 case RESPONSE_ACCEPT:
4197 ARDOUR::CleanupReport rep;
4199 editor->prepare_for_cleanup ();
4201 /* do not allow flush until a session is reloaded */
4203 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4205 act->set_sensitive (false);
4208 if (_session->cleanup_sources (rep)) {
4209 editor->finish_cleanup ();
4213 editor->finish_cleanup ();
4216 display_cleanup_results (rep, _("Cleaned Files"), false);
4220 ARDOUR_UI::flush_trash ()
4222 if (_session == 0) {
4223 /* shouldn't happen: menu item is insensitive */
4227 ARDOUR::CleanupReport rep;
4229 if (_session->cleanup_trash_sources (rep)) {
4233 display_cleanup_results (rep, _("deleted file"), true);
4237 ARDOUR_UI::cleanup_peakfiles ()
4239 if (_session == 0) {
4240 /* shouldn't happen: menu item is insensitive */
4244 if (! _session->can_cleanup_peakfiles ()) {
4248 // get all region-views in this session
4250 TrackViewList empty;
4252 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4253 std::list<RegionView*> views = rs.by_layer();
4255 // remove displayed audio-region-views waveforms
4256 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4257 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4258 if (!arv) { continue ; }
4259 arv->delete_waves();
4262 // cleanup peak files:
4263 // - stop pending peakfile threads
4264 // - close peakfiles if any
4265 // - remove peak dir in session
4266 // - setup peakfiles (background thread)
4267 _session->cleanup_peakfiles ();
4269 // re-add waves to ARV
4270 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4271 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4272 if (!arv) { continue ; }
4273 arv->create_waves();
4277 PresentationInfo::order_t
4278 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4280 if (editor->get_selection().tracks.empty()) {
4281 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4284 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4287 we want the new routes to have their order keys set starting from
4288 the highest order key in the selection + 1 (if available).
4291 if (place == RouteDialogs::AfterSelection) {
4292 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4294 order_hint = rtav->route()->presentation_info().order();
4297 } else if (place == RouteDialogs::BeforeSelection) {
4298 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4300 order_hint = rtav->route()->presentation_info().order();
4302 } else if (place == RouteDialogs::First) {
4305 /* leave order_hint at max_order */
4312 ARDOUR_UI::start_duplicate_routes ()
4314 if (!duplicate_routes_dialog) {
4315 duplicate_routes_dialog = new DuplicateRouteDialog;
4318 if (duplicate_routes_dialog->restart (_session)) {
4322 duplicate_routes_dialog->present ();
4326 ARDOUR_UI::add_route ()
4328 if (!add_route_dialog.get (false)) {
4329 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4336 if (add_route_dialog->is_visible()) {
4337 /* we're already doing this */
4341 add_route_dialog->set_position (WIN_POS_MOUSE);
4342 add_route_dialog->present();
4346 ARDOUR_UI::add_route_dialog_response (int r)
4349 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4356 case AddRouteDialog::Add:
4357 add_route_dialog->reset_name_edited ();
4359 case AddRouteDialog::AddAndClose:
4360 add_route_dialog->ArdourDialog::on_response (r);
4363 add_route_dialog->ArdourDialog::on_response (r);
4367 std::string template_path = add_route_dialog->get_template_path();
4368 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4369 meta_route_setup (template_path.substr (11));
4373 if ((count = add_route_dialog->count()) <= 0) {
4377 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4378 const string name_template = add_route_dialog->name_template ();
4379 DisplaySuspender ds;
4381 if (!template_path.empty ()) {
4382 if (add_route_dialog->name_template_is_default ()) {
4383 _session->new_route_from_template (count, order, template_path, string ());
4385 _session->new_route_from_template (count, order, template_path, name_template);
4390 ChanCount input_chan= add_route_dialog->channels ();
4391 ChanCount output_chan;
4392 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4393 RouteGroup* route_group = add_route_dialog->route_group ();
4394 AutoConnectOption oac = Config->get_output_auto_connect();
4395 bool strict_io = add_route_dialog->use_strict_io ();
4397 if (oac & AutoConnectMaster) {
4398 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4399 output_chan.set (DataType::MIDI, 0);
4401 output_chan = input_chan;
4404 /* XXX do something with name template */
4406 Session::ProcessorChangeBlocker pcb (_session);
4408 switch (add_route_dialog->type_wanted()) {
4409 case AddRouteDialog::AudioTrack:
4410 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);
4412 case AddRouteDialog::MidiTrack:
4413 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4415 case AddRouteDialog::MixedTrack:
4416 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4418 case AddRouteDialog::AudioBus:
4419 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4421 case AddRouteDialog::MidiBus:
4422 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4424 case AddRouteDialog::VCAMaster:
4425 _session->vca_manager().create_vca (count, name_template);
4427 case AddRouteDialog::ListenBus:
4428 session_add_listen_bus (count, name_template);
4434 ARDOUR_UI::stop_video_server (bool ask_confirm)
4436 if (!video_server_process && ask_confirm) {
4437 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4439 if (video_server_process) {
4441 ArdourDialog confirm (_("Stop Video-Server"), true);
4442 Label m (_("Do you really want to stop the Video Server?"));
4443 confirm.get_vbox()->pack_start (m, true, true);
4444 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4445 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4446 confirm.show_all ();
4447 if (confirm.run() == RESPONSE_CANCEL) {
4451 delete video_server_process;
4452 video_server_process =0;
4457 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4459 ARDOUR_UI::start_video_server( float_window, true);
4463 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4469 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4470 if (video_server_process) {
4471 popup_error(_("The Video Server is already started."));
4473 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4479 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4481 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4483 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4485 video_server_dialog->set_transient_for (*float_window);
4488 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4489 video_server_dialog->hide();
4491 ResponseType r = (ResponseType) video_server_dialog->run ();
4492 video_server_dialog->hide();
4493 if (r != RESPONSE_ACCEPT) { return false; }
4494 if (video_server_dialog->show_again()) {
4495 Config->set_show_video_server_dialog(false);
4499 std::string icsd_exec = video_server_dialog->get_exec_path();
4500 std::string icsd_docroot = video_server_dialog->get_docroot();
4501 #ifndef PLATFORM_WINDOWS
4502 if (icsd_docroot.empty()) {
4503 icsd_docroot = VideoUtils::video_get_docroot (Config);
4508 #ifdef PLATFORM_WINDOWS
4509 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4510 /* OK, allow all drive letters */
4513 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4514 warning << _("Specified docroot is not an existing directory.") << endmsg;
4517 #ifndef PLATFORM_WINDOWS
4518 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4519 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4520 warning << _("Given Video Server is not an executable file.") << endmsg;
4524 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4525 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4526 warning << _("Given Video Server is not an executable file.") << endmsg;
4532 argp=(char**) calloc(9,sizeof(char*));
4533 argp[0] = strdup(icsd_exec.c_str());
4534 argp[1] = strdup("-P");
4535 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4536 argp[3] = strdup("-p");
4537 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4538 argp[5] = strdup("-C");
4539 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4540 argp[7] = strdup(icsd_docroot.c_str());
4542 stop_video_server();
4544 #ifdef PLATFORM_WINDOWS
4545 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4546 /* OK, allow all drive letters */
4549 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4550 Config->set_video_advanced_setup(false);
4552 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4553 Config->set_video_server_url(url_str);
4554 Config->set_video_server_docroot(icsd_docroot);
4555 Config->set_video_advanced_setup(true);
4558 if (video_server_process) {
4559 delete video_server_process;
4562 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4563 if (video_server_process->start()) {
4564 warning << _("Cannot launch the video-server") << endmsg;
4567 int timeout = 120; // 6 sec
4568 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4569 Glib::usleep (50000);
4571 if (--timeout <= 0 || !video_server_process->is_running()) break;
4574 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4576 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4577 delete video_server_process;
4578 video_server_process = 0;
4586 ARDOUR_UI::add_video (Gtk::Window* float_window)
4592 if (!start_video_server(float_window, false)) {
4593 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4598 add_video_dialog->set_transient_for (*float_window);
4601 if (add_video_dialog->is_visible()) {
4602 /* we're already doing this */
4606 ResponseType r = (ResponseType) add_video_dialog->run ();
4607 add_video_dialog->hide();
4608 if (r != RESPONSE_ACCEPT) { return; }
4610 bool local_file, orig_local_file;
4611 std::string path = add_video_dialog->file_name(local_file);
4613 std::string orig_path = path;
4614 orig_local_file = local_file;
4616 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4618 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4619 warning << string_compose(_("could not open %1"), path) << endmsg;
4622 if (!local_file && path.length() == 0) {
4623 warning << _("no video-file selected") << endmsg;
4627 std::string audio_from_video;
4628 bool detect_ltc = false;
4630 switch (add_video_dialog->import_option()) {
4631 case VTL_IMPORT_TRANSCODE:
4633 TranscodeVideoDialog *transcode_video_dialog;
4634 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4635 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4636 transcode_video_dialog->hide();
4637 if (r != RESPONSE_ACCEPT) {
4638 delete transcode_video_dialog;
4642 audio_from_video = transcode_video_dialog->get_audiofile();
4644 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4647 else if (!audio_from_video.empty()) {
4648 editor->embed_audio_from_video(
4650 video_timeline->get_offset(),
4651 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4654 switch (transcode_video_dialog->import_option()) {
4655 case VTL_IMPORT_TRANSCODED:
4656 path = transcode_video_dialog->get_filename();
4659 case VTL_IMPORT_REFERENCE:
4662 delete transcode_video_dialog;
4665 delete transcode_video_dialog;
4669 case VTL_IMPORT_NONE:
4673 /* strip _session->session_directory().video_path() from video file if possible */
4674 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4675 path=path.substr(_session->session_directory().video_path().size());
4676 if (path.at(0) == G_DIR_SEPARATOR) {
4677 path=path.substr(1);
4681 video_timeline->set_update_session_fps(auto_set_session_fps);
4683 if (video_timeline->video_file_info(path, local_file)) {
4684 XMLNode* node = new XMLNode(X_("Videotimeline"));
4685 node->set_property (X_("Filename"), path);
4686 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4687 node->set_property (X_("LocalFile"), local_file);
4688 if (orig_local_file) {
4689 node->set_property (X_("OriginalVideoFile"), orig_path);
4691 node->remove_property (X_("OriginalVideoFile"));
4693 _session->add_extra_xml (*node);
4694 _session->set_dirty ();
4696 if (!audio_from_video.empty() && detect_ltc) {
4697 std::vector<LTCFileReader::LTCMap> ltc_seq;
4700 /* TODO ask user about TV standard (LTC alignment if any) */
4701 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4702 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4704 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4706 /* TODO seek near end of file, and read LTC until end.
4707 * if it fails to find any LTC samples, scan complete file
4709 * calculate drift of LTC compared to video-duration,
4710 * ask user for reference (timecode from start/mid/end)
4713 // LTCFileReader will have written error messages
4716 ::g_unlink(audio_from_video.c_str());
4718 if (ltc_seq.size() == 0) {
4719 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4721 /* the very first TC in the file is somteimes not aligned properly */
4722 int i = ltc_seq.size() -1;
4723 ARDOUR::sampleoffset_t video_start_offset =
4724 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4725 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4726 video_timeline->set_offset(video_start_offset);
4730 _session->maybe_update_session_range(
4731 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4732 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4735 if (add_video_dialog->launch_xjadeo() && local_file) {
4736 editor->set_xjadeo_sensitive(true);
4737 editor->toggle_xjadeo_proc(1);
4739 editor->toggle_xjadeo_proc(0);
4741 editor->toggle_ruler_video(true);
4746 ARDOUR_UI::remove_video ()
4748 video_timeline->close_session();
4749 editor->toggle_ruler_video(false);
4752 video_timeline->set_offset_locked(false);
4753 video_timeline->set_offset(0);
4755 /* delete session state */
4756 XMLNode* node = new XMLNode(X_("Videotimeline"));
4757 _session->add_extra_xml(*node);
4758 node = new XMLNode(X_("Videomonitor"));
4759 _session->add_extra_xml(*node);
4760 node = new XMLNode(X_("Videoexport"));
4761 _session->add_extra_xml(*node);
4762 stop_video_server();
4766 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4768 if (localcacheonly) {
4769 video_timeline->vmon_update();
4771 video_timeline->flush_cache();
4773 editor->queue_visual_videotimeline_update();
4777 ARDOUR_UI::export_video (bool range)
4779 if (ARDOUR::Config->get_show_video_export_info()) {
4780 ExportVideoInfobox infobox (_session);
4781 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4782 if (infobox.show_again()) {
4783 ARDOUR::Config->set_show_video_export_info(false);
4786 case GTK_RESPONSE_YES:
4787 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4793 export_video_dialog->set_session (_session);
4794 export_video_dialog->apply_state(editor->get_selection().time, range);
4795 export_video_dialog->run ();
4796 export_video_dialog->hide ();
4800 ARDOUR_UI::preferences_settings () const
4805 node = _session->instant_xml(X_("Preferences"));
4807 node = Config->instant_xml(X_("Preferences"));
4811 node = new XMLNode (X_("Preferences"));
4818 ARDOUR_UI::mixer_settings () const
4823 node = _session->instant_xml(X_("Mixer"));
4825 node = Config->instant_xml(X_("Mixer"));
4829 node = new XMLNode (X_("Mixer"));
4836 ARDOUR_UI::main_window_settings () const
4841 node = _session->instant_xml(X_("Main"));
4843 node = Config->instant_xml(X_("Main"));
4847 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4848 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4853 node = new XMLNode (X_("Main"));
4860 ARDOUR_UI::editor_settings () const
4865 node = _session->instant_xml(X_("Editor"));
4867 node = Config->instant_xml(X_("Editor"));
4871 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4872 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4877 node = new XMLNode (X_("Editor"));
4884 ARDOUR_UI::keyboard_settings () const
4888 node = Config->extra_xml(X_("Keyboard"));
4891 node = new XMLNode (X_("Keyboard"));
4898 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4901 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4902 _session->locations()->add (location);
4907 ARDOUR_UI::halt_on_xrun_message ()
4909 cerr << "HALT on xrun\n";
4910 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4915 ARDOUR_UI::xrun_handler (samplepos_t where)
4921 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4923 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4924 create_xrun_marker(where);
4927 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4928 halt_on_xrun_message ();
4933 ARDOUR_UI::disk_overrun_handler ()
4935 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4937 if (!have_disk_speed_dialog_displayed) {
4938 have_disk_speed_dialog_displayed = true;
4939 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4940 The disk system on your computer\n\
4941 was not able to keep up with %1.\n\
4943 Specifically, it failed to write data to disk\n\
4944 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4945 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4951 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4952 static MessageDialog *scan_dlg = NULL;
4953 static ProgressBar *scan_pbar = NULL;
4954 static HBox *scan_tbox = NULL;
4955 static Gtk::Button *scan_timeout_button;
4958 ARDOUR_UI::cancel_plugin_scan ()
4960 PluginManager::instance().cancel_plugin_scan();
4964 ARDOUR_UI::cancel_plugin_timeout ()
4966 PluginManager::instance().cancel_plugin_timeout();
4967 scan_timeout_button->set_sensitive (false);
4971 ARDOUR_UI::plugin_scan_timeout (int timeout)
4973 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4977 scan_pbar->set_sensitive (false);
4978 scan_timeout_button->set_sensitive (true);
4979 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4982 scan_pbar->set_sensitive (false);
4983 scan_timeout_button->set_sensitive (false);
4989 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4991 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4995 const bool cancelled = PluginManager::instance().cancelled();
4996 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4997 if (cancelled && scan_dlg->is_mapped()) {
5002 if (cancelled || !can_cancel) {
5007 static Gtk::Button *cancel_button;
5009 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5010 VBox* vbox = scan_dlg->get_vbox();
5011 vbox->set_size_request(400,-1);
5012 scan_dlg->set_title (_("Scanning for plugins"));
5014 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5015 cancel_button->set_name ("EditorGTKButton");
5016 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5017 cancel_button->show();
5019 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5021 scan_tbox = manage( new HBox() );
5023 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5024 scan_timeout_button->set_name ("EditorGTKButton");
5025 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5026 scan_timeout_button->show();
5028 scan_pbar = manage(new ProgressBar());
5029 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5030 scan_pbar->set_text(_("Scan Timeout"));
5033 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5034 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5036 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5039 assert(scan_dlg && scan_tbox && cancel_button);
5041 if (type == X_("closeme")) {
5045 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5048 if (!can_cancel || !cancelled) {
5049 scan_timeout_button->set_sensitive(false);
5051 cancel_button->set_sensitive(can_cancel && !cancelled);
5057 ARDOUR_UI::gui_idle_handler ()
5060 /* due to idle calls, gtk_events_pending() may always return true */
5061 while (gtk_events_pending() && --timeout) {
5062 gtk_main_iteration ();
5067 ARDOUR_UI::disk_underrun_handler ()
5069 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5071 if (!have_disk_speed_dialog_displayed) {
5072 have_disk_speed_dialog_displayed = true;
5073 MessageDialog* msg = new MessageDialog (
5074 _main_window, string_compose (_("The disk system on your computer\n\
5075 was not able to keep up with %1.\n\
5077 Specifically, it failed to read data from disk\n\
5078 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5079 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5085 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5087 have_disk_speed_dialog_displayed = false;
5092 ARDOUR_UI::session_dialog (std::string msg)
5094 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5098 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5105 ARDOUR_UI::pending_state_dialog ()
5107 HBox* hbox = manage (new HBox());
5108 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5109 ArdourDialog dialog (_("Crash Recovery"), true);
5110 Label message (string_compose (_("\
5111 This session appears to have been in the\n\
5112 middle of recording when %1 or\n\
5113 the computer was shutdown.\n\
5115 %1 can recover any captured audio for\n\
5116 you, or it can ignore it. Please decide\n\
5117 what you would like to do.\n"), PROGRAM_NAME));
5118 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5119 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5120 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5121 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5122 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5123 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5124 dialog.set_default_response (RESPONSE_ACCEPT);
5125 dialog.set_position (WIN_POS_CENTER);
5130 switch (dialog.run ()) {
5131 case RESPONSE_ACCEPT:
5139 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5141 HBox* hbox = new HBox();
5142 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5143 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5144 Label message (string_compose (_("\
5145 This session was created with a sample rate of %1 Hz, but\n\
5146 %2 is currently running at %3 Hz. If you load this session,\n\
5147 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5149 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5150 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5151 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5152 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5153 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5154 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5155 dialog.set_default_response (RESPONSE_ACCEPT);
5156 dialog.set_position (WIN_POS_CENTER);
5161 switch (dialog.run()) {
5162 case RESPONSE_ACCEPT:
5172 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5174 MessageDialog msg (string_compose (_("\
5175 This session was created with a sample rate of %1 Hz, but\n\
5176 %2 is currently running at %3 Hz.\n\
5177 Audio will be recorded and played at the wrong sample rate.\n\
5178 Re-Configure the Audio Engine in\n\
5179 Menu > Window > Audio/Midi Setup"),
5180 desired, PROGRAM_NAME, actual),
5182 Gtk::MESSAGE_WARNING);
5187 ARDOUR_UI::use_config ()
5189 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5191 set_transport_controllable_state (*node);
5196 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5198 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5200 primary_clock->set (pos);
5202 case DeltaEditPoint:
5203 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5205 case DeltaOriginMarker:
5207 Location* loc = _session->locations()->clock_origin_location ();
5208 primary_clock->set (pos, false, loc ? loc->start() : 0);
5213 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5215 secondary_clock->set (pos);
5217 case DeltaEditPoint:
5218 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5220 case DeltaOriginMarker:
5222 Location* loc = _session->locations()->clock_origin_location ();
5223 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5228 if (big_clock_window) {
5229 big_clock->set (pos);
5231 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5236 ARDOUR_UI::record_state_changed ()
5238 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5241 /* why bother - the clock isn't visible */
5245 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5247 if (big_clock_window) {
5248 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5249 big_clock->set_active (true);
5251 big_clock->set_active (false);
5258 ARDOUR_UI::first_idle ()
5261 _session->allow_auto_play (true);
5265 editor->first_idle();
5268 /* in 1 second, hide the splash screen
5270 * Consider hiding it *now*. If a user opens opens a dialog
5271 * during that one second while the splash is still visible,
5272 * the dialog will push-back the splash.
5273 * Closing the dialog later will pop it back.
5275 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5277 Keyboard::set_can_save_keybindings (true);
5282 ARDOUR_UI::store_clock_modes ()
5284 XMLNode* node = new XMLNode(X_("ClockModes"));
5286 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5287 XMLNode* child = new XMLNode (X_("Clock"));
5289 child->set_property (X_("name"), (*x)->name());
5290 child->set_property (X_("mode"), (*x)->mode());
5291 child->set_property (X_("on"), (*x)->on());
5293 node->add_child_nocopy (*child);
5296 _session->add_extra_xml (*node);
5297 _session->set_dirty ();
5301 ARDOUR_UI::setup_profile ()
5303 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5304 Profile->set_small_screen ();
5307 if (g_getenv ("TRX")) {
5308 Profile->set_trx ();
5311 if (g_getenv ("MIXBUS")) {
5312 Profile->set_mixbus ();
5317 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5319 MissingFileDialog dialog (s, str, type);
5324 int result = dialog.run ();
5331 return 1; // quit entire session load
5334 result = dialog.get_action ();
5340 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5342 AmbiguousFileDialog dialog (file, hits);
5349 return dialog.get_which ();
5352 /** Allocate our thread-local buffers */
5354 ARDOUR_UI::get_process_buffers ()
5356 _process_thread->get_buffers ();
5359 /** Drop our thread-local buffers */
5361 ARDOUR_UI::drop_process_buffers ()
5363 _process_thread->drop_buffers ();
5367 ARDOUR_UI::feedback_detected ()
5369 _feedback_exists = true;
5373 ARDOUR_UI::successful_graph_sort ()
5375 _feedback_exists = false;
5379 ARDOUR_UI::midi_panic ()
5382 _session->midi_panic();
5387 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5389 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5390 const char* end_big = "</span>";
5391 const char* start_mono = "<tt>";
5392 const char* end_mono = "</tt>";
5394 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5395 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5396 "From now on, use the backup copy with older versions of %3"),
5397 xml_path, backup_path, PROGRAM_NAME,
5399 start_mono, end_mono), true);
5405 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5407 using namespace Menu_Helpers;
5409 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5410 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5411 i->set_active (editor_meter->meter_type () == type);
5415 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5417 using namespace Gtk::Menu_Helpers;
5419 Gtk::Menu* m = manage (new Menu);
5420 MenuList& items = m->items ();
5422 RadioMenuItem::Group group;
5424 _suspend_editor_meter_callbacks = true;
5425 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5426 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5427 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5428 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5429 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5430 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5431 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5432 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5433 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5434 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5435 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5437 m->popup (ev->button, ev->time);
5438 _suspend_editor_meter_callbacks = false;
5442 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5444 if (ev->button == 3 && editor_meter) {
5445 popup_editor_meter_menu (ev);
5452 ARDOUR_UI::reset_peak_display ()
5454 if (!_session || !_session->master_out() || !editor_meter) return;
5455 editor_meter->clear_meters();
5456 editor_meter_max_peak = -INFINITY;
5457 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5461 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5463 if (!_session || !_session->master_out()) return;
5464 if (group == _session->master_out()->route_group()) {
5465 reset_peak_display ();
5470 ARDOUR_UI::reset_route_peak_display (Route* route)
5472 if (!_session || !_session->master_out()) return;
5473 if (_session->master_out().get() == route) {
5474 reset_peak_display ();
5479 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5481 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5482 audio_midi_setup->set_position (WIN_POS_CENTER);
5484 if (desired_sample_rate != 0) {
5485 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5486 audio_midi_setup->try_autostart ();
5487 if (ARDOUR::AudioEngine::instance()->running()) {
5494 int response = audio_midi_setup->run();
5496 case Gtk::RESPONSE_DELETE_EVENT:
5497 // after latency callibration engine may run,
5498 // Running() signal was emitted, but dialog will not
5499 // have emitted a response. The user needs to close
5500 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5501 if (!AudioEngine::instance()->running()) {
5506 if (!AudioEngine::instance()->running()) {
5509 audio_midi_setup->hide ();
5517 ARDOUR_UI::transport_numpad_timeout ()
5519 _numpad_locate_happening = false;
5520 if (_numpad_timeout_connection.connected() )
5521 _numpad_timeout_connection.disconnect();
5526 ARDOUR_UI::transport_numpad_decimal ()
5528 _numpad_timeout_connection.disconnect();
5530 if (_numpad_locate_happening) {
5531 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5532 _numpad_locate_happening = false;
5534 _pending_locate_num = 0;
5535 _numpad_locate_happening = true;
5536 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5541 ARDOUR_UI::transport_numpad_event (int num)
5543 if ( _numpad_locate_happening ) {
5544 _pending_locate_num = _pending_locate_num*10 + num;
5547 case 0: toggle_roll(false, false); break;
5548 case 1: transport_rewind(1); break;
5549 case 2: transport_forward(1); break;
5550 case 3: transport_record(true); break;
5551 case 4: toggle_session_auto_loop(); break;
5552 case 5: transport_record(false); toggle_session_auto_loop(); break;
5553 case 6: toggle_punch(); break;
5554 case 7: toggle_click(); break;
5555 case 8: toggle_auto_return(); break;
5556 case 9: toggle_follow_edits(); break;
5562 ARDOUR_UI::set_flat_buttons ()
5564 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5568 ARDOUR_UI::audioengine_became_silent ()
5570 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5572 Gtk::MESSAGE_WARNING,
5576 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5578 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5579 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5580 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5581 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5582 Gtk::HBox pay_button_box;
5583 Gtk::HBox subscribe_button_box;
5585 pay_button_box.pack_start (pay_button, true, false);
5586 subscribe_button_box.pack_start (subscribe_button, true, false);
5588 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 */
5590 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5591 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5593 msg.get_vbox()->pack_start (pay_label);
5594 msg.get_vbox()->pack_start (pay_button_box);
5595 msg.get_vbox()->pack_start (subscribe_label);
5596 msg.get_vbox()->pack_start (subscribe_button_box);
5598 msg.get_vbox()->show_all ();
5600 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5601 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5602 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5607 case Gtk::RESPONSE_YES:
5608 AudioEngine::instance()->reset_silence_countdown ();
5611 case Gtk::RESPONSE_NO:
5613 save_state_canfail ("");
5617 case Gtk::RESPONSE_CANCEL:
5619 /* don't reset, save session and exit */
5625 ARDOUR_UI::hide_application ()
5627 Application::instance ()-> hide ();
5631 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5633 /* icons, titles, WM stuff */
5635 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5637 if (window_icons.empty()) {
5638 Glib::RefPtr<Gdk::Pixbuf> icon;
5639 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5640 window_icons.push_back (icon);
5642 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5643 window_icons.push_back (icon);
5645 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5646 window_icons.push_back (icon);
5648 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5649 window_icons.push_back (icon);
5653 if (!window_icons.empty()) {
5654 window.set_default_icon_list (window_icons);
5657 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5659 if (!name.empty()) {
5663 window.set_title (title.get_string());
5664 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5666 window.set_flags (CAN_FOCUS);
5667 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5669 /* This is a hack to ensure that GTK-accelerators continue to
5670 * work. Once we switch over to entirely native bindings, this will be
5671 * unnecessary and should be removed
5673 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5675 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5676 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5677 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5678 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5682 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5684 Gtkmm2ext::Bindings* bindings = 0;
5685 Gtk::Window* window = 0;
5687 /* until we get ardour bindings working, we are not handling key
5691 if (ev->type != GDK_KEY_PRESS) {
5695 if (event_window == &_main_window) {
5697 window = event_window;
5699 /* find current tab contents */
5701 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5703 /* see if it uses the ardour binding system */
5706 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5709 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5713 window = event_window;
5715 /* see if window uses ardour binding system */
5717 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5720 /* An empty binding set is treated as if it doesn't exist */
5722 if (bindings && bindings->empty()) {
5726 return key_press_focus_accelerator_handler (*window, ev, bindings);
5729 static Gtkmm2ext::Bindings*
5730 get_bindings_from_widget_heirarchy (GtkWidget** w)
5735 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5738 *w = gtk_widget_get_parent (*w);
5741 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5745 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5747 GtkWindow* win = window.gobj();
5748 GtkWidget* focus = gtk_window_get_focus (win);
5749 GtkWidget* binding_widget = focus;
5750 bool special_handling_of_unmodified_accelerators = false;
5751 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5755 /* some widget has keyboard focus */
5757 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5759 /* A particular kind of focusable widget currently has keyboard
5760 * focus. All unmodified key events should go to that widget
5761 * first and not be used as an accelerator by default
5764 special_handling_of_unmodified_accelerators = true;
5768 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5769 if (focus_bindings) {
5770 bindings = focus_bindings;
5771 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5776 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",
5779 Gtkmm2ext::show_gdk_event_state (ev->state),
5780 special_handling_of_unmodified_accelerators,
5781 Keyboard::some_magic_widget_has_focus(),
5783 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5784 ((ev->state & mask) ? "yes" : "no"),
5785 window.get_title()));
5787 /* This exists to allow us to override the way GTK handles
5788 key events. The normal sequence is:
5790 a) event is delivered to a GtkWindow
5791 b) accelerators/mnemonics are activated
5792 c) if (b) didn't handle the event, propagate to
5793 the focus widget and/or focus chain
5795 The problem with this is that if the accelerators include
5796 keys without modifiers, such as the space bar or the
5797 letter "e", then pressing the key while typing into
5798 a text entry widget results in the accelerator being
5799 activated, instead of the desired letter appearing
5802 There is no good way of fixing this, but this
5803 represents a compromise. The idea is that
5804 key events involving modifiers (not Shift)
5805 get routed into the activation pathway first, then
5806 get propagated to the focus widget if necessary.
5808 If the key event doesn't involve modifiers,
5809 we deliver to the focus widget first, thus allowing
5810 it to get "normal text" without interference
5813 Of course, this can also be problematic: if there
5814 is a widget with focus, then it will swallow
5815 all "normal text" accelerators.
5819 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5821 /* no special handling or there are modifiers in effect: accelerate first */
5823 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5824 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5825 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5827 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5828 KeyboardKey k (ev->state, ev->keyval);
5832 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5834 if (bindings->activate (k, Bindings::Press)) {
5835 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5839 if (binding_widget) {
5840 binding_widget = gtk_widget_get_parent (binding_widget);
5841 if (binding_widget) {
5842 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5851 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5853 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5854 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5858 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5860 if (gtk_window_propagate_key_event (win, ev)) {
5861 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5867 /* no modifiers, propagate first */
5869 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5871 if (gtk_window_propagate_key_event (win, ev)) {
5872 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5876 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5877 KeyboardKey k (ev->state, ev->keyval);
5881 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5884 if (bindings->activate (k, Bindings::Press)) {
5885 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5889 if (binding_widget) {
5890 binding_widget = gtk_widget_get_parent (binding_widget);
5891 if (binding_widget) {
5892 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5901 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5903 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5904 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5909 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5914 ARDOUR_UI::load_bindings ()
5916 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5917 error << _("Global keybindings are missing") << endmsg;
5922 ARDOUR_UI::cancel_solo ()
5925 _session->cancel_all_solo ();
5930 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5932 /* this resets focus to the first focusable parent of the given widget,
5933 * or, if there is no focusable parent, cancels focus in the toplevel
5934 * window that the given widget is packed into (if there is one).
5941 Gtk::Widget* top = w->get_toplevel();
5943 if (!top || !top->is_toplevel()) {
5947 w = w->get_parent ();
5951 if (w->is_toplevel()) {
5952 /* Setting the focus widget to a Gtk::Window causes all
5953 * subsequent calls to ::has_focus() on the nominal
5954 * focus widget in that window to return
5955 * false. Workaround: never set focus to the toplevel
5961 if (w->get_can_focus ()) {
5962 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5963 win->set_focus (*w);
5966 w = w->get_parent ();
5969 if (top == &_main_window) {
5973 /* no focusable parent found, cancel focus in top level window.
5974 C++ API cannot be used for this. Thanks, references.
5977 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);