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/monitor_control.h"
96 #include "ardour/midi_track.h"
97 #include "ardour/port.h"
98 #include "ardour/plugin_manager.h"
99 #include "ardour/process_thread.h"
100 #include "ardour/profile.h"
101 #include "ardour/recent_sessions.h"
102 #include "ardour/record_enable_control.h"
103 #include "ardour/revision.h"
104 #include "ardour/session_directory.h"
105 #include "ardour/session_route.h"
106 #include "ardour/session_state_utils.h"
107 #include "ardour/session_utils.h"
108 #include "ardour/source_factory.h"
109 #include "ardour/transport_master.h"
110 #include "ardour/transport_master_manager.h"
111 #include "ardour/system_exec.h"
112 #include "ardour/track.h"
113 #include "ardour/vca_manager.h"
114 #include "ardour/utils.h"
116 #include "LuaBridge/LuaBridge.h"
118 #ifdef WINDOWS_VST_SUPPORT
121 #ifdef AUDIOUNIT_SUPPORT
122 #include "ardour/audio_unit.h"
125 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
130 #include "temporal/time.h"
132 typedef uint64_t microseconds_t;
136 #include "enums_convert.h"
138 #include "add_route_dialog.h"
139 #include "ambiguous_file_dialog.h"
140 #include "ardour_ui.h"
141 #include "audio_clock.h"
142 #include "audio_region_view.h"
143 #include "big_clock_window.h"
144 #include "big_transport_window.h"
145 #include "bundle_manager.h"
146 #include "duplicate_routes_dialog.h"
148 #include "engine_dialog.h"
149 #include "export_video_dialog.h"
150 #include "export_video_infobox.h"
151 #include "gain_meter.h"
152 #include "global_port_matrix.h"
153 #include "gui_object.h"
154 #include "gui_thread.h"
155 #include "idleometer.h"
156 #include "keyboard.h"
157 #include "keyeditor.h"
158 #include "location_ui.h"
159 #include "lua_script_manager.h"
160 #include "luawindow.h"
161 #include "main_clock.h"
162 #include "missing_file_dialog.h"
163 #include "missing_plugin_dialog.h"
164 #include "mixer_ui.h"
165 #include "meterbridge.h"
166 #include "meter_patterns.h"
167 #include "mouse_cursors.h"
170 #include "pingback.h"
171 #include "plugin_dspload_window.h"
172 #include "processor_box.h"
173 #include "public_editor.h"
174 #include "rc_option_editor.h"
175 #include "route_time_axis.h"
176 #include "route_params_ui.h"
177 #include "save_as_dialog.h"
178 #include "save_template_dialog.h"
179 #include "script_selector.h"
180 #include "session_archive_dialog.h"
181 #include "session_dialog.h"
182 #include "session_metadata_dialog.h"
183 #include "session_option_editor.h"
184 #include "speaker_dialog.h"
187 #include "template_dialog.h"
188 #include "time_axis_view_item.h"
189 #include "time_info_box.h"
191 #include "transport_masters_dialog.h"
193 #include "utils_videotl.h"
194 #include "video_server_dialog.h"
195 #include "add_video_dialog.h"
196 #include "transcode_video_dialog.h"
198 #include "pbd/i18n.h"
200 using namespace ARDOUR;
201 using namespace ARDOUR_UI_UTILS;
203 using namespace Gtkmm2ext;
204 using namespace ArdourWidgets;
207 using namespace Editing;
209 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
211 sigc::signal<void, samplepos_t> ARDOUR_UI::Clock;
212 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
215 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
217 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
218 "Would you like these files to be copied and used for %1 %2.x?\n\n"
219 "(This will require you to restart %1.)"),
220 PROGRAM_NAME, PROGRAM_VERSION, version),
221 false, /* no markup */
224 true /* modal, though it hardly matters since it is the only window */
227 msg.set_default_response (Gtk::RESPONSE_YES);
230 return (msg.run() == Gtk::RESPONSE_YES);
234 libxml_generic_error_func (void* /* parsing_context*/,
242 vsnprintf (buf, sizeof (buf), msg, ap);
243 error << buf << endmsg;
248 libxml_structured_error_func (void* /* parsing_context*/,
256 replace_all (msg, "\n", "");
259 if (err->file && err->line) {
260 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
263 error << ':' << err->int2;
268 error << X_("XML error: ") << msg << endmsg;
274 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
275 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
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 , ignore_dual_punch (false)
283 , main_window_visibility (0)
288 , _mixer_on_top (false)
289 , _initial_verbose_plugin_scan (false)
290 , first_time_engine_run (true)
291 , secondary_clock_spacer (0)
292 , auto_input_button (ArdourButton::led_default_elements)
294 , auto_return_button (ArdourButton::led_default_elements)
295 , follow_edits_button (ArdourButton::led_default_elements)
296 , auditioning_alert_button (_("Audition"))
297 , solo_alert_button (_("Solo"))
298 , feedback_alert_button (_("Feedback"))
299 , error_alert_button ( ArdourButton::just_led_default_elements )
300 , editor_meter_peak_display()
302 , _suspend_editor_meter_callbacks (false)
303 , _numpad_locate_happening (false)
304 , _session_is_new (false)
305 , last_key_press_time (0)
309 , rc_option_editor (0)
310 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
311 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
312 , about (X_("about"), _("About"))
313 , location_ui (X_("locations"), S_("Ranges|Locations"))
314 , route_params (X_("inspector"), _("Tracks and Busses"))
315 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
316 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
317 , lua_script_window (X_("script-manager"), _("Script Manager"))
318 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
319 , plugin_dsp_load_window (X_("plugin-dsp-load"), _("Plugin DSP Load"))
320 , transport_masters_window (X_("transport-masters"), _("Transport Masters"))
321 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
322 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
323 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
324 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
325 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
326 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
327 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
328 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
329 , video_server_process (0)
331 , have_configure_timeout (false)
332 , last_configure_time (0)
334 , have_disk_speed_dialog_displayed (false)
335 , _status_bar_visibility (X_("status-bar"))
336 , _feedback_exists (false)
337 , _log_not_acknowledged (LogLevelNone)
338 , duplicate_routes_dialog (0)
339 , editor_visibility_button (S_("Window|Editor"))
340 , mixer_visibility_button (S_("Window|Mixer"))
341 , prefs_visibility_button (S_("Window|Preferences"))
343 Gtkmm2ext::init (localedir);
345 UIConfiguration::instance().post_gui_init ();
347 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
349 /* "touch" the been-here-before path now that config has been migrated */
350 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
352 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
354 /* configuration was modified, exit immediately */
359 if (string (VERSIONSTRING).find (".pre") != string::npos) {
360 /* check this is not being run from ./ardev etc. */
361 if (!running_from_source_tree ()) {
362 pre_release_dialog ();
366 if (theArdourUI == 0) {
370 /* track main window visibility */
372 main_window_visibility = new VisibilityTracker (_main_window);
374 /* stop libxml from spewing to stdout/stderr */
376 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
377 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
379 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
380 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
381 UIConfiguration::instance().map_parameters (pc);
383 transport_ctrl.setup (this);
385 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
386 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
388 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
390 /* handle dialog requests */
392 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
394 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
396 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
398 /* handle Audio/MIDI setup when session requires it */
400 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
402 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
404 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
406 /* handle sr mismatch with a dialog - cross-thread from engine */
407 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
409 /* handle requests to quit (coming from JACK session) */
411 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
413 /* tell the user about feedback */
415 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
416 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
418 /* handle requests to deal with missing files */
420 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
422 /* and ambiguous files */
424 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
426 /* also plugin scan messages */
427 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
428 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
430 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
432 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
435 /* lets get this party started */
437 setup_gtk_ardour_enums ();
440 SessionEvent::create_per_thread_pool ("GUI", 4096);
442 /* we like keyboards */
444 keyboard = new ArdourKeyboard(*this);
446 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
448 keyboard->set_state (*node, Stateful::loading_state_version);
451 UIConfiguration::instance().reset_dpi ();
453 TimeAxisViewItem::set_constant_heights ();
455 /* Set this up so that our window proxies can register actions */
457 ActionManager::init ();
459 /* The following must happen after ARDOUR::init() so that Config is set up */
461 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
464 key_editor.set_state (*ui_xml, 0);
465 session_option_editor.set_state (*ui_xml, 0);
466 speaker_config_window.set_state (*ui_xml, 0);
467 about.set_state (*ui_xml, 0);
468 add_route_dialog.set_state (*ui_xml, 0);
469 add_video_dialog.set_state (*ui_xml, 0);
470 route_params.set_state (*ui_xml, 0);
471 bundle_manager.set_state (*ui_xml, 0);
472 location_ui.set_state (*ui_xml, 0);
473 big_clock_window.set_state (*ui_xml, 0);
474 big_transport_window.set_state (*ui_xml, 0);
475 audio_port_matrix.set_state (*ui_xml, 0);
476 midi_port_matrix.set_state (*ui_xml, 0);
477 export_video_dialog.set_state (*ui_xml, 0);
478 lua_script_window.set_state (*ui_xml, 0);
479 idleometer.set_state (*ui_xml, 0);
480 plugin_dsp_load_window.set_state (*ui_xml, 0);
481 transport_masters_window.set_state (*ui_xml, 0);
484 /* Separate windows */
486 WM::Manager::instance().register_window (&key_editor);
487 WM::Manager::instance().register_window (&session_option_editor);
488 WM::Manager::instance().register_window (&speaker_config_window);
489 WM::Manager::instance().register_window (&about);
490 WM::Manager::instance().register_window (&add_route_dialog);
491 WM::Manager::instance().register_window (&add_video_dialog);
492 WM::Manager::instance().register_window (&route_params);
493 WM::Manager::instance().register_window (&audio_midi_setup);
494 WM::Manager::instance().register_window (&export_video_dialog);
495 WM::Manager::instance().register_window (&lua_script_window);
496 WM::Manager::instance().register_window (&bundle_manager);
497 WM::Manager::instance().register_window (&location_ui);
498 WM::Manager::instance().register_window (&big_clock_window);
499 WM::Manager::instance().register_window (&big_transport_window);
500 WM::Manager::instance().register_window (&audio_port_matrix);
501 WM::Manager::instance().register_window (&midi_port_matrix);
502 WM::Manager::instance().register_window (&idleometer);
503 WM::Manager::instance().register_window (&plugin_dsp_load_window);
504 WM::Manager::instance().register_window (&transport_masters_window);
506 /* do not retain position for add route dialog */
507 add_route_dialog.set_state_mask (WindowProxy::Size);
509 /* Trigger setting up the color scheme and loading the GTK RC file */
511 UIConfiguration::instance().load_rc_file (false);
513 _process_thread = new ProcessThread ();
514 _process_thread->init ();
516 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
522 ARDOUR_UI::pre_release_dialog ()
524 ArdourDialog d (_("Pre-Release Warning"), true, false);
525 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
527 Label* label = manage (new Label);
528 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
529 There are still several issues and bugs to be worked on,\n\
530 as well as general workflow improvements, before this can be considered\n\
531 release software. So, a few guidelines:\n\
533 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
534 though it may be so, depending on your workflow.\n\
535 2) Please wait for a helpful writeup of new features.\n\
536 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
537 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
538 making sure to note the product version number as 6.0-pre.\n\
539 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
540 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
541 can get there directly from within the program via the Help->Chat menu option.\n\
543 Full information on all the above can be found on the support page at\n\
545 http://ardour.org/support\n\
546 "), PROGRAM_NAME, VERSIONSTRING));
548 d.get_vbox()->set_border_width (12);
549 d.get_vbox()->pack_start (*label, false, false, 12);
550 d.get_vbox()->show_all ();
555 GlobalPortMatrixWindow*
556 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
561 return new GlobalPortMatrixWindow (_session, type);
565 ARDOUR_UI::attach_to_engine ()
567 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
568 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
572 ARDOUR_UI::engine_stopped ()
574 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
575 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
576 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
577 update_sample_rate (0);
582 ARDOUR_UI::engine_running ()
584 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
585 if (first_time_engine_run) {
587 first_time_engine_run = false;
591 _session->reset_xrun_count ();
593 update_disk_space ();
595 update_sample_rate (AudioEngine::instance()->sample_rate());
596 update_timecode_format ();
597 update_peak_thread_work ();
598 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
599 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
603 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
605 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
606 /* we can't rely on the original string continuing to exist when we are called
607 again in the GUI thread, so make a copy and note that we need to
610 char *copy = strdup (reason);
611 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
615 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
616 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
618 update_sample_rate (0);
622 /* if the reason is a non-empty string, it means that the backend was shutdown
623 rather than just Ardour.
626 if (strlen (reason)) {
627 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
629 msgstr = string_compose (_("\
630 The audio backend has either been shutdown or it\n\
631 disconnected %1 because %1\n\
632 was not fast enough. Try to restart\n\
633 the audio backend and save the session."), PROGRAM_NAME);
636 MessageDialog msg (_main_window, msgstr);
637 pop_back_splash (msg);
641 free (const_cast<char*> (reason));
646 ARDOUR_UI::post_engine ()
648 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
650 #ifdef AUDIOUNIT_SUPPORT
652 if (AUPluginInfo::au_get_crashlog(au_msg)) {
653 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
654 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
655 info << au_msg << endmsg;
659 ARDOUR::init_post_engine ();
661 /* connect to important signals */
663 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
664 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
665 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
666 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
667 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
669 if (setup_windows ()) {
670 throw failed_constructor ();
673 transport_ctrl.map_actions ();
675 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
676 XMLNode* n = Config->extra_xml (X_("UI"));
678 _status_bar_visibility.set_state (*n);
681 check_memory_locking();
683 /* this is the first point at which all the possible actions are
684 * available, because some of the available actions are dependent on
685 * aspects of the engine/backend.
688 if (ARDOUR_COMMAND_LINE::show_key_actions) {
690 Bindings::save_all_bindings_as_html (sstr);
692 if (sstr.str().empty()) {
699 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
701 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
707 #ifdef PLATFORM_WINDOWS
713 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
714 #ifndef PLATFORM_WINDOWS
717 g_unlink (file_name);
719 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
725 #ifndef PLATFORM_WINDOWS
729 PBD::open_uri (string_compose ("file:///%1", file_name));
731 halt_connection.disconnect ();
732 AudioEngine::instance()->stop ();
737 if (ARDOUR_COMMAND_LINE::show_actions) {
740 vector<string> paths;
741 vector<string> labels;
742 vector<string> tooltips;
744 vector<Glib::RefPtr<Gtk::Action> > actions;
745 string ver_in = revision;
746 string ver = ver_in.substr(0, ver_in.find("-"));
749 output << "\n<h2>Menu actions</h2>" << endl;
750 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
751 output << " surfaces or scripts.\n</p>\n" << endl;
752 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
753 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
754 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
755 output << "<table class=\"dl\">\n <thead>" << endl;
756 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
757 output << " </thead>\n <tbody>" << endl;
759 ActionManager::get_all_actions (paths, labels, tooltips, keys, actions);
761 vector<string>::iterator p;
762 vector<string>::iterator l;
764 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
765 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (10, string::npos);
766 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
768 output << " </tbody>\n </table>" << endl;
770 // output this mess to a browser for easiest X-platform use
771 // it is not pretty HTML, but it works and it's main purpose
772 // is to create raw html to fit in Ardour's manual with no editing
777 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
779 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
785 #ifdef PLATFORM_WINDOWS
791 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
792 #ifndef PLATFORM_WINDOWS
795 g_unlink (file_name);
797 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
803 #ifndef PLATFORM_WINDOWS
807 PBD::open_uri (string_compose ("file:///%1", file_name));
809 halt_connection.disconnect ();
810 AudioEngine::instance()->stop ();
814 /* this being a GUI and all, we want peakfiles */
816 AudioFileSource::set_build_peakfiles (true);
817 AudioFileSource::set_build_missing_peakfiles (true);
819 /* set default clock modes */
821 primary_clock->set_mode (AudioClock::Timecode);
822 secondary_clock->set_mode (AudioClock::BBT);
824 /* start the time-of-day-clock */
827 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
828 update_wall_clock ();
829 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
834 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
835 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
836 Config->map_parameters (pc);
838 UIConfiguration::instance().map_parameters (pc);
842 ARDOUR_UI::~ARDOUR_UI ()
844 UIConfiguration::instance().save_state();
848 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
849 // don't bother at 'real' exit. the OS cleans up for us.
850 delete big_clock; big_clock = 0;
851 delete primary_clock; primary_clock = 0;
852 delete secondary_clock; secondary_clock = 0;
853 delete _process_thread; _process_thread = 0;
854 delete time_info_box; time_info_box = 0;
855 delete meterbridge; meterbridge = 0;
856 delete luawindow; luawindow = 0;
857 delete editor; editor = 0;
858 delete mixer; mixer = 0;
859 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
861 delete gui_object_state; gui_object_state = 0;
862 delete main_window_visibility;
863 FastMeter::flush_pattern_cache ();
864 ArdourFader::flush_pattern_cache ();
868 /* Small trick to flush main-thread event pool.
869 * Other thread-pools are destroyed at pthread_exit(),
870 * but tmain thread termination is too late to trigger Pool::~Pool()
872 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.
873 delete ev->event_pool();
878 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
880 if (Splash::instance()) {
881 Splash::instance()->pop_back_for (win);
886 ARDOUR_UI::configure_timeout ()
888 if (last_configure_time == 0) {
889 /* no configure events yet */
893 /* force a gap of 0.5 seconds since the last configure event
896 if (get_microseconds() - last_configure_time < 500000) {
899 have_configure_timeout = false;
900 save_ardour_state ();
906 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
908 if (have_configure_timeout) {
909 last_configure_time = get_microseconds();
911 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
912 have_configure_timeout = true;
919 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
923 if (node.get_property ("roll", str)){
924 roll_controllable->set_id (str);
926 if (node.get_property ("stop", str)) {
927 stop_controllable->set_id (str);
929 if (node.get_property ("goto-start", str)) {
930 goto_start_controllable->set_id (str);
932 if (node.get_property ("goto-end", str)) {
933 goto_end_controllable->set_id (str);
935 if (node.get_property ("auto-loop", str)) {
936 auto_loop_controllable->set_id (str);
938 if (node.get_property ("play-selection", str)) {
939 play_selection_controllable->set_id (str);
941 if (node.get_property ("rec", str)) {
942 rec_controllable->set_id (str);
944 if (node.get_property ("shuttle", str)) {
945 shuttle_box.controllable()->set_id (str);
950 ARDOUR_UI::get_transport_controllable_state ()
952 XMLNode* node = new XMLNode(X_("TransportControllables"));
954 node->set_property (X_("roll"), roll_controllable->id());
955 node->set_property (X_("stop"), stop_controllable->id());
956 node->set_property (X_("goto-start"), goto_start_controllable->id());
957 node->set_property (X_("goto-end"), goto_end_controllable->id());
958 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
959 node->set_property (X_("play-selection"), play_selection_controllable->id());
960 node->set_property (X_("rec"), rec_controllable->id());
961 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
967 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
970 _session->save_state (snapshot_name);
975 ARDOUR_UI::autosave_session ()
977 if (g_main_depth() > 1) {
978 /* inside a recursive main loop,
979 give up because we may not be able to
985 if (!Config->get_periodic_safety_backups()) {
990 _session->maybe_write_autosave();
997 ARDOUR_UI::session_dirty_changed ()
1004 ARDOUR_UI::update_autosave ()
1006 if (_session && _session->dirty()) {
1007 if (_autosave_connection.connected()) {
1008 _autosave_connection.disconnect();
1011 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1012 Config->get_periodic_safety_backup_interval() * 1000);
1015 if (_autosave_connection.connected()) {
1016 _autosave_connection.disconnect();
1022 ARDOUR_UI::check_announcements ()
1025 string _annc_filename;
1028 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1029 #elif defined PLATFORM_WINDOWS
1030 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1032 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1034 _annc_filename.append (VERSIONSTRING);
1036 _announce_string = "";
1038 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1039 FILE* fin = g_fopen (path.c_str(), "rb");
1041 while (!feof (fin)) {
1044 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1047 _announce_string.append (tmp, len);
1052 pingback (VERSIONSTRING, path);
1057 _hide_splash (gpointer arg)
1059 ((ARDOUR_UI*)arg)->hide_splash();
1064 ARDOUR_UI::starting ()
1066 Application* app = Application::instance ();
1067 const char *nsm_url;
1068 bool brand_new_user = ArdourStartup::required ();
1070 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1071 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1073 if (ARDOUR_COMMAND_LINE::check_announcements) {
1074 check_announcements ();
1079 /* we need to create this early because it may need to set the
1080 * audio backend end up.
1084 audio_midi_setup.get (true);
1086 std::cerr << "audio-midi engine setup failed."<< std::endl;
1090 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1091 nsm = new NSM_Client;
1092 if (!nsm->init (nsm_url)) {
1093 /* the ardour executable may have different names:
1095 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1096 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1097 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1099 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1101 const char *process_name = g_getenv ("ARDOUR_SELF");
1102 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1105 // wait for announce reply from nsm server
1106 for ( i = 0; i < 5000; ++i) {
1110 if (nsm->is_active()) {
1115 error << _("NSM server did not announce itself") << endmsg;
1118 // wait for open command from nsm server
1119 for ( i = 0; i < 5000; ++i) {
1121 Glib::usleep (1000);
1122 if (nsm->client_id ()) {
1128 error << _("NSM: no client ID provided") << endmsg;
1132 if (_session && nsm) {
1133 _session->set_nsm_state( nsm->is_active() );
1135 error << _("NSM: no session created") << endmsg;
1139 // nsm requires these actions disabled
1140 vector<string> action_names;
1141 action_names.push_back("SaveAs");
1142 action_names.push_back("Rename");
1143 action_names.push_back("New");
1144 action_names.push_back("Open");
1145 action_names.push_back("Recent");
1146 action_names.push_back("Close");
1148 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1149 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1151 act->set_sensitive (false);
1158 error << _("NSM: initialization failed") << endmsg;
1164 if (brand_new_user) {
1165 _initial_verbose_plugin_scan = true;
1170 _initial_verbose_plugin_scan = false;
1171 switch (s.response ()) {
1172 case Gtk::RESPONSE_OK:
1179 // TODO: maybe IFF brand_new_user
1180 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1181 std::string dspd (Config->get_default_session_parent_dir());
1182 Searchpath ds (ARDOUR::ardour_data_search_path());
1183 ds.add_subdirectory_to_paths ("sessions");
1184 vector<string> demos;
1185 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1187 ARDOUR::RecentSessions rs;
1188 ARDOUR::read_recent_sessions (rs);
1190 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1191 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1192 std::string name = basename_nosuffix (basename_nosuffix (*i));
1193 std::string path = Glib::build_filename (dspd, name);
1194 /* skip if session-dir already exists */
1195 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1198 /* skip sessions that are already in 'recent'.
1199 * eg. a new user changed <session-default-dir> shorly after installation
1201 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1202 if ((*r).first == name) {
1207 PBD::FileArchive ar (*i);
1208 if (0 == ar.inflate (dspd)) {
1209 store_recent_sessions (name, path);
1210 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1216 #ifdef NO_PLUGIN_STATE
1218 ARDOUR::RecentSessions rs;
1219 ARDOUR::read_recent_sessions (rs);
1221 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1223 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1225 /* already used Ardour, have sessions ... warn about plugin state */
1227 ArdourDialog d (_("Free/Demo Version Warning"), true);
1229 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1230 CheckButton c (_("Don't warn me about this again"));
1232 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"),
1233 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1234 _("It will not restore OR save any plugin settings"),
1235 _("If you load an existing session with plugin settings\n"
1236 "they will not be used and will be lost."),
1237 _("To get full access to updates without this limitation\n"
1238 "consider becoming a subscriber for a low cost every month.")));
1239 l.set_justify (JUSTIFY_CENTER);
1241 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1243 d.get_vbox()->pack_start (l, true, true);
1244 d.get_vbox()->pack_start (b, false, false, 12);
1245 d.get_vbox()->pack_start (c, false, false, 12);
1247 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1248 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1252 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1254 if (d.run () != RESPONSE_OK) {
1260 /* go get a session */
1262 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1264 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1265 std::cerr << "Cannot get session parameters."<< std::endl;
1272 WM::Manager::instance().show_visible ();
1274 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1275 * editor window, and we may want stuff to be hidden.
1277 _status_bar_visibility.update ();
1279 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1281 /* all other dialogs are created conditionally */
1287 ARDOUR_UI::check_memory_locking ()
1289 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1290 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1294 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1296 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1298 struct rlimit limits;
1300 long pages, page_size;
1302 size_t pages_len=sizeof(pages);
1303 if ((page_size = getpagesize()) < 0 ||
1304 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1306 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1311 ram = (int64_t) pages * (int64_t) page_size;
1314 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1318 if (limits.rlim_cur != RLIM_INFINITY) {
1320 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1324 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1325 "This might cause %1 to run out of memory before your system "
1326 "runs out of memory. \n\n"
1327 "You can view the memory limit with 'ulimit -l', "
1328 "and it is normally controlled by %2"),
1331 X_("/etc/login.conf")
1333 X_(" /etc/security/limits.conf")
1337 msg.set_default_response (RESPONSE_OK);
1339 VBox* vbox = msg.get_vbox();
1341 CheckButton cb (_("Do not show this window again"));
1342 hbox.pack_start (cb, true, false);
1343 vbox->pack_start (hbox);
1348 pop_back_splash (msg);
1352 if (cb.get_active()) {
1353 XMLNode node (X_("no-memory-warning"));
1354 Config->add_instant_xml (node);
1359 #endif // !__APPLE__
1364 ARDOUR_UI::queue_finish ()
1366 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1370 ARDOUR_UI::idle_finish ()
1373 return false; /* do not call again */
1380 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1382 if (_session->dirty()) {
1383 vector<string> actions;
1384 actions.push_back (_("Don't quit"));
1385 actions.push_back (_("Just quit"));
1386 actions.push_back (_("Save and quit"));
1387 switch (ask_about_saving_session(actions)) {
1392 /* use the default name */
1393 if (save_state_canfail ("")) {
1394 /* failed - don't quit */
1395 MessageDialog msg (_main_window,
1396 string_compose (_("\
1397 %1 was unable to save your session.\n\n\
1398 If you still wish to quit, please use the\n\n\
1399 \"Just quit\" option."), PROGRAM_NAME));
1400 pop_back_splash(msg);
1410 second_connection.disconnect ();
1411 point_one_second_connection.disconnect ();
1412 point_zero_something_second_connection.disconnect();
1413 fps_connection.disconnect();
1416 delete ARDOUR_UI::instance()->video_timeline;
1417 ARDOUR_UI::instance()->video_timeline = NULL;
1418 stop_video_server();
1420 /* Save state before deleting the session, as that causes some
1421 windows to be destroyed before their visible state can be
1424 save_ardour_state ();
1426 if (key_editor.get (false)) {
1427 key_editor->disconnect ();
1430 close_all_dialogs ();
1433 _session->set_clean ();
1434 _session->remove_pending_capture_state ();
1439 halt_connection.disconnect ();
1440 AudioEngine::instance()->stop ();
1441 #ifdef WINDOWS_VST_SUPPORT
1442 fst_stop_threading();
1448 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1450 ArdourDialog window (_("Unsaved Session"));
1451 Gtk::HBox dhbox; // the hbox for the image and text
1452 Gtk::Label prompt_label;
1453 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1457 assert (actions.size() >= 3);
1459 window.add_button (actions[0], RESPONSE_REJECT);
1460 window.add_button (actions[1], RESPONSE_APPLY);
1461 window.add_button (actions[2], RESPONSE_ACCEPT);
1463 window.set_default_response (RESPONSE_ACCEPT);
1465 Gtk::Button noquit_button (msg);
1466 noquit_button.set_name ("EditorGTKButton");
1470 if (_session->snap_name() == _session->name()) {
1471 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?"),
1472 _session->snap_name());
1474 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?"),
1475 _session->snap_name());
1478 prompt_label.set_text (prompt);
1479 prompt_label.set_name (X_("PrompterLabel"));
1480 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1482 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1483 dhbox.set_homogeneous (false);
1484 dhbox.pack_start (*dimage, false, false, 5);
1485 dhbox.pack_start (prompt_label, true, false, 5);
1486 window.get_vbox()->pack_start (dhbox);
1488 window.set_name (_("Prompter"));
1489 window.set_modal (true);
1490 window.set_resizable (false);
1493 prompt_label.show();
1498 ResponseType r = (ResponseType) window.run();
1503 case RESPONSE_ACCEPT: // save and get out of here
1505 case RESPONSE_APPLY: // get out of here
1516 ARDOUR_UI::every_second ()
1519 update_disk_space ();
1520 update_timecode_format ();
1521 update_peak_thread_work ();
1523 if (nsm && nsm->is_active ()) {
1526 if (!_was_dirty && _session->dirty ()) {
1530 else if (_was_dirty && !_session->dirty ()){
1538 ARDOUR_UI::every_point_one_seconds ()
1540 if (editor) editor->build_region_boundary_cache();
1544 ARDOUR_UI::every_point_zero_something_seconds ()
1546 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1548 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1549 float mpeak = editor_meter->update_meters();
1550 if (mpeak > editor_meter_max_peak) {
1551 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1552 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1559 ARDOUR_UI::set_fps_timeout_connection ()
1561 unsigned int interval = 40;
1562 if (!_session) return;
1563 if (_session->timecode_frames_per_second() != 0) {
1564 /* ideally we'll use a select() to sleep and not accumulate
1565 * idle time to provide a regular periodic signal.
1566 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1567 * However, that'll require a dedicated thread and cross-thread
1568 * signals to the GUI Thread..
1570 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1571 * _session->sample_rate() / _session->nominal_sample_rate()
1572 / _session->timecode_frames_per_second()
1574 #ifdef PLATFORM_WINDOWS
1575 // the smallest windows scheduler time-slice is ~15ms.
1576 // periodic GUI timeouts shorter than that will cause
1577 // WaitForSingleObject to spinlock (100% of one CPU Core)
1578 // and gtk never enters idle mode.
1579 // also changing timeBeginPeriod(1) does not affect that in
1580 // any beneficial way, so we just limit the max rate for now.
1581 interval = std::max(30u, interval); // at most ~33Hz.
1583 interval = std::max(8u, interval); // at most 120Hz.
1586 fps_connection.disconnect();
1587 Timers::set_fps_interval (interval);
1591 ARDOUR_UI::update_sample_rate (samplecnt_t)
1595 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1597 if (!AudioEngine::instance()->running()) {
1599 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1603 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1606 /* no sample rate available */
1607 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1610 if (fmod (rate, 1000.0) != 0.0) {
1611 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1612 (float) rate / 1000.0f,
1613 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1615 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1617 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1621 sample_rate_label.set_markup (buf);
1625 ARDOUR_UI::update_format ()
1628 format_label.set_text ("");
1633 s << _("File:") << X_(" <span foreground=\"green\">");
1635 switch (_session->config.get_native_file_header_format ()) {
1670 switch (_session->config.get_native_file_data_format ()) {
1684 format_label.set_markup (s.str ());
1688 ARDOUR_UI::update_cpu_load ()
1690 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1691 double const c = AudioEngine::instance()->get_dsp_load ();
1693 const char* const bg = c > 90 ? " background=\"red\"" : "";
1697 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1699 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1701 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1704 dsp_load_label.set_markup (buf);
1707 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1709 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1711 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1714 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1718 ARDOUR_UI::update_peak_thread_work ()
1721 const int c = SourceFactory::peak_work_queue_length ();
1723 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1724 peak_thread_work_label.set_markup (buf);
1726 peak_thread_work_label.set_markup (X_(""));
1731 ARDOUR_UI::count_recenabled_streams (Route& route)
1733 Track* track = dynamic_cast<Track*>(&route);
1734 if (track && track->rec_enable_control()->get_value()) {
1735 rec_enabled_streams += track->n_inputs().n_total();
1740 ARDOUR_UI::format_disk_space_label (float remain_sec)
1742 if (remain_sec < 0) {
1743 disk_space_label.set_text (_("N/A"));
1744 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1750 int sec = floor (remain_sec);
1751 int hrs = sec / 3600;
1752 int mins = (sec / 60) % 60;
1753 int secs = sec % 60;
1754 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1755 ArdourWidgets::set_tooltip (disk_space_label, buf);
1757 if (remain_sec > 86400) {
1758 disk_space_label.set_text (_("Rec: >24h"));
1760 } else if (remain_sec > 32400 /* 9 hours */) {
1761 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1762 } else if (remain_sec > 5940 /* 99 mins */) {
1763 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1765 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1767 disk_space_label.set_text (buf);
1772 ARDOUR_UI::update_disk_space()
1774 if (_session == 0) {
1775 format_disk_space_label (-1);
1779 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1780 samplecnt_t fr = _session->sample_rate();
1783 /* skip update - no SR available */
1784 format_disk_space_label (-1);
1789 /* Available space is unknown */
1790 format_disk_space_label (-1);
1791 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1792 format_disk_space_label (max_samplecnt);
1794 rec_enabled_streams = 0;
1795 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1797 samplecnt_t samples = opt_samples.get_value_or (0);
1799 if (rec_enabled_streams) {
1800 samples /= rec_enabled_streams;
1803 format_disk_space_label (samples / (float)fr);
1809 ARDOUR_UI::update_timecode_format ()
1815 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1816 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1818 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1819 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1824 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1825 matching ? X_("green") : X_("red"),
1826 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1828 snprintf (buf, sizeof (buf), "TC: n/a");
1831 timecode_format_label.set_markup (buf);
1835 ARDOUR_UI::update_wall_clock ()
1839 static int last_min = -1;
1842 tm_now = localtime (&now);
1843 if (last_min != tm_now->tm_min) {
1845 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1846 wall_clock_label.set_text (buf);
1847 last_min = tm_now->tm_min;
1854 ARDOUR_UI::open_recent_session ()
1856 bool can_return = (_session != 0);
1858 SessionDialog recent_session_dialog;
1862 ResponseType r = (ResponseType) recent_session_dialog.run ();
1865 case RESPONSE_ACCEPT:
1869 recent_session_dialog.hide();
1876 recent_session_dialog.hide();
1880 std::string path = recent_session_dialog.session_folder();
1881 std::string state = recent_session_dialog.session_name (should_be_new);
1883 if (should_be_new == true) {
1887 _session_is_new = false;
1889 if (load_session (path, state) == 0) {
1898 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1900 if (!AudioEngine::instance()->running()) {
1901 MessageDialog msg (parent, string_compose (
1902 _("%1 is not connected to any audio backend.\n"
1903 "You cannot open or close sessions in this condition"),
1905 pop_back_splash (msg);
1913 ARDOUR_UI::open_session ()
1915 if (!check_audioengine (_main_window)) {
1919 /* ardour sessions are folders */
1920 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1921 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1922 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1923 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1926 string session_parent_dir = Glib::path_get_dirname(_session->path());
1927 open_session_selector.set_current_folder(session_parent_dir);
1929 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1932 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1934 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1935 string default_session_folder = Config->get_default_session_parent_dir();
1936 open_session_selector.add_shortcut_folder (default_session_folder);
1938 catch (Glib::Error const& e) {
1939 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1942 FileFilter session_filter;
1943 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1944 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1945 open_session_selector.add_filter (session_filter);
1947 FileFilter archive_filter;
1948 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1949 archive_filter.set_name (_("Session Archives"));
1951 open_session_selector.add_filter (archive_filter);
1953 open_session_selector.set_filter (session_filter);
1955 int response = open_session_selector.run();
1956 open_session_selector.hide ();
1958 if (response == Gtk::RESPONSE_CANCEL) {
1962 string session_path = open_session_selector.get_filename();
1966 if (session_path.length() > 0) {
1967 int rv = ARDOUR::inflate_session (session_path,
1968 Config->get_default_session_parent_dir(), path, name);
1970 _session_is_new = false;
1971 load_session (path, name);
1974 MessageDialog msg (_main_window,
1975 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1978 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1979 _session_is_new = isnew;
1980 load_session (path, name);
1986 ARDOUR_UI::session_add_mixed_track (
1987 const ChanCount& input,
1988 const ChanCount& output,
1989 RouteGroup* route_group,
1991 const string& name_template,
1993 PluginInfoPtr instrument,
1994 Plugin::PresetRecord* pset,
1995 ARDOUR::PresentationInfo::order_t order)
1999 if (Profile->get_mixbus ()) {
2004 list<boost::shared_ptr<MidiTrack> > tracks;
2005 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2007 if (tracks.size() != how_many) {
2008 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2013 display_insufficient_ports_message ();
2019 ARDOUR_UI::session_add_midi_bus (
2020 RouteGroup* route_group,
2022 const string& name_template,
2024 PluginInfoPtr instrument,
2025 Plugin::PresetRecord* pset,
2026 ARDOUR::PresentationInfo::order_t order)
2028 if (_session == 0) {
2029 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2033 if (Profile->get_mixbus ()) {
2039 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2040 if (routes.size() != how_many) {
2041 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2046 display_insufficient_ports_message ();
2052 ARDOUR_UI::session_add_midi_route (
2054 RouteGroup* route_group,
2056 const string& name_template,
2058 PluginInfoPtr instrument,
2059 Plugin::PresetRecord* pset,
2060 ARDOUR::PresentationInfo::order_t order)
2062 ChanCount one_midi_channel;
2063 one_midi_channel.set (DataType::MIDI, 1);
2066 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2068 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2073 ARDOUR_UI::session_add_audio_route (
2075 int32_t input_channels,
2076 int32_t output_channels,
2077 ARDOUR::TrackMode mode,
2078 RouteGroup* route_group,
2080 string const & name_template,
2082 ARDOUR::PresentationInfo::order_t order)
2084 list<boost::shared_ptr<AudioTrack> > tracks;
2091 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2093 if (tracks.size() != how_many) {
2094 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2100 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2102 if (routes.size() != how_many) {
2103 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2110 display_insufficient_ports_message ();
2115 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2116 (*i)->set_strict_io (true);
2118 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2119 (*i)->set_strict_io (true);
2125 ARDOUR_UI::session_add_foldback_bus (uint32_t how_many, string const & name_template)
2132 routes = _session->new_audio_route (2, 2, 0, how_many, name_template, PresentationInfo::FoldbackBus, -1);
2134 if (routes.size() != how_many) {
2135 error << string_compose (P_("could not create %1 new foldback bus", "could not create %1 new foldback busses", how_many), how_many)
2141 display_insufficient_ports_message ();
2145 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2146 (*i)->set_strict_io (true);
2151 ARDOUR_UI::display_insufficient_ports_message ()
2153 MessageDialog msg (_main_window,
2154 string_compose (_("There are insufficient ports available\n\
2155 to create a new track or bus.\n\
2156 You should save %1, exit and\n\
2157 restart with more ports."), PROGRAM_NAME));
2158 pop_back_splash (msg);
2163 ARDOUR_UI::transport_goto_start ()
2166 _session->goto_start();
2168 /* force displayed area in editor to start no matter
2169 what "follow playhead" setting is.
2173 editor->center_screen (_session->current_start_sample ());
2179 ARDOUR_UI::transport_goto_zero ()
2182 _session->request_locate (0);
2184 /* force displayed area in editor to start no matter
2185 what "follow playhead" setting is.
2189 editor->reset_x_origin (0);
2195 ARDOUR_UI::transport_goto_wallclock ()
2197 if (_session && editor) {
2201 samplepos_t samples;
2204 localtime_r (&now, &tmnow);
2206 samplecnt_t sample_rate = _session->sample_rate();
2208 if (sample_rate == 0) {
2209 /* no frame rate available */
2213 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2214 samples += tmnow.tm_min * (60 * sample_rate);
2215 samples += tmnow.tm_sec * sample_rate;
2217 _session->request_locate (samples, _session->transport_rolling ());
2219 /* force displayed area in editor to start no matter
2220 what "follow playhead" setting is.
2224 editor->center_screen (samples);
2230 ARDOUR_UI::transport_goto_end ()
2233 samplepos_t const sample = _session->current_end_sample();
2234 _session->request_locate (sample);
2236 /* force displayed area in editor to start no matter
2237 what "follow playhead" setting is.
2241 editor->center_screen (sample);
2247 ARDOUR_UI::transport_stop ()
2253 if (_session->is_auditioning()) {
2254 _session->cancel_audition ();
2258 _session->request_stop (false, true);
2261 /** Check if any tracks are record enabled. If none are, record enable all of them.
2262 * @return true if track record-enabled status was changed, false otherwise.
2265 ARDOUR_UI::trx_record_enable_all_tracks ()
2271 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2272 bool none_record_enabled = true;
2274 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2275 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2278 if (t->rec_enable_control()->get_value()) {
2279 none_record_enabled = false;
2284 if (none_record_enabled) {
2285 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2288 return none_record_enabled;
2292 ARDOUR_UI::transport_record (bool roll)
2295 switch (_session->record_status()) {
2296 case Session::Disabled:
2297 if (_session->ntracks() == 0) {
2298 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."));
2302 if (Profile->get_trx()) {
2303 roll = trx_record_enable_all_tracks ();
2305 _session->maybe_enable_record ();
2310 case Session::Recording:
2312 _session->request_stop();
2314 _session->disable_record (false, true);
2318 case Session::Enabled:
2319 _session->disable_record (false, true);
2325 ARDOUR_UI::transport_roll ()
2331 if (_session->is_auditioning()) {
2335 if (_session->config.get_external_sync()) {
2336 switch (TransportMasterManager::instance().current()->type()) {
2340 /* transport controlled by the master */
2345 bool rolling = _session->transport_rolling();
2347 if (_session->get_play_loop()) {
2349 /* If loop playback is not a mode, then we should cancel
2350 it when this action is requested. If it is a mode
2351 we just leave it in place.
2354 if (!Config->get_loop_is_mode()) {
2355 /* XXX it is not possible to just leave seamless loop and keep
2356 playing at present (nov 4th 2009)
2358 if (!Config->get_seamless_loop()) {
2359 /* stop loop playback and stop rolling */
2360 _session->request_play_loop (false, true);
2361 } else if (rolling) {
2362 /* stop loop playback but keep rolling */
2363 _session->request_play_loop (false, false);
2367 } else if (_session->get_play_range () ) {
2368 /* stop playing a range if we currently are */
2369 _session->request_play_range (0, true);
2373 _session->request_transport_speed (1.0f);
2378 ARDOUR_UI::get_smart_mode() const
2380 return ( editor->get_smart_mode() );
2385 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2391 if (_session->is_auditioning()) {
2392 _session->cancel_audition ();
2396 if (_session->config.get_external_sync()) {
2397 switch (TransportMasterManager::instance().current()->type()) {
2401 /* transport controlled by the master */
2406 bool rolling = _session->transport_rolling();
2407 bool affect_transport = true;
2409 if (rolling && roll_out_of_bounded_mode) {
2410 /* drop out of loop/range playback but leave transport rolling */
2411 if (_session->get_play_loop()) {
2412 if (_session->actively_recording()) {
2414 /* just stop using the loop, then actually stop
2417 _session->request_play_loop (false, affect_transport);
2420 if (Config->get_seamless_loop()) {
2421 /* the disk buffers contain copies of the loop - we can't
2422 just keep playing, so stop the transport. the user
2423 can restart as they wish.
2425 affect_transport = true;
2427 /* disk buffers are normal, so we can keep playing */
2428 affect_transport = false;
2430 _session->request_play_loop (false, affect_transport);
2432 } else if (_session->get_play_range ()) {
2433 affect_transport = false;
2434 _session->request_play_range (0, true);
2438 if (affect_transport) {
2440 _session->request_stop (with_abort, true);
2442 } else if (!with_abort) { /* with_abort == true means the
2443 * command was intended to stop
2444 * transport, not start.
2447 /* the only external sync condition we can be in here
2448 * would be Engine (JACK) sync, in which case we still
2452 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
2453 _session->request_play_range (&editor->get_selection().time, true);
2454 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2456 _session->request_transport_speed (1.0f);
2462 ARDOUR_UI::toggle_session_auto_loop ()
2468 Location * looploc = _session->locations()->auto_loop_location();
2474 if (_session->get_play_loop()) {
2476 /* looping enabled, our job is to disable it */
2478 _session->request_play_loop (false);
2482 /* looping not enabled, our job is to enable it.
2484 loop-is-NOT-mode: this action always starts the transport rolling.
2485 loop-IS-mode: this action simply sets the loop play mechanism, but
2486 does not start transport.
2488 if (Config->get_loop_is_mode()) {
2489 _session->request_play_loop (true, false);
2491 _session->request_play_loop (true, true);
2495 //show the loop markers
2496 looploc->set_hidden (false, this);
2500 ARDOUR_UI::transport_play_selection ()
2506 editor->play_selection ();
2510 ARDOUR_UI::transport_play_preroll ()
2515 editor->play_with_preroll ();
2519 ARDOUR_UI::transport_rec_preroll ()
2524 editor->rec_with_preroll ();
2528 ARDOUR_UI::transport_rec_count_in ()
2533 editor->rec_with_count_in ();
2537 ARDOUR_UI::transport_rewind (int option)
2539 float current_transport_speed;
2542 current_transport_speed = _session->transport_speed();
2544 if (current_transport_speed >= 0.0f) {
2547 _session->request_transport_speed (-1.0f);
2550 _session->request_transport_speed (-4.0f);
2553 _session->request_transport_speed (-0.5f);
2558 _session->request_transport_speed (current_transport_speed * 1.5f);
2564 ARDOUR_UI::transport_forward (int option)
2570 float current_transport_speed = _session->transport_speed();
2572 if (current_transport_speed <= 0.0f) {
2575 _session->request_transport_speed (1.0f);
2578 _session->request_transport_speed (4.0f);
2581 _session->request_transport_speed (0.5f);
2586 _session->request_transport_speed (current_transport_speed * 1.5f);
2591 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2597 boost::shared_ptr<Route> r;
2599 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2601 boost::shared_ptr<Track> t;
2603 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2604 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2610 ARDOUR_UI::map_transport_state ()
2613 layered_button.set_sensitive (false);
2617 shuttle_box.map_transport_state ();
2619 float sp = _session->transport_speed();
2622 layered_button.set_sensitive (!_session->actively_recording ());
2624 layered_button.set_sensitive (true);
2625 update_disk_space ();
2630 ARDOUR_UI::blink_handler (bool blink_on)
2632 sync_blink (blink_on);
2634 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2637 error_blink (blink_on);
2638 solo_blink (blink_on);
2639 audition_blink (blink_on);
2640 feedback_blink (blink_on);
2644 ARDOUR_UI::update_clocks ()
2646 if (!_session) return;
2648 if (editor && !editor->dragging_playhead()) {
2649 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2654 ARDOUR_UI::start_clocking ()
2656 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2657 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2659 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2664 ARDOUR_UI::stop_clocking ()
2666 clock_signal_connection.disconnect ();
2670 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2674 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2676 label->set_text (buf);
2677 bar->set_fraction (fraction);
2679 /* process events, redraws, etc. */
2681 while (gtk_events_pending()) {
2682 gtk_main_iteration ();
2685 return true; /* continue with save-as */
2689 ARDOUR_UI::save_session_as ()
2695 if (_session->dirty()) {
2696 vector<string> actions;
2697 actions.push_back (_("Abort save-as"));
2698 actions.push_back (_("Don't save now, just save-as"));
2699 actions.push_back (_("Save it first"));
2700 switch (ask_about_saving_session(actions)) {
2705 if (save_state_canfail ("")) {
2706 MessageDialog msg (_main_window,
2707 string_compose (_("\
2708 %1 was unable to save your session.\n\n\
2709 If you still wish to proceed, please use the\n\n\
2710 \"Don't save now\" option."), PROGRAM_NAME));
2711 pop_back_splash(msg);
2717 _session->remove_pending_capture_state ();
2722 if (!save_as_dialog) {
2723 save_as_dialog = new SaveAsDialog;
2726 save_as_dialog->set_name (_session->name());
2728 int response = save_as_dialog->run ();
2730 save_as_dialog->hide ();
2733 case Gtk::RESPONSE_OK:
2742 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2743 sa.new_name = save_as_dialog->new_name ();
2744 sa.switch_to = save_as_dialog->switch_to();
2745 sa.copy_media = save_as_dialog->copy_media();
2746 sa.copy_external = save_as_dialog->copy_external();
2747 sa.include_media = save_as_dialog->include_media ();
2749 /* Only bother with a progress dialog if we're going to copy
2750 media into the save-as target. Without that choice, this
2751 will be very fast because we're only talking about a few kB's to
2752 perhaps a couple of MB's of data.
2755 ArdourDialog progress_dialog (_("Save As"), true);
2758 if (sa.include_media && sa.copy_media) {
2760 Gtk::Label* label = manage (new Gtk::Label());
2761 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2763 progress_dialog.get_vbox()->pack_start (*label);
2764 progress_dialog.get_vbox()->pack_start (*progress_bar);
2766 progress_bar->show ();
2768 /* this signal will be emitted from within this, the calling thread,
2769 * after every file is copied. It provides information on percentage
2770 * complete (in terms of total data to copy), the number of files
2771 * copied so far, and the total number to copy.
2774 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2776 progress_dialog.show_all ();
2777 progress_dialog.present ();
2780 if (_session->save_as (sa)) {
2782 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2786 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2787 * the trick is this: if the new session was copy with media included,
2788 * then Session::save_as() will have already done a neat trick to avoid
2789 * us having to unload and load the new state. But if the media was not
2790 * included, then this is required (it avoids us having to otherwise
2791 * drop all references to media (sources).
2794 if (!sa.include_media && sa.switch_to) {
2795 unload_session (false);
2796 load_session (sa.final_session_folder_name, sa.new_name);
2801 ARDOUR_UI::archive_session ()
2809 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2811 SessionArchiveDialog sad;
2812 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2813 int response = sad.run ();
2815 if (response != Gtk::RESPONSE_OK) {
2820 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2821 MessageDialog msg (_("Session Archiving failed."));
2827 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2831 struct tm local_time;
2834 localtime_r (&n, &local_time);
2835 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2836 if (switch_to_it && _session->dirty ()) {
2837 save_state_canfail ("");
2840 save_state (timebuf, switch_to_it);
2845 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2849 prompter.get_result (snapname);
2851 bool do_save = (snapname.length() != 0);
2854 char illegal = Session::session_name_is_legal(snapname);
2856 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2857 "snapshot names may not contain a '%1' character"), illegal));
2863 vector<std::string> p;
2864 get_state_files_in_directory (_session->session_directory().root_path(), p);
2865 vector<string> n = get_file_names_no_extension (p);
2867 if (find (n.begin(), n.end(), snapname) != n.end()) {
2869 do_save = overwrite_file_dialog (prompter,
2870 _("Confirm Snapshot Overwrite"),
2871 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2875 save_state (snapname, switch_to_it);
2885 /** Ask the user for the name of a new snapshot and then take it.
2889 ARDOUR_UI::snapshot_session (bool switch_to_it)
2891 if (switch_to_it && _session->dirty()) {
2892 vector<string> actions;
2893 actions.push_back (_("Abort saving snapshot"));
2894 actions.push_back (_("Don't save now, just snapshot"));
2895 actions.push_back (_("Save it first"));
2896 switch (ask_about_saving_session(actions)) {
2901 if (save_state_canfail ("")) {
2902 MessageDialog msg (_main_window,
2903 string_compose (_("\
2904 %1 was unable to save your session.\n\n\
2905 If you still wish to proceed, please use the\n\n\
2906 \"Don't save now\" option."), PROGRAM_NAME));
2907 pop_back_splash(msg);
2913 _session->remove_pending_capture_state ();
2918 Prompter prompter (true);
2919 prompter.set_name ("Prompter");
2920 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2922 prompter.set_title (_("Snapshot and switch"));
2923 prompter.set_prompt (_("New session name"));
2925 prompter.set_title (_("Take Snapshot"));
2926 prompter.set_prompt (_("Name of new snapshot"));
2930 prompter.set_initial_text (_session->snap_name());
2932 Glib::DateTime tm (g_date_time_new_now_local ());
2933 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2936 bool finished = false;
2938 switch (prompter.run()) {
2939 case RESPONSE_ACCEPT:
2941 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2952 /** Ask the user for a new session name and then rename the session to it.
2956 ARDOUR_UI::rename_session ()
2962 Prompter prompter (true);
2965 prompter.set_name ("Prompter");
2966 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2967 prompter.set_title (_("Rename Session"));
2968 prompter.set_prompt (_("New session name"));
2971 switch (prompter.run()) {
2972 case RESPONSE_ACCEPT:
2974 prompter.get_result (name);
2976 bool do_rename = (name.length() != 0);
2979 char illegal = Session::session_name_is_legal (name);
2982 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2983 "session names may not contain a '%1' character"), illegal));
2988 switch (_session->rename (name)) {
2990 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2991 msg.set_position (WIN_POS_MOUSE);
2999 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3000 msg.set_position (WIN_POS_MOUSE);
3016 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3018 if (!_session || _session->deletion_in_progress()) {
3022 XMLNode* node = new XMLNode (X_("UI"));
3024 WM::Manager::instance().add_state (*node);
3026 node->add_child_nocopy (gui_object_state->get_state());
3028 _session->add_extra_xml (*node);
3030 if (export_video_dialog) {
3031 _session->add_extra_xml (export_video_dialog->get_state());
3034 save_state_canfail (name, switch_to_it);
3038 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3043 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3048 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3053 ARDOUR_UI::primary_clock_value_changed ()
3056 _session->request_locate (primary_clock->current_time ());
3061 ARDOUR_UI::big_clock_value_changed ()
3064 _session->request_locate (big_clock->current_time ());
3069 ARDOUR_UI::secondary_clock_value_changed ()
3072 _session->request_locate (secondary_clock->current_time ());
3076 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3078 if (response == RESPONSE_ACCEPT) {
3079 const string name = d->get_template_name ();
3080 const string desc = d->get_description ();
3082 int failed = _session->save_template (name, desc);
3084 if (failed == -2) { /* file already exists. */
3085 bool overwrite = overwrite_file_dialog (*d,
3086 _("Confirm Template Overwrite"),
3087 _("A template already exists with that name. Do you want to overwrite it?"));
3090 _session->save_template (name, desc, true);
3102 ARDOUR_UI::save_template ()
3104 if (!check_audioengine (_main_window)) {
3108 const std::string desc = SessionMetadata::Metadata()->description ();
3109 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3110 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3114 void ARDOUR_UI::manage_templates ()
3121 ARDOUR_UI::edit_metadata ()
3123 SessionMetadataEditor dialog;
3124 dialog.set_session (_session);
3125 dialog.grab_focus ();
3130 ARDOUR_UI::import_metadata ()
3132 SessionMetadataImporter dialog;
3133 dialog.set_session (_session);
3138 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3140 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3142 MessageDialog msg (str,
3144 Gtk::MESSAGE_WARNING,
3145 Gtk::BUTTONS_YES_NO,
3149 msg.set_name (X_("OpenExistingDialog"));
3150 msg.set_title (_("Open Existing Session"));
3151 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3152 msg.set_position (Gtk::WIN_POS_CENTER);
3153 pop_back_splash (msg);
3155 switch (msg.run()) {
3164 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3166 BusProfile bus_profile;
3169 bus_profile.master_out_channels = 2;
3171 /* get settings from advanced section of NSD */
3172 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3175 // NULL profile: no master, no monitor
3176 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3184 ARDOUR_UI::load_from_application_api (const std::string& path)
3186 /* OS X El Capitan (and probably later) now somehow passes the command
3187 line arguments to an app via the openFile delegate protocol. Ardour
3188 already does its own command line processing, and having both
3189 pathways active causes crashes. So, if the command line was already
3190 set, do nothing here.
3193 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3197 ARDOUR_COMMAND_LINE::session_name = path;
3199 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3201 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3203 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3204 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3205 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3206 * -> SessionDialog is not displayed
3209 if (_session_dialog) {
3210 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3211 std::string session_path = path;
3212 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3213 session_path = Glib::path_get_dirname (session_path);
3215 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3216 _session_dialog->set_provided_session (session_name, session_path);
3217 _session_dialog->response (RESPONSE_NONE);
3218 _session_dialog->hide();
3223 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3224 /* /path/to/foo => /path/to/foo, foo */
3225 rv = load_session (path, basename_nosuffix (path));
3227 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3228 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3231 // if load_session fails -> pop up SessionDialog.
3233 ARDOUR_COMMAND_LINE::session_name = "";
3235 if (get_session_parameters (true, false)) {
3241 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3243 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3245 string session_name;
3246 string session_path;
3247 string template_name;
3249 bool likely_new = false;
3250 bool cancel_not_quit;
3252 /* deal with any existing DIRTY session now, rather than later. don't
3253 * treat a non-dirty session this way, so that it stays visible
3254 * as we bring up the new session dialog.
3257 if (_session && ARDOUR_UI::instance()->video_timeline) {
3258 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3261 /* if there is already a session, relabel the button
3262 on the SessionDialog so that we don't Quit directly
3264 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3266 if (_session && _session->dirty()) {
3267 if (unload_session (false)) {
3268 /* unload cancelled by user */
3271 ARDOUR_COMMAND_LINE::session_name = "";
3274 if (!load_template.empty()) {
3275 should_be_new = true;
3276 template_name = load_template;
3279 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3280 session_path = ARDOUR_COMMAND_LINE::session_name;
3282 if (!session_path.empty()) {
3283 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3284 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3285 /* session/snapshot file, change path to be dir */
3286 session_path = Glib::path_get_dirname (session_path);
3291 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3293 _session_dialog = &session_dialog;
3296 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3298 /* if they named a specific statefile, use it, otherwise they are
3299 just giving a session folder, and we want to use it as is
3300 to find the session.
3303 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3305 if (suffix != string::npos) {
3306 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3307 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3308 session_name = Glib::path_get_basename (session_name);
3310 session_path = ARDOUR_COMMAND_LINE::session_name;
3311 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3316 session_dialog.clear_given ();
3319 if (should_be_new || session_name.empty()) {
3320 /* need the dialog to get info from user */
3322 cerr << "run dialog\n";
3324 switch (session_dialog.run()) {
3325 case RESPONSE_ACCEPT:
3328 /* this is used for async * app->ShouldLoad(). */
3329 continue; // while loop
3332 if (quit_on_cancel) {
3333 ARDOUR_UI::finish ();
3334 Gtkmm2ext::Application::instance()->cleanup();
3336 pthread_cancel_all ();
3337 return -1; // caller is responsible to call exit()
3343 session_dialog.hide ();
3346 /* if we run the startup dialog again, offer more than just "new session" */
3348 should_be_new = false;
3350 session_name = session_dialog.session_name (likely_new);
3351 session_path = session_dialog.session_folder ();
3358 int rv = ARDOUR::inflate_session (session_name,
3359 Config->get_default_session_parent_dir(), session_path, session_name);
3361 MessageDialog msg (session_dialog,
3362 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3367 session_dialog.set_provided_session (session_name, session_path);
3371 // XXX check archive, inflate
3372 string::size_type suffix = session_name.find (statefile_suffix);
3374 if (suffix != string::npos) {
3375 session_name = session_name.substr (0, suffix);
3378 /* this shouldn't happen, but we catch it just in case it does */
3380 if (session_name.empty()) {
3384 if (session_dialog.use_session_template()) {
3385 template_name = session_dialog.session_template_name();
3386 _session_is_new = true;
3389 if (session_name[0] == G_DIR_SEPARATOR ||
3390 #ifdef PLATFORM_WINDOWS
3391 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3393 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3394 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3399 /* absolute path or cwd-relative path specified for session name: infer session folder
3400 from what was given.
3403 session_path = Glib::path_get_dirname (session_name);
3404 session_name = Glib::path_get_basename (session_name);
3408 session_path = session_dialog.session_folder();
3410 char illegal = Session::session_name_is_legal (session_name);
3413 MessageDialog msg (session_dialog,
3414 string_compose (_("To ensure compatibility with various systems\n"
3415 "session names may not contain a '%1' character"),
3418 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3423 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3426 if (likely_new && !nsm) {
3428 std::string existing = Glib::build_filename (session_path, session_name);
3430 if (!ask_about_loading_existing_session (existing)) {
3431 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3436 _session_is_new = false;
3441 pop_back_splash (session_dialog);
3442 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3444 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3448 char illegal = Session::session_name_is_legal(session_name);
3451 pop_back_splash (session_dialog);
3452 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3453 "session names may not contain a '%1' character"), illegal));
3455 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3459 _session_is_new = true;
3462 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3464 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3465 meta_session_setup (template_name.substr (11));
3467 } else if (likely_new && template_name.empty()) {
3469 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3473 ret = load_session (session_path, session_name, template_name);
3476 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3480 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3481 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3485 /* clear this to avoid endless attempts to load the
3489 ARDOUR_COMMAND_LINE::session_name = "";
3493 _session_dialog = NULL;
3499 ARDOUR_UI::close_session()
3501 if (!check_audioengine (_main_window)) {
3505 if (unload_session (true)) {
3509 ARDOUR_COMMAND_LINE::session_name = "";
3511 if (get_session_parameters (true, false)) {
3516 /** @param snap_name Snapshot name (without .ardour suffix).
3517 * @return -2 if the load failed because we are not connected to the AudioEngine.
3520 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3522 /* load_session calls flush_pending() which allows
3523 * GUI interaction and potentially loading another session
3524 * (that was easy via snapshot sidebar).
3525 * Recursing into load_session() from load_session() and recusive
3526 * event loops causes all kind of crashes.
3528 assert (!session_load_in_progress);
3529 if (session_load_in_progress) {
3532 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3534 Session *new_session;
3539 unload_status = unload_session ();
3541 if (unload_status < 0) {
3543 } else if (unload_status > 0) {
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);
3659 _session->set_clean ();
3662 #ifdef WINDOWS_VST_SUPPORT
3663 fst_stop_threading();
3667 Timers::TimerSuspender t;
3671 #ifdef WINDOWS_VST_SUPPORT
3672 fst_start_threading();
3676 if (!mix_template.empty ()) {
3677 /* if mix_template is given, assume this is a new session */
3678 string metascript = Glib::build_filename (mix_template, "template.lua");
3679 meta_session_setup (metascript);
3684 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3685 * which is queued by set_session().
3686 * If session-loading fails we hide it explicitly.
3687 * This covers both cases in a central place.
3696 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3698 Session *new_session;
3701 x = unload_session ();
3709 _session_is_new = true;
3712 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3715 catch (SessionException const& e) {
3716 cerr << "Here are the errors associated with this failed session:\n";
3718 cerr << "---------\n";
3719 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3720 msg.set_title (_("Loading Error"));
3721 msg.set_position (Gtk::WIN_POS_CENTER);
3722 pop_back_splash (msg);
3727 cerr << "Here are the errors associated with this failed session:\n";
3729 cerr << "---------\n";
3730 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3731 msg.set_title (_("Loading Error"));
3732 msg.set_position (Gtk::WIN_POS_CENTER);
3733 pop_back_splash (msg);
3738 /* Give the new session the default GUI state, if such things exist */
3741 n = Config->instant_xml (X_("Editor"));
3743 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3744 new_session->add_instant_xml (*n, false);
3746 n = Config->instant_xml (X_("Mixer"));
3748 new_session->add_instant_xml (*n, false);
3751 n = Config->instant_xml (X_("Preferences"));
3753 new_session->add_instant_xml (*n, false);
3756 /* Put the playhead at 0 and scroll fully left */
3757 n = new_session->instant_xml (X_("Editor"));
3759 n->set_property (X_("playhead"), X_("0"));
3760 n->set_property (X_("left-frame"), X_("0"));
3763 set_session (new_session);
3765 new_session->save_state(new_session->name());
3771 static void _lua_print (std::string s) {
3773 std::cout << "LuaInstance: " << s << "\n";
3775 PBD::info << "LuaInstance: " << s << endmsg;
3778 std::map<std::string, std::string>
3779 ARDOUR_UI::route_setup_info (const std::string& script_path)
3781 std::map<std::string, std::string> rv;
3783 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3788 lua.Print.connect (&_lua_print);
3791 lua_State* L = lua.getState();
3792 LuaInstance::register_classes (L);
3793 LuaBindings::set_session (L, _session);
3794 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3795 lua_setglobal (L, "Editor");
3797 lua.do_command ("function ardour () end");
3798 lua.do_file (script_path);
3801 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3802 if (!fn.isFunction ()) {
3805 luabridge::LuaRef rs = fn ();
3806 if (!rs.isTable ()) {
3809 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3810 if (!i.key().isString()) {
3813 std::string key = i.key().tostring();
3814 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3815 rv[key] = i.value().tostring();
3818 } catch (luabridge::LuaException const& e) {
3819 cerr << "LuaException:" << e.what () << endl;
3825 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3827 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3830 assert (add_route_dialog);
3833 if ((count = add_route_dialog->count()) <= 0) {
3838 lua.Print.connect (&_lua_print);
3841 lua_State* L = lua.getState();
3842 LuaInstance::register_classes (L);
3843 LuaBindings::set_session (L, _session);
3844 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3845 lua_setglobal (L, "Editor");
3847 lua.do_command ("function ardour () end");
3848 lua.do_file (script_path);
3850 luabridge::LuaRef args (luabridge::newTable (L));
3852 args["name"] = add_route_dialog->name_template ();
3853 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3854 args["group"] = add_route_dialog->route_group ();
3855 args["strict_io"] = add_route_dialog->use_strict_io ();
3856 args["instrument"] = add_route_dialog->requested_instrument ();
3857 args["track_mode"] = add_route_dialog->mode ();
3858 args["channels"] = add_route_dialog->channel_count ();
3859 args["how_many"] = count;
3862 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3863 if (fn.isFunction()) {
3866 } catch (luabridge::LuaException const& e) {
3867 cerr << "LuaException:" << e.what () << endl;
3869 display_insufficient_ports_message ();
3874 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3876 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3881 lua.Print.connect (&_lua_print);
3884 lua_State* L = lua.getState();
3885 LuaInstance::register_classes (L);
3886 LuaBindings::set_session (L, _session);
3887 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3888 lua_setglobal (L, "Editor");
3890 lua.do_command ("function ardour () end");
3891 lua.do_file (script_path);
3894 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3895 if (fn.isFunction()) {
3898 } catch (luabridge::LuaException const& e) {
3899 cerr << "LuaException:" << e.what () << endl;
3901 display_insufficient_ports_message ();
3906 ARDOUR_UI::launch_chat ()
3908 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3910 dialog.set_title (_("About the Chat"));
3911 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."));
3913 switch (dialog.run()) {
3915 open_uri("http://webchat.freenode.net/?channels=ardour");
3923 ARDOUR_UI::launch_manual ()
3925 PBD::open_uri (Config->get_tutorial_manual_url());
3929 ARDOUR_UI::launch_reference ()
3931 PBD::open_uri (Config->get_reference_manual_url());
3935 ARDOUR_UI::launch_tracker ()
3937 PBD::open_uri ("http://tracker.ardour.org");
3941 ARDOUR_UI::launch_subscribe ()
3943 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3947 ARDOUR_UI::launch_cheat_sheet ()
3950 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3952 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3957 ARDOUR_UI::launch_website ()
3959 PBD::open_uri ("http://ardour.org");
3963 ARDOUR_UI::launch_website_dev ()
3965 PBD::open_uri ("http://ardour.org/development.html");
3969 ARDOUR_UI::launch_forums ()
3971 PBD::open_uri ("https://community.ardour.org/forums");
3975 ARDOUR_UI::launch_howto_report ()
3977 PBD::open_uri ("http://ardour.org/reporting_bugs");
3981 ARDOUR_UI::loading_message (const std::string& msg)
3983 if (ARDOUR_COMMAND_LINE::no_splash) {
3991 splash->message (msg);
3995 ARDOUR_UI::show_splash ()
3999 splash = new Splash;
4009 ARDOUR_UI::hide_splash ()
4016 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4020 removed = rep.paths.size();
4023 MessageDialog msgd (_main_window,
4024 _("No files were ready for clean-up"),
4028 msgd.set_title (_("Clean-up"));
4029 msgd.set_secondary_text (_("If this seems surprising, \n\
4030 check for any existing snapshots.\n\
4031 These may still include regions that\n\
4032 require some unused files to continue to exist."));
4038 ArdourDialog results (_("Clean-up"), true, false);
4040 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4041 CleanupResultsModelColumns() {
4045 Gtk::TreeModelColumn<std::string> visible_name;
4046 Gtk::TreeModelColumn<std::string> fullpath;
4050 CleanupResultsModelColumns results_columns;
4051 Glib::RefPtr<Gtk::ListStore> results_model;
4052 Gtk::TreeView results_display;
4054 results_model = ListStore::create (results_columns);
4055 results_display.set_model (results_model);
4056 results_display.append_column (list_title, results_columns.visible_name);
4058 results_display.set_name ("CleanupResultsList");
4059 results_display.set_headers_visible (true);
4060 results_display.set_headers_clickable (false);
4061 results_display.set_reorderable (false);
4063 Gtk::ScrolledWindow list_scroller;
4066 Gtk::HBox dhbox; // the hbox for the image and text
4067 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4068 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4070 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4072 const string dead_directory = _session->session_directory().dead_path();
4075 %1 - number of files removed
4076 %2 - location of "dead"
4077 %3 - size of files affected
4078 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4081 const char* bprefix;
4082 double space_adjusted = 0;
4084 if (rep.space < 1000) {
4086 space_adjusted = rep.space;
4087 } else if (rep.space < 1000000) {
4088 bprefix = _("kilo");
4089 space_adjusted = floorf((float)rep.space / 1000.0);
4090 } else if (rep.space < 1000000 * 1000) {
4091 bprefix = _("mega");
4092 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4094 bprefix = _("giga");
4095 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4099 txt.set_markup (string_compose (P_("\
4100 The following file was deleted from %2,\n\
4101 releasing %3 %4bytes of disk space", "\
4102 The following %1 files were deleted from %2,\n\
4103 releasing %3 %4bytes of disk space", removed),
4104 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4106 txt.set_markup (string_compose (P_("\
4107 The following file was not in use and \n\
4108 has been moved to: %2\n\n\
4109 After a restart of %5\n\n\
4110 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4111 will release an additional %3 %4bytes of disk space.\n", "\
4112 The following %1 files were not in use and \n\
4113 have 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", removed),
4117 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4120 dhbox.pack_start (*dimage, true, false, 5);
4121 dhbox.pack_start (txt, true, false, 5);
4123 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4124 TreeModel::Row row = *(results_model->append());
4125 row[results_columns.visible_name] = *i;
4126 row[results_columns.fullpath] = *i;
4129 list_scroller.add (results_display);
4130 list_scroller.set_size_request (-1, 150);
4131 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4133 dvbox.pack_start (dhbox, true, false, 5);
4134 dvbox.pack_start (list_scroller, true, false, 5);
4135 ddhbox.pack_start (dvbox, true, false, 5);
4137 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4138 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4139 results.set_default_response (RESPONSE_CLOSE);
4140 results.set_position (Gtk::WIN_POS_MOUSE);
4142 results_display.show();
4143 list_scroller.show();
4150 //results.get_vbox()->show();
4151 results.set_resizable (false);
4158 ARDOUR_UI::cleanup ()
4160 if (_session == 0) {
4161 /* shouldn't happen: menu item is insensitive */
4166 MessageDialog checker (_("Are you sure you want to clean-up?"),
4168 Gtk::MESSAGE_QUESTION,
4171 checker.set_title (_("Clean-up"));
4173 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4174 ALL undo/redo information will be lost if you clean-up.\n\
4175 Clean-up will move all unused files to a \"dead\" location."));
4177 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4178 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4179 checker.set_default_response (RESPONSE_CANCEL);
4181 checker.set_name (_("CleanupDialog"));
4182 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4183 checker.set_position (Gtk::WIN_POS_MOUSE);
4185 switch (checker.run()) {
4186 case RESPONSE_ACCEPT:
4192 ARDOUR::CleanupReport rep;
4194 editor->prepare_for_cleanup ();
4196 /* do not allow flush until a session is reloaded */
4198 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4200 act->set_sensitive (false);
4203 if (_session->cleanup_sources (rep)) {
4204 editor->finish_cleanup ();
4208 editor->finish_cleanup ();
4211 display_cleanup_results (rep, _("Cleaned Files"), false);
4215 ARDOUR_UI::flush_trash ()
4217 if (_session == 0) {
4218 /* shouldn't happen: menu item is insensitive */
4222 ARDOUR::CleanupReport rep;
4224 if (_session->cleanup_trash_sources (rep)) {
4228 display_cleanup_results (rep, _("deleted file"), true);
4232 ARDOUR_UI::cleanup_peakfiles ()
4234 if (_session == 0) {
4235 /* shouldn't happen: menu item is insensitive */
4239 if (! _session->can_cleanup_peakfiles ()) {
4243 // get all region-views in this session
4245 TrackViewList empty;
4247 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4248 std::list<RegionView*> views = rs.by_layer();
4250 // remove displayed audio-region-views waveforms
4251 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4252 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4253 if (!arv) { continue ; }
4254 arv->delete_waves();
4257 // cleanup peak files:
4258 // - stop pending peakfile threads
4259 // - close peakfiles if any
4260 // - remove peak dir in session
4261 // - setup peakfiles (background thread)
4262 _session->cleanup_peakfiles ();
4264 // re-add waves to ARV
4265 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4266 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4267 if (!arv) { continue ; }
4268 arv->create_waves();
4272 PresentationInfo::order_t
4273 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4275 if (editor->get_selection().tracks.empty()) {
4276 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4279 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4282 we want the new routes to have their order keys set starting from
4283 the highest order key in the selection + 1 (if available).
4286 if (place == RouteDialogs::AfterSelection) {
4287 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4289 order_hint = rtav->route()->presentation_info().order();
4292 } else if (place == RouteDialogs::BeforeSelection) {
4293 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4295 order_hint = rtav->route()->presentation_info().order();
4297 } else if (place == RouteDialogs::First) {
4300 /* leave order_hint at max_order */
4307 ARDOUR_UI::start_duplicate_routes ()
4309 if (!duplicate_routes_dialog) {
4310 duplicate_routes_dialog = new DuplicateRouteDialog;
4313 if (duplicate_routes_dialog->restart (_session)) {
4317 duplicate_routes_dialog->present ();
4321 ARDOUR_UI::add_route ()
4323 if (!add_route_dialog.get (false)) {
4324 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4331 if (add_route_dialog->is_visible()) {
4332 /* we're already doing this */
4336 add_route_dialog->set_position (WIN_POS_MOUSE);
4337 add_route_dialog->present();
4341 ARDOUR_UI::add_route_dialog_response (int r)
4344 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4348 if (!AudioEngine::instance()->running ()) {
4350 case AddRouteDialog::Add:
4351 case AddRouteDialog::AddAndClose:
4356 add_route_dialog->ArdourDialog::on_response (r);
4357 ARDOUR_UI_UTILS::engine_is_running ();
4364 case AddRouteDialog::Add:
4365 add_route_dialog->reset_name_edited ();
4367 case AddRouteDialog::AddAndClose:
4368 add_route_dialog->ArdourDialog::on_response (r);
4371 add_route_dialog->ArdourDialog::on_response (r);
4375 std::string template_path = add_route_dialog->get_template_path();
4376 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4377 meta_route_setup (template_path.substr (11));
4381 if ((count = add_route_dialog->count()) <= 0) {
4385 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4386 const string name_template = add_route_dialog->name_template ();
4387 DisplaySuspender ds;
4389 if (!template_path.empty ()) {
4390 if (add_route_dialog->name_template_is_default ()) {
4391 _session->new_route_from_template (count, order, template_path, string ());
4393 _session->new_route_from_template (count, order, template_path, name_template);
4398 ChanCount input_chan= add_route_dialog->channels ();
4399 ChanCount output_chan;
4400 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4401 RouteGroup* route_group = add_route_dialog->route_group ();
4402 AutoConnectOption oac = Config->get_output_auto_connect();
4403 bool strict_io = add_route_dialog->use_strict_io ();
4405 if (oac & AutoConnectMaster) {
4406 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4407 output_chan.set (DataType::MIDI, 0);
4409 output_chan = input_chan;
4412 /* XXX do something with name template */
4414 Session::ProcessorChangeBlocker pcb (_session);
4416 switch (add_route_dialog->type_wanted()) {
4417 case AddRouteDialog::AudioTrack:
4418 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);
4420 case AddRouteDialog::MidiTrack:
4421 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4423 case AddRouteDialog::MixedTrack:
4424 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4426 case AddRouteDialog::AudioBus:
4427 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4429 case AddRouteDialog::MidiBus:
4430 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4432 case AddRouteDialog::VCAMaster:
4433 _session->vca_manager().create_vca (count, name_template);
4435 case AddRouteDialog::FoldbackBus:
4436 session_add_foldback_bus (count, name_template);
4442 ARDOUR_UI::stop_video_server (bool ask_confirm)
4444 if (!video_server_process && ask_confirm) {
4445 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4447 if (video_server_process) {
4449 ArdourDialog confirm (_("Stop Video-Server"), true);
4450 Label m (_("Do you really want to stop the Video Server?"));
4451 confirm.get_vbox()->pack_start (m, true, true);
4452 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4453 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4454 confirm.show_all ();
4455 if (confirm.run() == RESPONSE_CANCEL) {
4459 delete video_server_process;
4460 video_server_process =0;
4465 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4467 ARDOUR_UI::start_video_server( float_window, true);
4471 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4477 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4478 if (video_server_process) {
4479 popup_error(_("The Video Server is already started."));
4481 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4487 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4489 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4491 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4493 video_server_dialog->set_transient_for (*float_window);
4496 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4497 video_server_dialog->hide();
4499 ResponseType r = (ResponseType) video_server_dialog->run ();
4500 video_server_dialog->hide();
4501 if (r != RESPONSE_ACCEPT) { return false; }
4502 if (video_server_dialog->show_again()) {
4503 Config->set_show_video_server_dialog(false);
4507 std::string icsd_exec = video_server_dialog->get_exec_path();
4508 std::string icsd_docroot = video_server_dialog->get_docroot();
4509 #ifndef PLATFORM_WINDOWS
4510 if (icsd_docroot.empty()) {
4511 icsd_docroot = VideoUtils::video_get_docroot (Config);
4516 #ifdef PLATFORM_WINDOWS
4517 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4518 /* OK, allow all drive letters */
4521 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4522 warning << _("Specified docroot is not an existing directory.") << endmsg;
4525 #ifndef PLATFORM_WINDOWS
4526 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4527 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4528 warning << _("Given Video Server is not an executable file.") << endmsg;
4532 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4533 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4534 warning << _("Given Video Server is not an executable file.") << endmsg;
4540 argp=(char**) calloc(9,sizeof(char*));
4541 argp[0] = strdup(icsd_exec.c_str());
4542 argp[1] = strdup("-P");
4543 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4544 argp[3] = strdup("-p");
4545 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4546 argp[5] = strdup("-C");
4547 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4548 argp[7] = strdup(icsd_docroot.c_str());
4550 stop_video_server();
4552 #ifdef PLATFORM_WINDOWS
4553 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4554 /* OK, allow all drive letters */
4557 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4558 Config->set_video_advanced_setup(false);
4560 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4561 Config->set_video_server_url(url_str);
4562 Config->set_video_server_docroot(icsd_docroot);
4563 Config->set_video_advanced_setup(true);
4566 if (video_server_process) {
4567 delete video_server_process;
4570 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4571 if (video_server_process->start()) {
4572 warning << _("Cannot launch the video-server") << endmsg;
4575 int timeout = 120; // 6 sec
4576 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4577 Glib::usleep (50000);
4579 if (--timeout <= 0 || !video_server_process->is_running()) break;
4582 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4584 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4585 delete video_server_process;
4586 video_server_process = 0;
4594 ARDOUR_UI::add_video (Gtk::Window* float_window)
4600 if (!start_video_server(float_window, false)) {
4601 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4606 add_video_dialog->set_transient_for (*float_window);
4609 if (add_video_dialog->is_visible()) {
4610 /* we're already doing this */
4614 ResponseType r = (ResponseType) add_video_dialog->run ();
4615 add_video_dialog->hide();
4616 if (r != RESPONSE_ACCEPT) { return; }
4618 bool local_file, orig_local_file;
4619 std::string path = add_video_dialog->file_name(local_file);
4621 std::string orig_path = path;
4622 orig_local_file = local_file;
4624 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4626 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4627 warning << string_compose(_("could not open %1"), path) << endmsg;
4630 if (!local_file && path.length() == 0) {
4631 warning << _("no video-file selected") << endmsg;
4635 std::string audio_from_video;
4636 bool detect_ltc = false;
4638 switch (add_video_dialog->import_option()) {
4639 case VTL_IMPORT_TRANSCODE:
4641 TranscodeVideoDialog *transcode_video_dialog;
4642 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4643 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4644 transcode_video_dialog->hide();
4645 if (r != RESPONSE_ACCEPT) {
4646 delete transcode_video_dialog;
4650 audio_from_video = transcode_video_dialog->get_audiofile();
4652 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4655 else if (!audio_from_video.empty()) {
4656 editor->embed_audio_from_video(
4658 video_timeline->get_offset(),
4659 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4662 switch (transcode_video_dialog->import_option()) {
4663 case VTL_IMPORT_TRANSCODED:
4664 path = transcode_video_dialog->get_filename();
4667 case VTL_IMPORT_REFERENCE:
4670 delete transcode_video_dialog;
4673 delete transcode_video_dialog;
4677 case VTL_IMPORT_NONE:
4681 /* strip _session->session_directory().video_path() from video file if possible */
4682 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4683 path=path.substr(_session->session_directory().video_path().size());
4684 if (path.at(0) == G_DIR_SEPARATOR) {
4685 path=path.substr(1);
4689 video_timeline->set_update_session_fps(auto_set_session_fps);
4691 if (video_timeline->video_file_info(path, local_file)) {
4692 XMLNode* node = new XMLNode(X_("Videotimeline"));
4693 node->set_property (X_("Filename"), path);
4694 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4695 node->set_property (X_("LocalFile"), local_file);
4696 if (orig_local_file) {
4697 node->set_property (X_("OriginalVideoFile"), orig_path);
4699 node->remove_property (X_("OriginalVideoFile"));
4701 _session->add_extra_xml (*node);
4702 _session->set_dirty ();
4704 if (!audio_from_video.empty() && detect_ltc) {
4705 std::vector<LTCFileReader::LTCMap> ltc_seq;
4708 /* TODO ask user about TV standard (LTC alignment if any) */
4709 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4710 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4712 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4714 /* TODO seek near end of file, and read LTC until end.
4715 * if it fails to find any LTC samples, scan complete file
4717 * calculate drift of LTC compared to video-duration,
4718 * ask user for reference (timecode from start/mid/end)
4721 // LTCFileReader will have written error messages
4724 ::g_unlink(audio_from_video.c_str());
4726 if (ltc_seq.size() == 0) {
4727 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4729 /* the very first TC in the file is somteimes not aligned properly */
4730 int i = ltc_seq.size() -1;
4731 ARDOUR::sampleoffset_t video_start_offset =
4732 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4733 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4734 video_timeline->set_offset(video_start_offset);
4738 _session->maybe_update_session_range(
4739 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4740 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4743 if (add_video_dialog->launch_xjadeo() && local_file) {
4744 editor->set_xjadeo_sensitive(true);
4745 editor->toggle_xjadeo_proc(1);
4747 editor->toggle_xjadeo_proc(0);
4749 editor->toggle_ruler_video(true);
4754 ARDOUR_UI::remove_video ()
4756 video_timeline->close_session();
4757 editor->toggle_ruler_video(false);
4760 video_timeline->set_offset_locked(false);
4761 video_timeline->set_offset(0);
4763 /* delete session state */
4764 XMLNode* node = new XMLNode(X_("Videotimeline"));
4765 _session->add_extra_xml(*node);
4766 node = new XMLNode(X_("Videomonitor"));
4767 _session->add_extra_xml(*node);
4768 node = new XMLNode(X_("Videoexport"));
4769 _session->add_extra_xml(*node);
4770 stop_video_server();
4774 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4776 if (localcacheonly) {
4777 video_timeline->vmon_update();
4779 video_timeline->flush_cache();
4781 editor->queue_visual_videotimeline_update();
4785 ARDOUR_UI::export_video (bool range)
4787 if (ARDOUR::Config->get_show_video_export_info()) {
4788 ExportVideoInfobox infobox (_session);
4789 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4790 if (infobox.show_again()) {
4791 ARDOUR::Config->set_show_video_export_info(false);
4794 case GTK_RESPONSE_YES:
4795 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4801 export_video_dialog->set_session (_session);
4802 export_video_dialog->apply_state(editor->get_selection().time, range);
4803 export_video_dialog->run ();
4804 export_video_dialog->hide ();
4808 ARDOUR_UI::preferences_settings () const
4813 node = _session->instant_xml(X_("Preferences"));
4815 node = Config->instant_xml(X_("Preferences"));
4819 node = new XMLNode (X_("Preferences"));
4826 ARDOUR_UI::mixer_settings () const
4831 node = _session->instant_xml(X_("Mixer"));
4833 node = Config->instant_xml(X_("Mixer"));
4837 node = new XMLNode (X_("Mixer"));
4844 ARDOUR_UI::main_window_settings () const
4849 node = _session->instant_xml(X_("Main"));
4851 node = Config->instant_xml(X_("Main"));
4855 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4856 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4861 node = new XMLNode (X_("Main"));
4868 ARDOUR_UI::editor_settings () const
4873 node = _session->instant_xml(X_("Editor"));
4875 node = Config->instant_xml(X_("Editor"));
4879 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4880 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4885 node = new XMLNode (X_("Editor"));
4892 ARDOUR_UI::keyboard_settings () const
4896 node = Config->extra_xml(X_("Keyboard"));
4899 node = new XMLNode (X_("Keyboard"));
4906 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4909 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4910 _session->locations()->add (location);
4915 ARDOUR_UI::halt_on_xrun_message ()
4917 cerr << "HALT on xrun\n";
4918 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4923 ARDOUR_UI::xrun_handler (samplepos_t where)
4929 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4931 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4932 create_xrun_marker(where);
4935 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4936 halt_on_xrun_message ();
4941 ARDOUR_UI::disk_overrun_handler ()
4943 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4945 if (!have_disk_speed_dialog_displayed) {
4946 have_disk_speed_dialog_displayed = true;
4947 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4948 The disk system on your computer\n\
4949 was not able to keep up with %1.\n\
4951 Specifically, it failed to write data to disk\n\
4952 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4953 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4959 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4960 static MessageDialog *scan_dlg = NULL;
4961 static ProgressBar *scan_pbar = NULL;
4962 static HBox *scan_tbox = NULL;
4963 static Gtk::Button *scan_timeout_button;
4966 ARDOUR_UI::cancel_plugin_scan ()
4968 PluginManager::instance().cancel_plugin_scan();
4972 ARDOUR_UI::cancel_plugin_timeout ()
4974 PluginManager::instance().cancel_plugin_timeout();
4975 scan_timeout_button->set_sensitive (false);
4979 ARDOUR_UI::plugin_scan_timeout (int timeout)
4981 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4985 scan_pbar->set_sensitive (false);
4986 scan_timeout_button->set_sensitive (true);
4987 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4990 scan_pbar->set_sensitive (false);
4991 scan_timeout_button->set_sensitive (false);
4997 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4999 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5003 const bool cancelled = PluginManager::instance().cancelled();
5004 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5005 if (cancelled && scan_dlg->is_mapped()) {
5010 if (cancelled || !can_cancel) {
5015 static Gtk::Button *cancel_button;
5017 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5018 VBox* vbox = scan_dlg->get_vbox();
5019 vbox->set_size_request(400,-1);
5020 scan_dlg->set_title (_("Scanning for plugins"));
5022 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5023 cancel_button->set_name ("EditorGTKButton");
5024 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5025 cancel_button->show();
5027 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5029 scan_tbox = manage( new HBox() );
5031 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5032 scan_timeout_button->set_name ("EditorGTKButton");
5033 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5034 scan_timeout_button->show();
5036 scan_pbar = manage(new ProgressBar());
5037 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5038 scan_pbar->set_text(_("Scan Timeout"));
5041 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5042 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5044 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5047 assert(scan_dlg && scan_tbox && cancel_button);
5049 if (type == X_("closeme")) {
5053 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5056 if (!can_cancel || !cancelled) {
5057 scan_timeout_button->set_sensitive(false);
5059 cancel_button->set_sensitive(can_cancel && !cancelled);
5065 ARDOUR_UI::gui_idle_handler ()
5068 /* due to idle calls, gtk_events_pending() may always return true */
5069 while (gtk_events_pending() && --timeout) {
5070 gtk_main_iteration ();
5075 ARDOUR_UI::disk_underrun_handler ()
5077 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5079 if (!have_disk_speed_dialog_displayed) {
5080 have_disk_speed_dialog_displayed = true;
5081 MessageDialog* msg = new MessageDialog (
5082 _main_window, string_compose (_("The disk system on your computer\n\
5083 was not able to keep up with %1.\n\
5085 Specifically, it failed to read data from disk\n\
5086 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5087 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5093 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5095 have_disk_speed_dialog_displayed = false;
5100 ARDOUR_UI::session_dialog (std::string msg)
5102 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5106 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5113 ARDOUR_UI::pending_state_dialog ()
5115 HBox* hbox = manage (new HBox());
5116 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5117 ArdourDialog dialog (_("Crash Recovery"), true);
5118 Label message (string_compose (_("\
5119 This session appears to have been in the\n\
5120 middle of recording when %1 or\n\
5121 the computer was shutdown.\n\
5123 %1 can recover any captured audio for\n\
5124 you, or it can ignore it. Please decide\n\
5125 what you would like to do.\n"), PROGRAM_NAME));
5126 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5127 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5128 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5129 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5130 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5131 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5132 dialog.set_default_response (RESPONSE_ACCEPT);
5133 dialog.set_position (WIN_POS_CENTER);
5138 switch (dialog.run ()) {
5139 case RESPONSE_ACCEPT:
5147 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5149 HBox* hbox = new HBox();
5150 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5151 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5152 Label message (string_compose (_("\
5153 This session was created with a sample rate of %1 Hz, but\n\
5154 %2 is currently running at %3 Hz. If you load this session,\n\
5155 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5157 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5158 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5159 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5160 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5161 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5162 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5163 dialog.set_default_response (RESPONSE_ACCEPT);
5164 dialog.set_position (WIN_POS_CENTER);
5169 switch (dialog.run()) {
5170 case RESPONSE_ACCEPT:
5180 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5182 MessageDialog msg (string_compose (_("\
5183 This session was created with a sample rate of %1 Hz, but\n\
5184 %2 is currently running at %3 Hz.\n\
5185 Audio will be recorded and played at the wrong sample rate.\n\
5186 Re-Configure the Audio Engine in\n\
5187 Menu > Window > Audio/Midi Setup"),
5188 desired, PROGRAM_NAME, actual),
5190 Gtk::MESSAGE_WARNING);
5195 ARDOUR_UI::use_config ()
5197 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5199 set_transport_controllable_state (*node);
5204 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5206 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5208 primary_clock->set (pos);
5210 case DeltaEditPoint:
5211 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5213 case DeltaOriginMarker:
5215 Location* loc = _session->locations()->clock_origin_location ();
5216 primary_clock->set (pos, false, loc ? loc->start() : 0);
5221 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5223 secondary_clock->set (pos);
5225 case DeltaEditPoint:
5226 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5228 case DeltaOriginMarker:
5230 Location* loc = _session->locations()->clock_origin_location ();
5231 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5236 if (big_clock_window) {
5237 big_clock->set (pos);
5239 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5244 ARDOUR_UI::record_state_changed ()
5246 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5249 /* why bother - the clock isn't visible */
5253 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5255 if (big_clock_window) {
5256 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5257 big_clock->set_active (true);
5259 big_clock->set_active (false);
5266 ARDOUR_UI::first_idle ()
5269 _session->allow_auto_play (true);
5273 editor->first_idle();
5276 /* in 1 second, hide the splash screen
5278 * Consider hiding it *now*. If a user opens opens a dialog
5279 * during that one second while the splash is still visible,
5280 * the dialog will push-back the splash.
5281 * Closing the dialog later will pop it back.
5283 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5285 Keyboard::set_can_save_keybindings (true);
5290 ARDOUR_UI::store_clock_modes ()
5292 XMLNode* node = new XMLNode(X_("ClockModes"));
5294 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5295 XMLNode* child = new XMLNode (X_("Clock"));
5297 child->set_property (X_("name"), (*x)->name());
5298 child->set_property (X_("mode"), (*x)->mode());
5299 child->set_property (X_("on"), (*x)->on());
5301 node->add_child_nocopy (*child);
5304 _session->add_extra_xml (*node);
5305 _session->set_dirty ();
5309 ARDOUR_UI::setup_profile ()
5311 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5312 Profile->set_small_screen ();
5315 if (g_getenv ("TRX")) {
5316 Profile->set_trx ();
5319 if (g_getenv ("MIXBUS")) {
5320 Profile->set_mixbus ();
5325 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5327 MissingFileDialog dialog (s, str, type);
5332 int result = dialog.run ();
5339 return 1; // quit entire session load
5342 result = dialog.get_action ();
5348 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5350 AmbiguousFileDialog dialog (file, hits);
5357 return dialog.get_which ();
5360 /** Allocate our thread-local buffers */
5362 ARDOUR_UI::get_process_buffers ()
5364 _process_thread->get_buffers ();
5367 /** Drop our thread-local buffers */
5369 ARDOUR_UI::drop_process_buffers ()
5371 _process_thread->drop_buffers ();
5375 ARDOUR_UI::feedback_detected ()
5377 _feedback_exists = true;
5381 ARDOUR_UI::successful_graph_sort ()
5383 _feedback_exists = false;
5387 ARDOUR_UI::midi_panic ()
5390 _session->midi_panic();
5395 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5397 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5398 const char* end_big = "</span>";
5399 const char* start_mono = "<tt>";
5400 const char* end_mono = "</tt>";
5402 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5403 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5404 "From now on, use the backup copy with older versions of %3"),
5405 xml_path, backup_path, PROGRAM_NAME,
5407 start_mono, end_mono), true);
5413 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5415 using namespace Menu_Helpers;
5417 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5418 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5419 i->set_active (editor_meter->meter_type () == type);
5423 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5425 using namespace Gtk::Menu_Helpers;
5427 Gtk::Menu* m = manage (new Menu);
5428 MenuList& items = m->items ();
5430 RadioMenuItem::Group group;
5432 _suspend_editor_meter_callbacks = true;
5433 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5434 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5435 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5436 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5437 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5438 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5439 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5440 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5441 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5442 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5443 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5445 m->popup (ev->button, ev->time);
5446 _suspend_editor_meter_callbacks = false;
5450 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5452 if (ev->button == 3 && editor_meter) {
5453 popup_editor_meter_menu (ev);
5460 ARDOUR_UI::reset_peak_display ()
5462 if (!_session || !_session->master_out() || !editor_meter) return;
5463 editor_meter->clear_meters();
5464 editor_meter_max_peak = -INFINITY;
5465 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5469 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5471 if (!_session || !_session->master_out()) return;
5472 if (group == _session->master_out()->route_group()) {
5473 reset_peak_display ();
5478 ARDOUR_UI::reset_route_peak_display (Route* route)
5480 if (!_session || !_session->master_out()) return;
5481 if (_session->master_out().get() == route) {
5482 reset_peak_display ();
5487 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5489 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5490 audio_midi_setup->set_position (WIN_POS_CENTER);
5492 if (desired_sample_rate != 0) {
5493 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5494 audio_midi_setup->try_autostart ();
5495 if (ARDOUR::AudioEngine::instance()->running()) {
5502 int response = audio_midi_setup->run();
5504 case Gtk::RESPONSE_DELETE_EVENT:
5505 // after latency callibration engine may run,
5506 // Running() signal was emitted, but dialog will not
5507 // have emitted a response. The user needs to close
5508 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5509 if (!AudioEngine::instance()->running()) {
5514 if (!AudioEngine::instance()->running()) {
5517 audio_midi_setup->hide ();
5525 ARDOUR_UI::transport_numpad_timeout ()
5527 _numpad_locate_happening = false;
5528 if (_numpad_timeout_connection.connected() )
5529 _numpad_timeout_connection.disconnect();
5534 ARDOUR_UI::transport_numpad_decimal ()
5536 _numpad_timeout_connection.disconnect();
5538 if (_numpad_locate_happening) {
5539 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5540 _numpad_locate_happening = false;
5542 _pending_locate_num = 0;
5543 _numpad_locate_happening = true;
5544 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5549 ARDOUR_UI::transport_numpad_event (int num)
5551 if ( _numpad_locate_happening ) {
5552 _pending_locate_num = _pending_locate_num*10 + num;
5555 case 0: toggle_roll(false, false); break;
5556 case 1: transport_rewind(1); break;
5557 case 2: transport_forward(1); break;
5558 case 3: transport_record(true); break;
5559 case 4: toggle_session_auto_loop(); break;
5560 case 5: transport_record(false); toggle_session_auto_loop(); break;
5561 case 6: toggle_punch(); break;
5562 case 7: toggle_click(); break;
5563 case 8: toggle_auto_return(); break;
5564 case 9: toggle_follow_edits(); break;
5570 ARDOUR_UI::set_flat_buttons ()
5572 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5576 ARDOUR_UI::audioengine_became_silent ()
5578 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5580 Gtk::MESSAGE_WARNING,
5584 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5586 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5587 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5588 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5589 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5590 Gtk::HBox pay_button_box;
5591 Gtk::HBox subscribe_button_box;
5593 pay_button_box.pack_start (pay_button, true, false);
5594 subscribe_button_box.pack_start (subscribe_button, true, false);
5596 bool (*openuri)(const char*) = PBD::open_uri; /* this forces selection of the const char* variant of PBD::open_uri(), which we need to avoid ambiguity below */
5598 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5599 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5601 msg.get_vbox()->pack_start (pay_label);
5602 msg.get_vbox()->pack_start (pay_button_box);
5603 msg.get_vbox()->pack_start (subscribe_label);
5604 msg.get_vbox()->pack_start (subscribe_button_box);
5606 msg.get_vbox()->show_all ();
5608 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5609 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5610 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5615 case Gtk::RESPONSE_YES:
5616 AudioEngine::instance()->reset_silence_countdown ();
5619 case Gtk::RESPONSE_NO:
5621 save_state_canfail ("");
5625 case Gtk::RESPONSE_CANCEL:
5627 /* don't reset, save session and exit */
5633 ARDOUR_UI::hide_application ()
5635 Application::instance ()-> hide ();
5639 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5641 /* icons, titles, WM stuff */
5643 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5645 if (window_icons.empty()) {
5646 Glib::RefPtr<Gdk::Pixbuf> icon;
5647 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5648 window_icons.push_back (icon);
5650 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5651 window_icons.push_back (icon);
5653 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5654 window_icons.push_back (icon);
5656 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5657 window_icons.push_back (icon);
5661 if (!window_icons.empty()) {
5662 window.set_default_icon_list (window_icons);
5665 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5667 if (!name.empty()) {
5671 window.set_title (title.get_string());
5672 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5674 window.set_flags (CAN_FOCUS);
5675 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5677 /* This is a hack to ensure that GTK-accelerators continue to
5678 * work. Once we switch over to entirely native bindings, this will be
5679 * unnecessary and should be removed
5681 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5683 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5684 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5685 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5686 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5690 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5692 Gtkmm2ext::Bindings* bindings = 0;
5693 Gtk::Window* window = 0;
5695 /* until we get ardour bindings working, we are not handling key
5699 if (ev->type != GDK_KEY_PRESS) {
5703 if (event_window == &_main_window) {
5705 window = event_window;
5707 /* find current tab contents */
5709 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5711 /* see if it uses the ardour binding system */
5714 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5717 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5721 window = event_window;
5723 /* see if window uses ardour binding system */
5725 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5728 /* An empty binding set is treated as if it doesn't exist */
5730 if (bindings && bindings->empty()) {
5734 return key_press_focus_accelerator_handler (*window, ev, bindings);
5737 static Gtkmm2ext::Bindings*
5738 get_bindings_from_widget_heirarchy (GtkWidget** w)
5743 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5746 *w = gtk_widget_get_parent (*w);
5749 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5753 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5755 GtkWindow* win = window.gobj();
5756 GtkWidget* focus = gtk_window_get_focus (win);
5757 GtkWidget* binding_widget = focus;
5758 bool special_handling_of_unmodified_accelerators = false;
5759 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5763 /* some widget has keyboard focus */
5765 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5767 /* A particular kind of focusable widget currently has keyboard
5768 * focus. All unmodified key events should go to that widget
5769 * first and not be used as an accelerator by default
5772 special_handling_of_unmodified_accelerators = true;
5776 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5777 if (focus_bindings) {
5778 bindings = focus_bindings;
5779 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5784 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
5787 Gtkmm2ext::show_gdk_event_state (ev->state),
5788 special_handling_of_unmodified_accelerators,
5789 Keyboard::some_magic_widget_has_focus(),
5791 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5792 ((ev->state & mask) ? "yes" : "no"),
5793 window.get_title()));
5795 /* This exists to allow us to override the way GTK handles
5796 key events. The normal sequence is:
5798 a) event is delivered to a GtkWindow
5799 b) accelerators/mnemonics are activated
5800 c) if (b) didn't handle the event, propagate to
5801 the focus widget and/or focus chain
5803 The problem with this is that if the accelerators include
5804 keys without modifiers, such as the space bar or the
5805 letter "e", then pressing the key while typing into
5806 a text entry widget results in the accelerator being
5807 activated, instead of the desired letter appearing
5810 There is no good way of fixing this, but this
5811 represents a compromise. The idea is that
5812 key events involving modifiers (not Shift)
5813 get routed into the activation pathway first, then
5814 get propagated to the focus widget if necessary.
5816 If the key event doesn't involve modifiers,
5817 we deliver to the focus widget first, thus allowing
5818 it to get "normal text" without interference
5821 Of course, this can also be problematic: if there
5822 is a widget with focus, then it will swallow
5823 all "normal text" accelerators.
5827 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5829 /* no special handling or there are modifiers in effect: accelerate first */
5831 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5832 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5833 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5835 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5836 KeyboardKey k (ev->state, ev->keyval);
5840 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5842 if (bindings->activate (k, Bindings::Press)) {
5843 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5847 if (binding_widget) {
5848 binding_widget = gtk_widget_get_parent (binding_widget);
5849 if (binding_widget) {
5850 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5859 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5861 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5862 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5866 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5868 if (gtk_window_propagate_key_event (win, ev)) {
5869 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5875 /* no modifiers, propagate first */
5877 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5879 if (gtk_window_propagate_key_event (win, ev)) {
5880 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5884 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5885 KeyboardKey k (ev->state, ev->keyval);
5889 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5892 if (bindings->activate (k, Bindings::Press)) {
5893 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5897 if (binding_widget) {
5898 binding_widget = gtk_widget_get_parent (binding_widget);
5899 if (binding_widget) {
5900 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5909 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5911 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5912 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5917 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5922 ARDOUR_UI::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);
5982 ARDOUR_UI::monitor_dim_all ()
5984 boost::shared_ptr<Route> mon = _session->monitor_out ();
5988 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5990 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
5991 assert (act); Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
5992 assert (tact); _monitor->set_dim_all (tact->get_active());
5996 ARDOUR_UI::monitor_cut_all ()
5998 boost::shared_ptr<Route> mon = _session->monitor_out ();
6002 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6004 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
6005 assert (act); Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
6006 assert (tact); _monitor->set_cut_all (tact->get_active());
6010 ARDOUR_UI::monitor_mono ()
6012 boost::shared_ptr<Route> mon = _session->monitor_out ();
6016 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6018 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
6019 assert (act); Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
6020 assert (tact);_monitor->set_mono (tact->get_active());