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 , global_actions (X_("global"))
283 , ignore_dual_punch (false)
284 , main_window_visibility (0)
289 , _mixer_on_top (false)
290 , _initial_verbose_plugin_scan (false)
291 , first_time_engine_run (true)
292 , secondary_clock_spacer (0)
293 , auto_input_button (ArdourButton::led_default_elements)
295 , auto_return_button (ArdourButton::led_default_elements)
296 , follow_edits_button (ArdourButton::led_default_elements)
297 , auditioning_alert_button (_("Audition"))
298 , solo_alert_button (_("Solo"))
299 , feedback_alert_button (_("Feedback"))
300 , error_alert_button ( ArdourButton::just_led_default_elements )
301 , editor_meter_peak_display()
303 , _suspend_editor_meter_callbacks (false)
304 , _numpad_locate_happening (false)
305 , _session_is_new (false)
306 , last_key_press_time (0)
310 , rc_option_editor (0)
311 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
312 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
313 , about (X_("about"), _("About"))
314 , location_ui (X_("locations"), S_("Ranges|Locations"))
315 , route_params (X_("inspector"), _("Tracks and Busses"))
316 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
317 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
318 , lua_script_window (X_("script-manager"), _("Script Manager"))
319 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
320 , plugin_dsp_load_window (X_("plugin-dsp-load"), _("Plugin DSP Load"))
321 , transport_masters_window (X_("transport-masters"), _("Transport Masters"))
322 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
323 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
324 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
325 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
326 , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this))
327 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
328 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
329 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
330 , video_server_process (0)
332 , have_configure_timeout (false)
333 , last_configure_time (0)
335 , have_disk_speed_dialog_displayed (false)
336 , _status_bar_visibility (X_("status-bar"))
337 , _feedback_exists (false)
338 , _log_not_acknowledged (LogLevelNone)
339 , duplicate_routes_dialog (0)
340 , editor_visibility_button (S_("Window|Editor"))
341 , mixer_visibility_button (S_("Window|Mixer"))
342 , prefs_visibility_button (S_("Window|Preferences"))
344 Gtkmm2ext::init (localedir);
346 UIConfiguration::instance().post_gui_init ();
348 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
350 /* "touch" the been-here-before path now that config has been migrated */
351 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
353 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
355 /* configuration was modified, exit immediately */
360 if (string (VERSIONSTRING).find (".pre") != string::npos) {
361 /* check this is not being run from ./ardev etc. */
362 if (!running_from_source_tree ()) {
363 pre_release_dialog ();
367 if (theArdourUI == 0) {
371 /* track main window visibility */
373 main_window_visibility = new VisibilityTracker (_main_window);
375 /* stop libxml from spewing to stdout/stderr */
377 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
378 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
380 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
381 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
382 UIConfiguration::instance().map_parameters (pc);
384 transport_ctrl.setup (this);
386 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
387 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
389 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
391 /* handle dialog requests */
393 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
395 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
397 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
399 /* handle Audio/MIDI setup when session requires it */
401 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
403 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
405 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
407 /* handle sr mismatch with a dialog - cross-thread from engine */
408 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
410 /* handle requests to quit (coming from JACK session) */
412 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
414 /* tell the user about feedback */
416 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
417 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
419 /* handle requests to deal with missing files */
421 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
423 /* and ambiguous files */
425 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
427 /* also plugin scan messages */
428 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
429 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
431 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
433 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
436 /* lets get this party started */
438 setup_gtk_ardour_enums ();
441 SessionEvent::create_per_thread_pool ("GUI", 4096);
443 /* we like keyboards */
445 keyboard = new ArdourKeyboard(*this);
447 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
449 keyboard->set_state (*node, Stateful::loading_state_version);
452 UIConfiguration::instance().reset_dpi ();
454 TimeAxisViewItem::set_constant_heights ();
456 /* Set this up so that our window proxies can register actions */
458 ActionManager::init ();
460 /* The following must happen after ARDOUR::init() so that Config is set up */
462 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
465 key_editor.set_state (*ui_xml, 0);
466 session_option_editor.set_state (*ui_xml, 0);
467 speaker_config_window.set_state (*ui_xml, 0);
468 about.set_state (*ui_xml, 0);
469 add_route_dialog.set_state (*ui_xml, 0);
470 add_video_dialog.set_state (*ui_xml, 0);
471 route_params.set_state (*ui_xml, 0);
472 bundle_manager.set_state (*ui_xml, 0);
473 location_ui.set_state (*ui_xml, 0);
474 big_clock_window.set_state (*ui_xml, 0);
475 big_transport_window.set_state (*ui_xml, 0);
476 audio_port_matrix.set_state (*ui_xml, 0);
477 midi_port_matrix.set_state (*ui_xml, 0);
478 export_video_dialog.set_state (*ui_xml, 0);
479 lua_script_window.set_state (*ui_xml, 0);
480 idleometer.set_state (*ui_xml, 0);
481 plugin_dsp_load_window.set_state (*ui_xml, 0);
482 transport_masters_window.set_state (*ui_xml, 0);
485 /* Separate windows */
487 WM::Manager::instance().register_window (&key_editor);
488 WM::Manager::instance().register_window (&session_option_editor);
489 WM::Manager::instance().register_window (&speaker_config_window);
490 WM::Manager::instance().register_window (&about);
491 WM::Manager::instance().register_window (&add_route_dialog);
492 WM::Manager::instance().register_window (&add_video_dialog);
493 WM::Manager::instance().register_window (&route_params);
494 WM::Manager::instance().register_window (&audio_midi_setup);
495 WM::Manager::instance().register_window (&export_video_dialog);
496 WM::Manager::instance().register_window (&lua_script_window);
497 WM::Manager::instance().register_window (&bundle_manager);
498 WM::Manager::instance().register_window (&location_ui);
499 WM::Manager::instance().register_window (&big_clock_window);
500 WM::Manager::instance().register_window (&big_transport_window);
501 WM::Manager::instance().register_window (&audio_port_matrix);
502 WM::Manager::instance().register_window (&midi_port_matrix);
503 WM::Manager::instance().register_window (&idleometer);
504 WM::Manager::instance().register_window (&plugin_dsp_load_window);
505 WM::Manager::instance().register_window (&transport_masters_window);
507 /* do not retain position for add route dialog */
508 add_route_dialog.set_state_mask (WindowProxy::Size);
510 /* Trigger setting up the color scheme and loading the GTK RC file */
512 UIConfiguration::instance().load_rc_file (false);
514 _process_thread = new ProcessThread ();
515 _process_thread->init ();
517 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
523 ARDOUR_UI::pre_release_dialog ()
525 ArdourDialog d (_("Pre-Release Warning"), true, false);
526 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
528 Label* label = manage (new Label);
529 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
530 There are still several issues and bugs to be worked on,\n\
531 as well as general workflow improvements, before this can be considered\n\
532 release software. So, a few guidelines:\n\
534 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
535 though it may be so, depending on your workflow.\n\
536 2) Please wait for a helpful writeup of new features.\n\
537 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
538 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
539 making sure to note the product version number as 6.0-pre.\n\
540 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
541 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
542 can get there directly from within the program via the Help->Chat menu option.\n\
544 Full information on all the above can be found on the support page at\n\
546 http://ardour.org/support\n\
547 "), PROGRAM_NAME, VERSIONSTRING));
549 d.get_vbox()->set_border_width (12);
550 d.get_vbox()->pack_start (*label, false, false, 12);
551 d.get_vbox()->show_all ();
556 GlobalPortMatrixWindow*
557 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
562 return new GlobalPortMatrixWindow (_session, type);
566 ARDOUR_UI::attach_to_engine ()
568 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
569 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
573 ARDOUR_UI::engine_stopped ()
575 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
576 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
577 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
578 update_sample_rate (0);
583 ARDOUR_UI::engine_running ()
585 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
586 if (first_time_engine_run) {
588 first_time_engine_run = false;
592 _session->reset_xrun_count ();
594 update_disk_space ();
596 update_sample_rate (AudioEngine::instance()->sample_rate());
597 update_timecode_format ();
598 update_peak_thread_work ();
599 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
600 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
604 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
606 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
607 /* we can't rely on the original string continuing to exist when we are called
608 again in the GUI thread, so make a copy and note that we need to
611 char *copy = strdup (reason);
612 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
616 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
617 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
619 update_sample_rate (0);
623 /* if the reason is a non-empty string, it means that the backend was shutdown
624 rather than just Ardour.
627 if (strlen (reason)) {
628 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
630 msgstr = string_compose (_("\
631 The audio backend has either been shutdown or it\n\
632 disconnected %1 because %1\n\
633 was not fast enough. Try to restart\n\
634 the audio backend and save the session."), PROGRAM_NAME);
637 MessageDialog msg (_main_window, msgstr);
638 pop_back_splash (msg);
642 free (const_cast<char*> (reason));
647 ARDOUR_UI::post_engine ()
649 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
651 #ifdef AUDIOUNIT_SUPPORT
653 if (AUPluginInfo::au_get_crashlog(au_msg)) {
654 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
655 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
656 info << au_msg << endmsg;
660 ARDOUR::init_post_engine ();
662 /* connect to important signals */
664 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
665 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
666 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
667 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
668 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
670 if (setup_windows ()) {
671 throw failed_constructor ();
674 transport_ctrl.map_actions ();
676 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
677 XMLNode* n = Config->extra_xml (X_("UI"));
679 _status_bar_visibility.set_state (*n);
682 check_memory_locking();
684 /* this is the first point at which all the possible actions are
685 * available, because some of the available actions are dependent on
686 * aspects of the engine/backend.
689 if (ARDOUR_COMMAND_LINE::show_key_actions) {
691 Bindings::save_all_bindings_as_html (sstr);
693 if (sstr.str().empty()) {
700 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
702 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
708 #ifdef PLATFORM_WINDOWS
714 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
715 #ifndef PLATFORM_WINDOWS
718 g_unlink (file_name);
720 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
726 #ifndef PLATFORM_WINDOWS
730 PBD::open_uri (string_compose ("file:///%1", file_name));
732 halt_connection.disconnect ();
733 AudioEngine::instance()->stop ();
738 if (ARDOUR_COMMAND_LINE::show_actions) {
741 vector<string> paths;
742 vector<string> labels;
743 vector<string> tooltips;
745 vector<Glib::RefPtr<Gtk::Action> > actions;
746 string ver_in = revision;
747 string ver = ver_in.substr(0, ver_in.find("-"));
750 output << "\n<h2>Menu actions</h2>" << endl;
751 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
752 output << " surfaces or scripts.\n</p>\n" << endl;
753 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
754 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
755 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
756 output << "<table class=\"dl\">\n <thead>" << endl;
757 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
758 output << " </thead>\n <tbody>" << endl;
760 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
762 vector<string>::iterator p;
763 vector<string>::iterator l;
765 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
766 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (10, string::npos);
767 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
769 output << " </tbody>\n </table>" << endl;
771 // output this mess to a browser for easiest X-platform use
772 // it is not pretty HTML, but it works and it's main purpose
773 // is to create raw html to fit in Ardour's manual with no editing
778 if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) {
780 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
786 #ifdef PLATFORM_WINDOWS
792 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
793 #ifndef PLATFORM_WINDOWS
796 g_unlink (file_name);
798 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
804 #ifndef PLATFORM_WINDOWS
808 PBD::open_uri (string_compose ("file:///%1", file_name));
810 halt_connection.disconnect ();
811 AudioEngine::instance()->stop ();
815 /* this being a GUI and all, we want peakfiles */
817 AudioFileSource::set_build_peakfiles (true);
818 AudioFileSource::set_build_missing_peakfiles (true);
820 /* set default clock modes */
822 primary_clock->set_mode (AudioClock::Timecode);
823 secondary_clock->set_mode (AudioClock::BBT);
825 /* start the time-of-day-clock */
828 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
829 update_wall_clock ();
830 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
835 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
836 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
837 Config->map_parameters (pc);
839 UIConfiguration::instance().map_parameters (pc);
843 ARDOUR_UI::~ARDOUR_UI ()
845 UIConfiguration::instance().save_state();
849 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
850 // don't bother at 'real' exit. the OS cleans up for us.
851 delete big_clock; big_clock = 0;
852 delete primary_clock; primary_clock = 0;
853 delete secondary_clock; secondary_clock = 0;
854 delete _process_thread; _process_thread = 0;
855 delete time_info_box; time_info_box = 0;
856 delete meterbridge; meterbridge = 0;
857 delete luawindow; luawindow = 0;
858 delete editor; editor = 0;
859 delete mixer; mixer = 0;
860 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
862 delete gui_object_state; gui_object_state = 0;
863 delete main_window_visibility;
864 FastMeter::flush_pattern_cache ();
865 ArdourFader::flush_pattern_cache ();
869 /* Small trick to flush main-thread event pool.
870 * Other thread-pools are destroyed at pthread_exit(),
871 * but tmain thread termination is too late to trigger Pool::~Pool()
873 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
874 delete ev->event_pool();
879 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
881 if (Splash::instance()) {
882 Splash::instance()->pop_back_for (win);
887 ARDOUR_UI::configure_timeout ()
889 if (last_configure_time == 0) {
890 /* no configure events yet */
894 /* force a gap of 0.5 seconds since the last configure event
897 if (get_microseconds() - last_configure_time < 500000) {
900 have_configure_timeout = false;
901 save_ardour_state ();
907 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
909 if (have_configure_timeout) {
910 last_configure_time = get_microseconds();
912 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
913 have_configure_timeout = true;
920 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
924 if (node.get_property ("roll", str)){
925 roll_controllable->set_id (str);
927 if (node.get_property ("stop", str)) {
928 stop_controllable->set_id (str);
930 if (node.get_property ("goto-start", str)) {
931 goto_start_controllable->set_id (str);
933 if (node.get_property ("goto-end", str)) {
934 goto_end_controllable->set_id (str);
936 if (node.get_property ("auto-loop", str)) {
937 auto_loop_controllable->set_id (str);
939 if (node.get_property ("play-selection", str)) {
940 play_selection_controllable->set_id (str);
942 if (node.get_property ("rec", str)) {
943 rec_controllable->set_id (str);
945 if (node.get_property ("shuttle", str)) {
946 shuttle_box.controllable()->set_id (str);
951 ARDOUR_UI::get_transport_controllable_state ()
953 XMLNode* node = new XMLNode(X_("TransportControllables"));
955 node->set_property (X_("roll"), roll_controllable->id());
956 node->set_property (X_("stop"), stop_controllable->id());
957 node->set_property (X_("goto-start"), goto_start_controllable->id());
958 node->set_property (X_("goto-end"), goto_end_controllable->id());
959 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
960 node->set_property (X_("play-selection"), play_selection_controllable->id());
961 node->set_property (X_("rec"), rec_controllable->id());
962 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
968 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
971 _session->save_state (snapshot_name);
976 ARDOUR_UI::autosave_session ()
978 if (g_main_depth() > 1) {
979 /* inside a recursive main loop,
980 give up because we may not be able to
986 if (!Config->get_periodic_safety_backups()) {
991 _session->maybe_write_autosave();
998 ARDOUR_UI::session_dirty_changed ()
1005 ARDOUR_UI::update_autosave ()
1007 if (_session && _session->dirty()) {
1008 if (_autosave_connection.connected()) {
1009 _autosave_connection.disconnect();
1012 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1013 Config->get_periodic_safety_backup_interval() * 1000);
1016 if (_autosave_connection.connected()) {
1017 _autosave_connection.disconnect();
1023 ARDOUR_UI::check_announcements ()
1026 string _annc_filename;
1029 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1030 #elif defined PLATFORM_WINDOWS
1031 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1033 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1035 _annc_filename.append (VERSIONSTRING);
1037 _announce_string = "";
1039 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1040 FILE* fin = g_fopen (path.c_str(), "rb");
1042 while (!feof (fin)) {
1045 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1048 _announce_string.append (tmp, len);
1053 pingback (VERSIONSTRING, path);
1058 _hide_splash (gpointer arg)
1060 ((ARDOUR_UI*)arg)->hide_splash();
1065 ARDOUR_UI::starting ()
1067 Application* app = Application::instance ();
1068 const char *nsm_url;
1069 bool brand_new_user = ArdourStartup::required ();
1071 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1072 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1074 if (ARDOUR_COMMAND_LINE::check_announcements) {
1075 check_announcements ();
1080 /* we need to create this early because it may need to set the
1081 * audio backend end up.
1085 audio_midi_setup.get (true);
1087 std::cerr << "audio-midi engine setup failed."<< std::endl;
1091 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1092 nsm = new NSM_Client;
1093 if (!nsm->init (nsm_url)) {
1094 /* the ardour executable may have different names:
1096 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1097 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1098 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1100 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1102 const char *process_name = g_getenv ("ARDOUR_SELF");
1103 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
1106 // wait for announce reply from nsm server
1107 for ( i = 0; i < 5000; ++i) {
1111 if (nsm->is_active()) {
1116 error << _("NSM server did not announce itself") << endmsg;
1119 // wait for open command from nsm server
1120 for ( i = 0; i < 5000; ++i) {
1122 Glib::usleep (1000);
1123 if (nsm->client_id ()) {
1129 error << _("NSM: no client ID provided") << endmsg;
1133 if (_session && nsm) {
1134 _session->set_nsm_state( nsm->is_active() );
1136 error << _("NSM: no session created") << endmsg;
1140 // nsm requires these actions disabled
1141 vector<string> action_names;
1142 action_names.push_back("SaveAs");
1143 action_names.push_back("Rename");
1144 action_names.push_back("New");
1145 action_names.push_back("Open");
1146 action_names.push_back("Recent");
1147 action_names.push_back("Close");
1149 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1150 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1152 act->set_sensitive (false);
1159 error << _("NSM: initialization failed") << endmsg;
1165 if (brand_new_user) {
1166 _initial_verbose_plugin_scan = true;
1171 _initial_verbose_plugin_scan = false;
1172 switch (s.response ()) {
1173 case Gtk::RESPONSE_OK:
1180 // TODO: maybe IFF brand_new_user
1181 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1182 std::string dspd (Config->get_default_session_parent_dir());
1183 Searchpath ds (ARDOUR::ardour_data_search_path());
1184 ds.add_subdirectory_to_paths ("sessions");
1185 vector<string> demos;
1186 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
1188 ARDOUR::RecentSessions rs;
1189 ARDOUR::read_recent_sessions (rs);
1191 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1192 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
1193 std::string name = basename_nosuffix (basename_nosuffix (*i));
1194 std::string path = Glib::build_filename (dspd, name);
1195 /* skip if session-dir already exists */
1196 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1199 /* skip sessions that are already in 'recent'.
1200 * eg. a new user changed <session-default-dir> shorly after installation
1202 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1203 if ((*r).first == name) {
1208 PBD::FileArchive ar (*i);
1209 if (0 == ar.inflate (dspd)) {
1210 store_recent_sessions (name, path);
1211 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1217 #ifdef NO_PLUGIN_STATE
1219 ARDOUR::RecentSessions rs;
1220 ARDOUR::read_recent_sessions (rs);
1222 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1224 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1226 /* already used Ardour, have sessions ... warn about plugin state */
1228 ArdourDialog d (_("Free/Demo Version Warning"), true);
1230 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1231 CheckButton c (_("Don't warn me about this again"));
1233 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1234 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1235 _("It will not restore OR save any plugin settings"),
1236 _("If you load an existing session with plugin settings\n"
1237 "they will not be used and will be lost."),
1238 _("To get full access to updates without this limitation\n"
1239 "consider becoming a subscriber for a low cost every month.")));
1240 l.set_justify (JUSTIFY_CENTER);
1242 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1244 d.get_vbox()->pack_start (l, true, true);
1245 d.get_vbox()->pack_start (b, false, false, 12);
1246 d.get_vbox()->pack_start (c, false, false, 12);
1248 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1249 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1253 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1255 if (d.run () != RESPONSE_OK) {
1261 /* go get a session */
1263 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1265 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1266 std::cerr << "Cannot get session parameters."<< std::endl;
1273 WM::Manager::instance().show_visible ();
1275 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1276 * editor window, and we may want stuff to be hidden.
1278 _status_bar_visibility.update ();
1280 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1282 /* all other dialogs are created conditionally */
1288 ARDOUR_UI::check_memory_locking ()
1290 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1291 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1295 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1297 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1299 struct rlimit limits;
1301 long pages, page_size;
1303 size_t pages_len=sizeof(pages);
1304 if ((page_size = getpagesize()) < 0 ||
1305 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1307 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1312 ram = (int64_t) pages * (int64_t) page_size;
1315 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1319 if (limits.rlim_cur != RLIM_INFINITY) {
1321 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1325 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1326 "This might cause %1 to run out of memory before your system "
1327 "runs out of memory. \n\n"
1328 "You can view the memory limit with 'ulimit -l', "
1329 "and it is normally controlled by %2"),
1332 X_("/etc/login.conf")
1334 X_(" /etc/security/limits.conf")
1338 msg.set_default_response (RESPONSE_OK);
1340 VBox* vbox = msg.get_vbox();
1342 CheckButton cb (_("Do not show this window again"));
1343 hbox.pack_start (cb, true, false);
1344 vbox->pack_start (hbox);
1349 pop_back_splash (msg);
1353 if (cb.get_active()) {
1354 XMLNode node (X_("no-memory-warning"));
1355 Config->add_instant_xml (node);
1360 #endif // !__APPLE__
1365 ARDOUR_UI::queue_finish ()
1367 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1371 ARDOUR_UI::idle_finish ()
1374 return false; /* do not call again */
1381 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1383 if (_session->dirty()) {
1384 vector<string> actions;
1385 actions.push_back (_("Don't quit"));
1386 actions.push_back (_("Just quit"));
1387 actions.push_back (_("Save and quit"));
1388 switch (ask_about_saving_session(actions)) {
1393 /* use the default name */
1394 if (save_state_canfail ("")) {
1395 /* failed - don't quit */
1396 MessageDialog msg (_main_window,
1397 string_compose (_("\
1398 %1 was unable to save your session.\n\n\
1399 If you still wish to quit, please use the\n\n\
1400 \"Just quit\" option."), PROGRAM_NAME));
1401 pop_back_splash(msg);
1411 second_connection.disconnect ();
1412 point_one_second_connection.disconnect ();
1413 point_zero_something_second_connection.disconnect();
1414 fps_connection.disconnect();
1417 delete ARDOUR_UI::instance()->video_timeline;
1418 ARDOUR_UI::instance()->video_timeline = NULL;
1419 stop_video_server();
1421 /* Save state before deleting the session, as that causes some
1422 windows to be destroyed before their visible state can be
1425 save_ardour_state ();
1427 if (key_editor.get (false)) {
1428 key_editor->disconnect ();
1431 close_all_dialogs ();
1434 _session->set_clean ();
1435 _session->remove_pending_capture_state ();
1440 halt_connection.disconnect ();
1441 AudioEngine::instance()->stop ();
1442 #ifdef WINDOWS_VST_SUPPORT
1443 fst_stop_threading();
1449 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1451 ArdourDialog window (_("Unsaved Session"));
1452 Gtk::HBox dhbox; // the hbox for the image and text
1453 Gtk::Label prompt_label;
1454 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1458 assert (actions.size() >= 3);
1460 window.add_button (actions[0], RESPONSE_REJECT);
1461 window.add_button (actions[1], RESPONSE_APPLY);
1462 window.add_button (actions[2], RESPONSE_ACCEPT);
1464 window.set_default_response (RESPONSE_ACCEPT);
1466 Gtk::Button noquit_button (msg);
1467 noquit_button.set_name ("EditorGTKButton");
1471 if (_session->snap_name() == _session->name()) {
1472 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1473 _session->snap_name());
1475 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1476 _session->snap_name());
1479 prompt_label.set_text (prompt);
1480 prompt_label.set_name (X_("PrompterLabel"));
1481 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1483 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1484 dhbox.set_homogeneous (false);
1485 dhbox.pack_start (*dimage, false, false, 5);
1486 dhbox.pack_start (prompt_label, true, false, 5);
1487 window.get_vbox()->pack_start (dhbox);
1489 window.set_name (_("Prompter"));
1490 window.set_modal (true);
1491 window.set_resizable (false);
1494 prompt_label.show();
1499 ResponseType r = (ResponseType) window.run();
1504 case RESPONSE_ACCEPT: // save and get out of here
1506 case RESPONSE_APPLY: // get out of here
1517 ARDOUR_UI::every_second ()
1520 update_disk_space ();
1521 update_timecode_format ();
1522 update_peak_thread_work ();
1524 if (nsm && nsm->is_active ()) {
1527 if (!_was_dirty && _session->dirty ()) {
1531 else if (_was_dirty && !_session->dirty ()){
1539 ARDOUR_UI::every_point_one_seconds ()
1541 if (editor) editor->build_region_boundary_cache();
1545 ARDOUR_UI::every_point_zero_something_seconds ()
1547 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1549 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1550 float mpeak = editor_meter->update_meters();
1551 if (mpeak > editor_meter_max_peak) {
1552 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1553 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1560 ARDOUR_UI::set_fps_timeout_connection ()
1562 unsigned int interval = 40;
1563 if (!_session) return;
1564 if (_session->timecode_frames_per_second() != 0) {
1565 /* ideally we'll use a select() to sleep and not accumulate
1566 * idle time to provide a regular periodic signal.
1567 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1568 * However, that'll require a dedicated thread and cross-thread
1569 * signals to the GUI Thread..
1571 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1572 * _session->sample_rate() / _session->nominal_sample_rate()
1573 / _session->timecode_frames_per_second()
1575 #ifdef PLATFORM_WINDOWS
1576 // the smallest windows scheduler time-slice is ~15ms.
1577 // periodic GUI timeouts shorter than that will cause
1578 // WaitForSingleObject to spinlock (100% of one CPU Core)
1579 // and gtk never enters idle mode.
1580 // also changing timeBeginPeriod(1) does not affect that in
1581 // any beneficial way, so we just limit the max rate for now.
1582 interval = std::max(30u, interval); // at most ~33Hz.
1584 interval = std::max(8u, interval); // at most 120Hz.
1587 fps_connection.disconnect();
1588 Timers::set_fps_interval (interval);
1592 ARDOUR_UI::update_sample_rate (samplecnt_t)
1596 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1598 if (!AudioEngine::instance()->running()) {
1600 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1604 samplecnt_t rate = AudioEngine::instance()->sample_rate();
1607 /* no sample rate available */
1608 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1611 if (fmod (rate, 1000.0) != 0.0) {
1612 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1613 (float) rate / 1000.0f,
1614 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1616 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1618 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1622 sample_rate_label.set_markup (buf);
1626 ARDOUR_UI::update_format ()
1629 format_label.set_text ("");
1634 s << _("File:") << X_(" <span foreground=\"green\">");
1636 switch (_session->config.get_native_file_header_format ()) {
1671 switch (_session->config.get_native_file_data_format ()) {
1685 format_label.set_markup (s.str ());
1689 ARDOUR_UI::update_cpu_load ()
1691 const unsigned int x = _session ? _session->get_xrun_count () : 0;
1692 double const c = AudioEngine::instance()->get_dsp_load ();
1694 const char* const bg = c > 90 ? " background=\"red\"" : "";
1698 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (>10k)", bg, c);
1700 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span> (%d)", bg, c, x);
1702 snprintf (buf, sizeof (buf), "DSP: <span%s>%.0f%%</span>", bg, c);
1705 dsp_load_label.set_markup (buf);
1708 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: >10k\n%s"), c, _("Shift+Click to clear xruns."));
1710 snprintf (buf, sizeof (buf), _("DSP: %.1f%% X: %u\n%s"), c, x, _("Shift+Click to clear xruns."));
1712 snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), c);
1715 ArdourWidgets::set_tooltip (dsp_load_label, buf);
1719 ARDOUR_UI::update_peak_thread_work ()
1722 const int c = SourceFactory::peak_work_queue_length ();
1724 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1725 peak_thread_work_label.set_markup (buf);
1727 peak_thread_work_label.set_markup (X_(""));
1732 ARDOUR_UI::count_recenabled_streams (Route& route)
1734 Track* track = dynamic_cast<Track*>(&route);
1735 if (track && track->rec_enable_control()->get_value()) {
1736 rec_enabled_streams += track->n_inputs().n_total();
1741 ARDOUR_UI::format_disk_space_label (float remain_sec)
1743 if (remain_sec < 0) {
1744 disk_space_label.set_text (_("N/A"));
1745 ArdourWidgets::set_tooltip (disk_space_label, _("Unknown"));
1751 int sec = floor (remain_sec);
1752 int hrs = sec / 3600;
1753 int mins = (sec / 60) % 60;
1754 int secs = sec % 60;
1755 snprintf (buf, sizeof(buf), _("%02dh:%02dm:%02ds"), hrs, mins, secs);
1756 ArdourWidgets::set_tooltip (disk_space_label, buf);
1758 if (remain_sec > 86400) {
1759 disk_space_label.set_text (_("Rec: >24h"));
1761 } else if (remain_sec > 32400 /* 9 hours */) {
1762 snprintf (buf, sizeof (buf), "Rec: %.0fh", remain_sec / 3600.f);
1763 } else if (remain_sec > 5940 /* 99 mins */) {
1764 snprintf (buf, sizeof (buf), "Rec: %.1fh", remain_sec / 3600.f);
1766 snprintf (buf, sizeof (buf), "Rec: %.0fm", remain_sec / 60.f);
1768 disk_space_label.set_text (buf);
1773 ARDOUR_UI::update_disk_space()
1775 if (_session == 0) {
1776 format_disk_space_label (-1);
1780 boost::optional<samplecnt_t> opt_samples = _session->available_capture_duration();
1781 samplecnt_t fr = _session->sample_rate();
1784 /* skip update - no SR available */
1785 format_disk_space_label (-1);
1790 /* Available space is unknown */
1791 format_disk_space_label (-1);
1792 } else if (opt_samples.get_value_or (0) == max_samplecnt) {
1793 format_disk_space_label (max_samplecnt);
1795 rec_enabled_streams = 0;
1796 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1798 samplecnt_t samples = opt_samples.get_value_or (0);
1800 if (rec_enabled_streams) {
1801 samples /= rec_enabled_streams;
1804 format_disk_space_label (samples / (float)fr);
1810 ARDOUR_UI::update_timecode_format ()
1816 boost::shared_ptr<TimecodeTransportMaster> tcmaster;
1817 boost::shared_ptr<TransportMaster> tm = TransportMasterManager::instance().current();
1819 if ((tm->type() == LTC || tm->type() == MTC) && (tcmaster = boost::dynamic_pointer_cast<TimecodeTransportMaster>(tm)) != 0) {
1820 matching = (tcmaster->apparent_timecode_format() == _session->config.get_timecode_format());
1825 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1826 matching ? X_("green") : X_("red"),
1827 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1829 snprintf (buf, sizeof (buf), "TC: n/a");
1832 timecode_format_label.set_markup (buf);
1836 ARDOUR_UI::update_wall_clock ()
1840 static int last_min = -1;
1843 tm_now = localtime (&now);
1844 if (last_min != tm_now->tm_min) {
1846 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1847 wall_clock_label.set_text (buf);
1848 last_min = tm_now->tm_min;
1855 ARDOUR_UI::open_recent_session ()
1857 bool can_return = (_session != 0);
1859 SessionDialog recent_session_dialog;
1863 ResponseType r = (ResponseType) recent_session_dialog.run ();
1866 case RESPONSE_ACCEPT:
1870 recent_session_dialog.hide();
1877 recent_session_dialog.hide();
1881 std::string path = recent_session_dialog.session_folder();
1882 std::string state = recent_session_dialog.session_name (should_be_new);
1884 if (should_be_new == true) {
1888 _session_is_new = false;
1890 if (load_session (path, state) == 0) {
1899 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1901 if (!AudioEngine::instance()->running()) {
1902 MessageDialog msg (parent, string_compose (
1903 _("%1 is not connected to any audio backend.\n"
1904 "You cannot open or close sessions in this condition"),
1906 pop_back_splash (msg);
1914 ARDOUR_UI::open_session ()
1916 if (!check_audioengine (_main_window)) {
1920 /* ardour sessions are folders */
1921 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1922 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1923 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1924 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1927 string session_parent_dir = Glib::path_get_dirname(_session->path());
1928 open_session_selector.set_current_folder(session_parent_dir);
1930 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1933 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1935 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1936 string default_session_folder = Config->get_default_session_parent_dir();
1937 open_session_selector.add_shortcut_folder (default_session_folder);
1939 catch (Glib::Error const& e) {
1940 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1943 FileFilter session_filter;
1944 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1945 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1946 open_session_selector.add_filter (session_filter);
1948 FileFilter archive_filter;
1949 archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1950 archive_filter.set_name (_("Session Archives"));
1952 open_session_selector.add_filter (archive_filter);
1954 open_session_selector.set_filter (session_filter);
1956 int response = open_session_selector.run();
1957 open_session_selector.hide ();
1959 if (response == Gtk::RESPONSE_CANCEL) {
1963 string session_path = open_session_selector.get_filename();
1967 if (session_path.length() > 0) {
1968 int rv = ARDOUR::inflate_session (session_path,
1969 Config->get_default_session_parent_dir(), path, name);
1971 _session_is_new = false;
1972 load_session (path, name);
1975 MessageDialog msg (_main_window,
1976 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1979 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1980 _session_is_new = isnew;
1981 load_session (path, name);
1987 ARDOUR_UI::session_add_mixed_track (
1988 const ChanCount& input,
1989 const ChanCount& output,
1990 RouteGroup* route_group,
1992 const string& name_template,
1994 PluginInfoPtr instrument,
1995 Plugin::PresetRecord* pset,
1996 ARDOUR::PresentationInfo::order_t order)
2000 if (Profile->get_mixbus ()) {
2005 list<boost::shared_ptr<MidiTrack> > tracks;
2006 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2008 if (tracks.size() != how_many) {
2009 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2014 display_insufficient_ports_message ();
2020 ARDOUR_UI::session_add_midi_bus (
2021 RouteGroup* route_group,
2023 const string& name_template,
2025 PluginInfoPtr instrument,
2026 Plugin::PresetRecord* pset,
2027 ARDOUR::PresentationInfo::order_t order)
2029 if (_session == 0) {
2030 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2034 if (Profile->get_mixbus ()) {
2040 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2041 if (routes.size() != how_many) {
2042 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2047 display_insufficient_ports_message ();
2053 ARDOUR_UI::session_add_midi_route (
2055 RouteGroup* route_group,
2057 const string& name_template,
2059 PluginInfoPtr instrument,
2060 Plugin::PresetRecord* pset,
2061 ARDOUR::PresentationInfo::order_t order)
2063 ChanCount one_midi_channel;
2064 one_midi_channel.set (DataType::MIDI, 1);
2067 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2069 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2074 ARDOUR_UI::session_add_audio_route (
2076 int32_t input_channels,
2077 int32_t output_channels,
2078 ARDOUR::TrackMode mode,
2079 RouteGroup* route_group,
2081 string const & name_template,
2083 ARDOUR::PresentationInfo::order_t order)
2085 list<boost::shared_ptr<AudioTrack> > tracks;
2092 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2094 if (tracks.size() != how_many) {
2095 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2101 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2103 if (routes.size() != how_many) {
2104 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2111 display_insufficient_ports_message ();
2116 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2117 (*i)->set_strict_io (true);
2119 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2120 (*i)->set_strict_io (true);
2126 ARDOUR_UI::session_add_foldback_bus (uint32_t how_many, string const & name_template)
2133 routes = _session->new_audio_route (2, 2, 0, how_many, name_template, PresentationInfo::FoldbackBus, -1);
2135 if (routes.size() != how_many) {
2136 error << string_compose (P_("could not create %1 new foldback bus", "could not create %1 new foldback busses", how_many), how_many)
2142 display_insufficient_ports_message ();
2146 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2147 (*i)->set_strict_io (true);
2152 ARDOUR_UI::display_insufficient_ports_message ()
2154 MessageDialog msg (_main_window,
2155 string_compose (_("There are insufficient ports available\n\
2156 to create a new track or bus.\n\
2157 You should save %1, exit and\n\
2158 restart with more ports."), PROGRAM_NAME));
2159 pop_back_splash (msg);
2164 ARDOUR_UI::transport_goto_start ()
2167 _session->goto_start();
2169 /* force displayed area in editor to start no matter
2170 what "follow playhead" setting is.
2174 editor->center_screen (_session->current_start_sample ());
2180 ARDOUR_UI::transport_goto_zero ()
2183 _session->request_locate (0);
2185 /* force displayed area in editor to start no matter
2186 what "follow playhead" setting is.
2190 editor->reset_x_origin (0);
2196 ARDOUR_UI::transport_goto_wallclock ()
2198 if (_session && editor) {
2202 samplepos_t samples;
2205 localtime_r (&now, &tmnow);
2207 samplecnt_t sample_rate = _session->sample_rate();
2209 if (sample_rate == 0) {
2210 /* no frame rate available */
2214 samples = tmnow.tm_hour * (60 * 60 * sample_rate);
2215 samples += tmnow.tm_min * (60 * sample_rate);
2216 samples += tmnow.tm_sec * sample_rate;
2218 _session->request_locate (samples, _session->transport_rolling ());
2220 /* force displayed area in editor to start no matter
2221 what "follow playhead" setting is.
2225 editor->center_screen (samples);
2231 ARDOUR_UI::transport_goto_end ()
2234 samplepos_t const sample = _session->current_end_sample();
2235 _session->request_locate (sample);
2237 /* force displayed area in editor to start no matter
2238 what "follow playhead" setting is.
2242 editor->center_screen (sample);
2248 ARDOUR_UI::transport_stop ()
2254 if (_session->is_auditioning()) {
2255 _session->cancel_audition ();
2259 _session->request_stop (false, true);
2262 /** Check if any tracks are record enabled. If none are, record enable all of them.
2263 * @return true if track record-enabled status was changed, false otherwise.
2266 ARDOUR_UI::trx_record_enable_all_tracks ()
2272 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2273 bool none_record_enabled = true;
2275 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2276 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2279 if (t->rec_enable_control()->get_value()) {
2280 none_record_enabled = false;
2285 if (none_record_enabled) {
2286 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2289 return none_record_enabled;
2293 ARDOUR_UI::transport_record (bool roll)
2296 switch (_session->record_status()) {
2297 case Session::Disabled:
2298 if (_session->ntracks() == 0) {
2299 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."));
2303 if (Profile->get_trx()) {
2304 roll = trx_record_enable_all_tracks ();
2306 _session->maybe_enable_record ();
2311 case Session::Recording:
2313 _session->request_stop();
2315 _session->disable_record (false, true);
2319 case Session::Enabled:
2320 _session->disable_record (false, true);
2326 ARDOUR_UI::transport_roll ()
2332 if (_session->is_auditioning()) {
2336 if (_session->config.get_external_sync()) {
2337 switch (TransportMasterManager::instance().current()->type()) {
2341 /* transport controlled by the master */
2346 bool rolling = _session->transport_rolling();
2348 if (_session->get_play_loop()) {
2350 /* If loop playback is not a mode, then we should cancel
2351 it when this action is requested. If it is a mode
2352 we just leave it in place.
2355 if (!Config->get_loop_is_mode()) {
2356 /* XXX it is not possible to just leave seamless loop and keep
2357 playing at present (nov 4th 2009)
2359 if (!Config->get_seamless_loop()) {
2360 /* stop loop playback and stop rolling */
2361 _session->request_play_loop (false, true);
2362 } else if (rolling) {
2363 /* stop loop playback but keep rolling */
2364 _session->request_play_loop (false, false);
2368 } else if (_session->get_play_range () ) {
2369 /* stop playing a range if we currently are */
2370 _session->request_play_range (0, true);
2374 _session->request_transport_speed (1.0f);
2379 ARDOUR_UI::get_smart_mode() const
2381 return ( editor->get_smart_mode() );
2386 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2392 if (_session->is_auditioning()) {
2393 _session->cancel_audition ();
2397 if (_session->config.get_external_sync()) {
2398 switch (TransportMasterManager::instance().current()->type()) {
2402 /* transport controlled by the master */
2407 bool rolling = _session->transport_rolling();
2408 bool affect_transport = true;
2410 if (rolling && roll_out_of_bounded_mode) {
2411 /* drop out of loop/range playback but leave transport rolling */
2412 if (_session->get_play_loop()) {
2413 if (_session->actively_recording()) {
2415 /* just stop using the loop, then actually stop
2418 _session->request_play_loop (false, affect_transport);
2421 if (Config->get_seamless_loop()) {
2422 /* the disk buffers contain copies of the loop - we can't
2423 just keep playing, so stop the transport. the user
2424 can restart as they wish.
2426 affect_transport = true;
2428 /* disk buffers are normal, so we can keep playing */
2429 affect_transport = false;
2431 _session->request_play_loop (false, affect_transport);
2433 } else if (_session->get_play_range ()) {
2434 affect_transport = false;
2435 _session->request_play_range (0, true);
2439 if (affect_transport) {
2441 _session->request_stop (with_abort, true);
2443 } else if (!with_abort) { /* with_abort == true means the
2444 * command was intended to stop
2445 * transport, not start.
2448 /* the only external sync condition we can be in here
2449 * would be Engine (JACK) sync, in which case we still
2453 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
2454 _session->request_play_range (&editor->get_selection().time, true);
2455 _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here
2457 _session->request_transport_speed (1.0f);
2463 ARDOUR_UI::toggle_session_auto_loop ()
2469 Location * looploc = _session->locations()->auto_loop_location();
2475 if (_session->get_play_loop()) {
2477 /* looping enabled, our job is to disable it */
2479 _session->request_play_loop (false);
2483 /* looping not enabled, our job is to enable it.
2485 loop-is-NOT-mode: this action always starts the transport rolling.
2486 loop-IS-mode: this action simply sets the loop play mechanism, but
2487 does not start transport.
2489 if (Config->get_loop_is_mode()) {
2490 _session->request_play_loop (true, false);
2492 _session->request_play_loop (true, true);
2496 //show the loop markers
2497 looploc->set_hidden (false, this);
2501 ARDOUR_UI::transport_play_selection ()
2507 editor->play_selection ();
2511 ARDOUR_UI::transport_play_preroll ()
2516 editor->play_with_preroll ();
2520 ARDOUR_UI::transport_rec_preroll ()
2525 editor->rec_with_preroll ();
2529 ARDOUR_UI::transport_rec_count_in ()
2534 editor->rec_with_count_in ();
2538 ARDOUR_UI::transport_rewind (int option)
2540 float current_transport_speed;
2543 current_transport_speed = _session->transport_speed();
2545 if (current_transport_speed >= 0.0f) {
2548 _session->request_transport_speed (-1.0f);
2551 _session->request_transport_speed (-4.0f);
2554 _session->request_transport_speed (-0.5f);
2559 _session->request_transport_speed (current_transport_speed * 1.5f);
2565 ARDOUR_UI::transport_forward (int option)
2571 float current_transport_speed = _session->transport_speed();
2573 if (current_transport_speed <= 0.0f) {
2576 _session->request_transport_speed (1.0f);
2579 _session->request_transport_speed (4.0f);
2582 _session->request_transport_speed (0.5f);
2587 _session->request_transport_speed (current_transport_speed * 1.5f);
2592 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2598 boost::shared_ptr<Route> r;
2600 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2602 boost::shared_ptr<Track> t;
2604 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2605 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2611 ARDOUR_UI::map_transport_state ()
2614 layered_button.set_sensitive (false);
2618 shuttle_box.map_transport_state ();
2620 float sp = _session->transport_speed();
2623 layered_button.set_sensitive (!_session->actively_recording ());
2625 layered_button.set_sensitive (true);
2626 update_disk_space ();
2631 ARDOUR_UI::blink_handler (bool blink_on)
2633 sync_blink (blink_on);
2635 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2638 error_blink (blink_on);
2639 solo_blink (blink_on);
2640 audition_blink (blink_on);
2641 feedback_blink (blink_on);
2645 ARDOUR_UI::update_clocks ()
2647 if (!_session) return;
2649 if (editor && !editor->dragging_playhead()) {
2650 Clock (_session->audible_sample()); /* EMIT_SIGNAL */
2655 ARDOUR_UI::start_clocking ()
2657 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2658 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2660 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2665 ARDOUR_UI::stop_clocking ()
2667 clock_signal_connection.disconnect ();
2671 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2675 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2677 label->set_text (buf);
2678 bar->set_fraction (fraction);
2680 /* process events, redraws, etc. */
2682 while (gtk_events_pending()) {
2683 gtk_main_iteration ();
2686 return true; /* continue with save-as */
2690 ARDOUR_UI::save_session_as ()
2696 if (_session->dirty()) {
2697 vector<string> actions;
2698 actions.push_back (_("Abort save-as"));
2699 actions.push_back (_("Don't save now, just save-as"));
2700 actions.push_back (_("Save it first"));
2701 switch (ask_about_saving_session(actions)) {
2706 if (save_state_canfail ("")) {
2707 MessageDialog msg (_main_window,
2708 string_compose (_("\
2709 %1 was unable to save your session.\n\n\
2710 If you still wish to proceed, please use the\n\n\
2711 \"Don't save now\" option."), PROGRAM_NAME));
2712 pop_back_splash(msg);
2718 _session->remove_pending_capture_state ();
2723 if (!save_as_dialog) {
2724 save_as_dialog = new SaveAsDialog;
2727 save_as_dialog->set_name (_session->name());
2729 int response = save_as_dialog->run ();
2731 save_as_dialog->hide ();
2734 case Gtk::RESPONSE_OK:
2743 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2744 sa.new_name = save_as_dialog->new_name ();
2745 sa.switch_to = save_as_dialog->switch_to();
2746 sa.copy_media = save_as_dialog->copy_media();
2747 sa.copy_external = save_as_dialog->copy_external();
2748 sa.include_media = save_as_dialog->include_media ();
2750 /* Only bother with a progress dialog if we're going to copy
2751 media into the save-as target. Without that choice, this
2752 will be very fast because we're only talking about a few kB's to
2753 perhaps a couple of MB's of data.
2756 ArdourDialog progress_dialog (_("Save As"), true);
2759 if (sa.include_media && sa.copy_media) {
2761 Gtk::Label* label = manage (new Gtk::Label());
2762 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2764 progress_dialog.get_vbox()->pack_start (*label);
2765 progress_dialog.get_vbox()->pack_start (*progress_bar);
2767 progress_bar->show ();
2769 /* this signal will be emitted from within this, the calling thread,
2770 * after every file is copied. It provides information on percentage
2771 * complete (in terms of total data to copy), the number of files
2772 * copied so far, and the total number to copy.
2775 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2777 progress_dialog.show_all ();
2778 progress_dialog.present ();
2781 if (_session->save_as (sa)) {
2783 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2787 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2788 * the trick is this: if the new session was copy with media included,
2789 * then Session::save_as() will have already done a neat trick to avoid
2790 * us having to unload and load the new state. But if the media was not
2791 * included, then this is required (it avoids us having to otherwise
2792 * drop all references to media (sources).
2795 if (!sa.include_media && sa.switch_to) {
2796 unload_session (false);
2797 load_session (sa.final_session_folder_name, sa.new_name);
2802 ARDOUR_UI::archive_session ()
2810 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2812 SessionArchiveDialog sad;
2813 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2814 int response = sad.run ();
2816 if (response != Gtk::RESPONSE_OK) {
2821 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
2822 MessageDialog msg (_("Session Archiving failed."));
2828 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2832 struct tm local_time;
2835 localtime_r (&n, &local_time);
2836 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2837 if (switch_to_it && _session->dirty ()) {
2838 save_state_canfail ("");
2841 save_state (timebuf, switch_to_it);
2846 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2850 prompter.get_result (snapname);
2852 bool do_save = (snapname.length() != 0);
2855 char illegal = Session::session_name_is_legal(snapname);
2857 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2858 "snapshot names may not contain a '%1' character"), illegal));
2864 vector<std::string> p;
2865 get_state_files_in_directory (_session->session_directory().root_path(), p);
2866 vector<string> n = get_file_names_no_extension (p);
2868 if (find (n.begin(), n.end(), snapname) != n.end()) {
2870 do_save = overwrite_file_dialog (prompter,
2871 _("Confirm Snapshot Overwrite"),
2872 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2876 save_state (snapname, switch_to_it);
2886 /** Ask the user for the name of a new snapshot and then take it.
2890 ARDOUR_UI::snapshot_session (bool switch_to_it)
2892 if (switch_to_it && _session->dirty()) {
2893 vector<string> actions;
2894 actions.push_back (_("Abort saving snapshot"));
2895 actions.push_back (_("Don't save now, just snapshot"));
2896 actions.push_back (_("Save it first"));
2897 switch (ask_about_saving_session(actions)) {
2902 if (save_state_canfail ("")) {
2903 MessageDialog msg (_main_window,
2904 string_compose (_("\
2905 %1 was unable to save your session.\n\n\
2906 If you still wish to proceed, please use the\n\n\
2907 \"Don't save now\" option."), PROGRAM_NAME));
2908 pop_back_splash(msg);
2914 _session->remove_pending_capture_state ();
2919 Prompter prompter (true);
2920 prompter.set_name ("Prompter");
2921 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2923 prompter.set_title (_("Snapshot and switch"));
2924 prompter.set_prompt (_("New session name"));
2926 prompter.set_title (_("Take Snapshot"));
2927 prompter.set_prompt (_("Name of new snapshot"));
2931 prompter.set_initial_text (_session->snap_name());
2933 Glib::DateTime tm (g_date_time_new_now_local ());
2934 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2937 bool finished = false;
2939 switch (prompter.run()) {
2940 case RESPONSE_ACCEPT:
2942 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2953 /** Ask the user for a new session name and then rename the session to it.
2957 ARDOUR_UI::rename_session ()
2963 Prompter prompter (true);
2966 prompter.set_name ("Prompter");
2967 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2968 prompter.set_title (_("Rename Session"));
2969 prompter.set_prompt (_("New session name"));
2972 switch (prompter.run()) {
2973 case RESPONSE_ACCEPT:
2975 prompter.get_result (name);
2977 bool do_rename = (name.length() != 0);
2980 char illegal = Session::session_name_is_legal (name);
2983 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2984 "session names may not contain a '%1' character"), illegal));
2989 switch (_session->rename (name)) {
2991 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2992 msg.set_position (WIN_POS_MOUSE);
3000 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3001 msg.set_position (WIN_POS_MOUSE);
3017 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3019 if (!_session || _session->deletion_in_progress()) {
3023 XMLNode* node = new XMLNode (X_("UI"));
3025 WM::Manager::instance().add_state (*node);
3027 node->add_child_nocopy (gui_object_state->get_state());
3029 _session->add_extra_xml (*node);
3031 if (export_video_dialog) {
3032 _session->add_extra_xml (export_video_dialog->get_state());
3035 save_state_canfail (name, switch_to_it);
3039 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3044 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3049 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3054 ARDOUR_UI::primary_clock_value_changed ()
3057 _session->request_locate (primary_clock->current_time ());
3062 ARDOUR_UI::big_clock_value_changed ()
3065 _session->request_locate (big_clock->current_time ());
3070 ARDOUR_UI::secondary_clock_value_changed ()
3073 _session->request_locate (secondary_clock->current_time ());
3077 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3079 if (response == RESPONSE_ACCEPT) {
3080 const string name = d->get_template_name ();
3081 const string desc = d->get_description ();
3083 int failed = _session->save_template (name, desc);
3085 if (failed == -2) { /* file already exists. */
3086 bool overwrite = overwrite_file_dialog (*d,
3087 _("Confirm Template Overwrite"),
3088 _("A template already exists with that name. Do you want to overwrite it?"));
3091 _session->save_template (name, desc, true);
3103 ARDOUR_UI::save_template ()
3105 if (!check_audioengine (_main_window)) {
3109 const std::string desc = SessionMetadata::Metadata()->description ();
3110 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3111 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3115 void ARDOUR_UI::manage_templates ()
3122 ARDOUR_UI::edit_metadata ()
3124 SessionMetadataEditor dialog;
3125 dialog.set_session (_session);
3126 dialog.grab_focus ();
3131 ARDOUR_UI::import_metadata ()
3133 SessionMetadataImporter dialog;
3134 dialog.set_session (_session);
3139 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3141 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3143 MessageDialog msg (str,
3145 Gtk::MESSAGE_WARNING,
3146 Gtk::BUTTONS_YES_NO,
3150 msg.set_name (X_("OpenExistingDialog"));
3151 msg.set_title (_("Open Existing Session"));
3152 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3153 msg.set_position (Gtk::WIN_POS_CENTER);
3154 pop_back_splash (msg);
3156 switch (msg.run()) {
3165 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3167 BusProfile bus_profile;
3170 bus_profile.master_out_channels = 2;
3172 /* get settings from advanced section of NSD */
3173 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3176 // NULL profile: no master, no monitor
3177 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3185 ARDOUR_UI::load_from_application_api (const std::string& path)
3187 /* OS X El Capitan (and probably later) now somehow passes the command
3188 line arguments to an app via the openFile delegate protocol. Ardour
3189 already does its own command line processing, and having both
3190 pathways active causes crashes. So, if the command line was already
3191 set, do nothing here.
3194 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3198 ARDOUR_COMMAND_LINE::session_name = path;
3200 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3202 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3204 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3205 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3206 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3207 * -> SessionDialog is not displayed
3210 if (_session_dialog) {
3211 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3212 std::string session_path = path;
3213 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3214 session_path = Glib::path_get_dirname (session_path);
3216 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3217 _session_dialog->set_provided_session (session_name, session_path);
3218 _session_dialog->response (RESPONSE_NONE);
3219 _session_dialog->hide();
3224 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3225 /* /path/to/foo => /path/to/foo, foo */
3226 rv = load_session (path, basename_nosuffix (path));
3228 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3229 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3232 // if load_session fails -> pop up SessionDialog.
3234 ARDOUR_COMMAND_LINE::session_name = "";
3236 if (get_session_parameters (true, false)) {
3242 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3244 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3246 string session_name;
3247 string session_path;
3248 string template_name;
3250 bool likely_new = false;
3251 bool cancel_not_quit;
3253 /* deal with any existing DIRTY session now, rather than later. don't
3254 * treat a non-dirty session this way, so that it stays visible
3255 * as we bring up the new session dialog.
3258 if (_session && ARDOUR_UI::instance()->video_timeline) {
3259 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3262 /* if there is already a session, relabel the button
3263 on the SessionDialog so that we don't Quit directly
3265 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3267 if (_session && _session->dirty()) {
3268 if (unload_session (false)) {
3269 /* unload cancelled by user */
3272 ARDOUR_COMMAND_LINE::session_name = "";
3275 if (!load_template.empty()) {
3276 should_be_new = true;
3277 template_name = load_template;
3280 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3281 session_path = ARDOUR_COMMAND_LINE::session_name;
3283 if (!session_path.empty()) {
3284 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3285 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3286 /* session/snapshot file, change path to be dir */
3287 session_path = Glib::path_get_dirname (session_path);
3292 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3294 _session_dialog = &session_dialog;
3297 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3299 /* if they named a specific statefile, use it, otherwise they are
3300 just giving a session folder, and we want to use it as is
3301 to find the session.
3304 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3306 if (suffix != string::npos) {
3307 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3308 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3309 session_name = Glib::path_get_basename (session_name);
3311 session_path = ARDOUR_COMMAND_LINE::session_name;
3312 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3317 session_dialog.clear_given ();
3320 if (should_be_new || session_name.empty()) {
3321 /* need the dialog to get info from user */
3323 cerr << "run dialog\n";
3325 switch (session_dialog.run()) {
3326 case RESPONSE_ACCEPT:
3329 /* this is used for async * app->ShouldLoad(). */
3330 continue; // while loop
3333 if (quit_on_cancel) {
3334 ARDOUR_UI::finish ();
3335 Gtkmm2ext::Application::instance()->cleanup();
3337 pthread_cancel_all ();
3338 return -1; // caller is responsible to call exit()
3344 session_dialog.hide ();
3347 /* if we run the startup dialog again, offer more than just "new session" */
3349 should_be_new = false;
3351 session_name = session_dialog.session_name (likely_new);
3352 session_path = session_dialog.session_folder ();
3359 int rv = ARDOUR::inflate_session (session_name,
3360 Config->get_default_session_parent_dir(), session_path, session_name);
3362 MessageDialog msg (session_dialog,
3363 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3368 session_dialog.set_provided_session (session_name, session_path);
3372 // XXX check archive, inflate
3373 string::size_type suffix = session_name.find (statefile_suffix);
3375 if (suffix != string::npos) {
3376 session_name = session_name.substr (0, suffix);
3379 /* this shouldn't happen, but we catch it just in case it does */
3381 if (session_name.empty()) {
3385 if (session_dialog.use_session_template()) {
3386 template_name = session_dialog.session_template_name();
3387 _session_is_new = true;
3390 if (session_name[0] == G_DIR_SEPARATOR ||
3391 #ifdef PLATFORM_WINDOWS
3392 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3394 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3395 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3400 /* absolute path or cwd-relative path specified for session name: infer session folder
3401 from what was given.
3404 session_path = Glib::path_get_dirname (session_name);
3405 session_name = Glib::path_get_basename (session_name);
3409 session_path = session_dialog.session_folder();
3411 char illegal = Session::session_name_is_legal (session_name);
3414 MessageDialog msg (session_dialog,
3415 string_compose (_("To ensure compatibility with various systems\n"
3416 "session names may not contain a '%1' character"),
3419 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3424 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3427 if (likely_new && !nsm) {
3429 std::string existing = Glib::build_filename (session_path, session_name);
3431 if (!ask_about_loading_existing_session (existing)) {
3432 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3437 _session_is_new = false;
3442 pop_back_splash (session_dialog);
3443 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3445 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3449 char illegal = Session::session_name_is_legal(session_name);
3452 pop_back_splash (session_dialog);
3453 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3454 "session names may not contain a '%1' character"), illegal));
3456 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3460 _session_is_new = true;
3463 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3465 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3466 meta_session_setup (template_name.substr (11));
3468 } else if (likely_new && template_name.empty()) {
3470 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3474 ret = load_session (session_path, session_name, template_name);
3477 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3481 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3482 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3486 /* clear this to avoid endless attempts to load the
3490 ARDOUR_COMMAND_LINE::session_name = "";
3494 _session_dialog = NULL;
3500 ARDOUR_UI::close_session()
3502 if (!check_audioengine (_main_window)) {
3506 if (unload_session (true)) {
3510 ARDOUR_COMMAND_LINE::session_name = "";
3512 if (get_session_parameters (true, false)) {
3517 /** @param snap_name Snapshot name (without .ardour suffix).
3518 * @return -2 if the load failed because we are not connected to the AudioEngine.
3521 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3523 /* load_session calls flush_pending() which allows
3524 * GUI interaction and potentially loading another session
3525 * (that was easy via snapshot sidebar).
3526 * Recursing into load_session() from load_session() and recusive
3527 * event loops causes all kind of crashes.
3529 assert (!session_load_in_progress);
3530 if (session_load_in_progress) {
3533 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3535 Session *new_session;
3540 unload_status = unload_session ();
3542 if (unload_status < 0) {
3544 } else if (unload_status > 0) {
3550 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3553 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3556 /* this one is special */
3558 catch (AudioEngine::PortRegistrationFailure const& err) {
3560 MessageDialog msg (err.what(),
3563 Gtk::BUTTONS_CLOSE);
3565 msg.set_title (_("Port Registration Error"));
3566 msg.set_secondary_text (_("Click the Close button to try again."));
3567 msg.set_position (Gtk::WIN_POS_CENTER);
3568 pop_back_splash (msg);
3571 int response = msg.run ();
3576 case RESPONSE_CANCEL:
3583 catch (SessionException const& e) {
3584 MessageDialog msg (string_compose(
3585 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3586 path, snap_name, e.what()),
3591 msg.set_title (_("Loading Error"));
3592 msg.set_position (Gtk::WIN_POS_CENTER);
3593 pop_back_splash (msg);
3605 MessageDialog msg (string_compose(
3606 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3612 msg.set_title (_("Loading Error"));
3613 msg.set_position (Gtk::WIN_POS_CENTER);
3614 pop_back_splash (msg);
3626 list<string> const u = new_session->unknown_processors ();
3628 MissingPluginDialog d (_session, u);
3633 if (!new_session->writable()) {
3634 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3639 msg.set_title (_("Read-only Session"));
3640 msg.set_position (Gtk::WIN_POS_CENTER);
3641 pop_back_splash (msg);
3648 /* Now the session been created, add the transport controls */
3649 new_session->add_controllable(roll_controllable);
3650 new_session->add_controllable(stop_controllable);
3651 new_session->add_controllable(goto_start_controllable);
3652 new_session->add_controllable(goto_end_controllable);
3653 new_session->add_controllable(auto_loop_controllable);
3654 new_session->add_controllable(play_selection_controllable);
3655 new_session->add_controllable(rec_controllable);
3657 set_session (new_session);
3660 _session->set_clean ();
3663 #ifdef WINDOWS_VST_SUPPORT
3664 fst_stop_threading();
3668 Timers::TimerSuspender t;
3672 #ifdef WINDOWS_VST_SUPPORT
3673 fst_start_threading();
3677 if (!mix_template.empty ()) {
3678 /* if mix_template is given, assume this is a new session */
3679 string metascript = Glib::build_filename (mix_template, "template.lua");
3680 meta_session_setup (metascript);
3685 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3686 * which is queued by set_session().
3687 * If session-loading fails we hide it explicitly.
3688 * This covers both cases in a central place.
3697 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3699 Session *new_session;
3702 x = unload_session ();
3710 _session_is_new = true;
3713 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3716 catch (SessionException const& e) {
3717 cerr << "Here are the errors associated with this failed session:\n";
3719 cerr << "---------\n";
3720 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3721 msg.set_title (_("Loading Error"));
3722 msg.set_position (Gtk::WIN_POS_CENTER);
3723 pop_back_splash (msg);
3728 cerr << "Here are the errors associated with this failed session:\n";
3730 cerr << "---------\n";
3731 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3732 msg.set_title (_("Loading Error"));
3733 msg.set_position (Gtk::WIN_POS_CENTER);
3734 pop_back_splash (msg);
3739 /* Give the new session the default GUI state, if such things exist */
3742 n = Config->instant_xml (X_("Editor"));
3744 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3745 new_session->add_instant_xml (*n, false);
3747 n = Config->instant_xml (X_("Mixer"));
3749 new_session->add_instant_xml (*n, false);
3752 n = Config->instant_xml (X_("Preferences"));
3754 new_session->add_instant_xml (*n, false);
3757 /* Put the playhead at 0 and scroll fully left */
3758 n = new_session->instant_xml (X_("Editor"));
3760 n->set_property (X_("playhead"), X_("0"));
3761 n->set_property (X_("left-frame"), X_("0"));
3764 set_session (new_session);
3766 new_session->save_state(new_session->name());
3772 static void _lua_print (std::string s) {
3774 std::cout << "LuaInstance: " << s << "\n";
3776 PBD::info << "LuaInstance: " << s << endmsg;
3779 std::map<std::string, std::string>
3780 ARDOUR_UI::route_setup_info (const std::string& script_path)
3782 std::map<std::string, std::string> rv;
3784 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3789 lua.Print.connect (&_lua_print);
3792 lua_State* L = lua.getState();
3793 LuaInstance::register_classes (L);
3794 LuaBindings::set_session (L, _session);
3795 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3796 lua_setglobal (L, "Editor");
3798 lua.do_command ("function ardour () end");
3799 lua.do_file (script_path);
3802 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3803 if (!fn.isFunction ()) {
3806 luabridge::LuaRef rs = fn ();
3807 if (!rs.isTable ()) {
3810 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3811 if (!i.key().isString()) {
3814 std::string key = i.key().tostring();
3815 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3816 rv[key] = i.value().tostring();
3819 } catch (luabridge::LuaException const& e) {
3820 cerr << "LuaException:" << e.what () << endl;
3826 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3828 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3831 assert (add_route_dialog);
3834 if ((count = add_route_dialog->count()) <= 0) {
3839 lua.Print.connect (&_lua_print);
3842 lua_State* L = lua.getState();
3843 LuaInstance::register_classes (L);
3844 LuaBindings::set_session (L, _session);
3845 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3846 lua_setglobal (L, "Editor");
3848 lua.do_command ("function ardour () end");
3849 lua.do_file (script_path);
3851 luabridge::LuaRef args (luabridge::newTable (L));
3853 args["name"] = add_route_dialog->name_template ();
3854 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3855 args["group"] = add_route_dialog->route_group ();
3856 args["strict_io"] = add_route_dialog->use_strict_io ();
3857 args["instrument"] = add_route_dialog->requested_instrument ();
3858 args["track_mode"] = add_route_dialog->mode ();
3859 args["channels"] = add_route_dialog->channel_count ();
3860 args["how_many"] = count;
3863 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3864 if (fn.isFunction()) {
3867 } catch (luabridge::LuaException const& e) {
3868 cerr << "LuaException:" << e.what () << endl;
3870 display_insufficient_ports_message ();
3875 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3877 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3882 lua.Print.connect (&_lua_print);
3885 lua_State* L = lua.getState();
3886 LuaInstance::register_classes (L);
3887 LuaBindings::set_session (L, _session);
3888 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3889 lua_setglobal (L, "Editor");
3891 lua.do_command ("function ardour () end");
3892 lua.do_file (script_path);
3895 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3896 if (fn.isFunction()) {
3899 } catch (luabridge::LuaException const& e) {
3900 cerr << "LuaException:" << e.what () << endl;
3902 display_insufficient_ports_message ();
3907 ARDOUR_UI::launch_chat ()
3909 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3911 dialog.set_title (_("About the Chat"));
3912 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."));
3914 switch (dialog.run()) {
3916 open_uri("http://webchat.freenode.net/?channels=ardour");
3924 ARDOUR_UI::launch_manual ()
3926 PBD::open_uri (Config->get_tutorial_manual_url());
3930 ARDOUR_UI::launch_reference ()
3932 PBD::open_uri (Config->get_reference_manual_url());
3936 ARDOUR_UI::launch_tracker ()
3938 PBD::open_uri ("http://tracker.ardour.org");
3942 ARDOUR_UI::launch_subscribe ()
3944 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3948 ARDOUR_UI::launch_cheat_sheet ()
3951 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3953 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3958 ARDOUR_UI::launch_website ()
3960 PBD::open_uri ("http://ardour.org");
3964 ARDOUR_UI::launch_website_dev ()
3966 PBD::open_uri ("http://ardour.org/development.html");
3970 ARDOUR_UI::launch_forums ()
3972 PBD::open_uri ("https://community.ardour.org/forums");
3976 ARDOUR_UI::launch_howto_report ()
3978 PBD::open_uri ("http://ardour.org/reporting_bugs");
3982 ARDOUR_UI::loading_message (const std::string& msg)
3984 if (ARDOUR_COMMAND_LINE::no_splash) {
3992 splash->message (msg);
3996 ARDOUR_UI::show_splash ()
4000 splash = new Splash;
4010 ARDOUR_UI::hide_splash ()
4017 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4021 removed = rep.paths.size();
4024 MessageDialog msgd (_main_window,
4025 _("No files were ready for clean-up"),
4029 msgd.set_title (_("Clean-up"));
4030 msgd.set_secondary_text (_("If this seems surprising, \n\
4031 check for any existing snapshots.\n\
4032 These may still include regions that\n\
4033 require some unused files to continue to exist."));
4039 ArdourDialog results (_("Clean-up"), true, false);
4041 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4042 CleanupResultsModelColumns() {
4046 Gtk::TreeModelColumn<std::string> visible_name;
4047 Gtk::TreeModelColumn<std::string> fullpath;
4051 CleanupResultsModelColumns results_columns;
4052 Glib::RefPtr<Gtk::ListStore> results_model;
4053 Gtk::TreeView results_display;
4055 results_model = ListStore::create (results_columns);
4056 results_display.set_model (results_model);
4057 results_display.append_column (list_title, results_columns.visible_name);
4059 results_display.set_name ("CleanupResultsList");
4060 results_display.set_headers_visible (true);
4061 results_display.set_headers_clickable (false);
4062 results_display.set_reorderable (false);
4064 Gtk::ScrolledWindow list_scroller;
4067 Gtk::HBox dhbox; // the hbox for the image and text
4068 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4069 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4071 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4073 const string dead_directory = _session->session_directory().dead_path();
4076 %1 - number of files removed
4077 %2 - location of "dead"
4078 %3 - size of files affected
4079 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4082 const char* bprefix;
4083 double space_adjusted = 0;
4085 if (rep.space < 1000) {
4087 space_adjusted = rep.space;
4088 } else if (rep.space < 1000000) {
4089 bprefix = _("kilo");
4090 space_adjusted = floorf((float)rep.space / 1000.0);
4091 } else if (rep.space < 1000000 * 1000) {
4092 bprefix = _("mega");
4093 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4095 bprefix = _("giga");
4096 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4100 txt.set_markup (string_compose (P_("\
4101 The following file was deleted from %2,\n\
4102 releasing %3 %4bytes of disk space", "\
4103 The following %1 files were deleted from %2,\n\
4104 releasing %3 %4bytes of disk space", removed),
4105 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4107 txt.set_markup (string_compose (P_("\
4108 The following file was not in use and \n\
4109 has been moved to: %2\n\n\
4110 After a restart of %5\n\n\
4111 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4112 will release an additional %3 %4bytes of disk space.\n", "\
4113 The following %1 files were not in use and \n\
4114 have been moved to: %2\n\n\
4115 After a restart of %5\n\n\
4116 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4117 will release an additional %3 %4bytes of disk space.\n", removed),
4118 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4121 dhbox.pack_start (*dimage, true, false, 5);
4122 dhbox.pack_start (txt, true, false, 5);
4124 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4125 TreeModel::Row row = *(results_model->append());
4126 row[results_columns.visible_name] = *i;
4127 row[results_columns.fullpath] = *i;
4130 list_scroller.add (results_display);
4131 list_scroller.set_size_request (-1, 150);
4132 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4134 dvbox.pack_start (dhbox, true, false, 5);
4135 dvbox.pack_start (list_scroller, true, false, 5);
4136 ddhbox.pack_start (dvbox, true, false, 5);
4138 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4139 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4140 results.set_default_response (RESPONSE_CLOSE);
4141 results.set_position (Gtk::WIN_POS_MOUSE);
4143 results_display.show();
4144 list_scroller.show();
4151 //results.get_vbox()->show();
4152 results.set_resizable (false);
4159 ARDOUR_UI::cleanup ()
4161 if (_session == 0) {
4162 /* shouldn't happen: menu item is insensitive */
4167 MessageDialog checker (_("Are you sure you want to clean-up?"),
4169 Gtk::MESSAGE_QUESTION,
4172 checker.set_title (_("Clean-up"));
4174 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4175 ALL undo/redo information will be lost if you clean-up.\n\
4176 Clean-up will move all unused files to a \"dead\" location."));
4178 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4179 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4180 checker.set_default_response (RESPONSE_CANCEL);
4182 checker.set_name (_("CleanupDialog"));
4183 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4184 checker.set_position (Gtk::WIN_POS_MOUSE);
4186 switch (checker.run()) {
4187 case RESPONSE_ACCEPT:
4193 ARDOUR::CleanupReport rep;
4195 editor->prepare_for_cleanup ();
4197 /* do not allow flush until a session is reloaded */
4199 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4201 act->set_sensitive (false);
4204 if (_session->cleanup_sources (rep)) {
4205 editor->finish_cleanup ();
4209 editor->finish_cleanup ();
4212 display_cleanup_results (rep, _("Cleaned Files"), false);
4216 ARDOUR_UI::flush_trash ()
4218 if (_session == 0) {
4219 /* shouldn't happen: menu item is insensitive */
4223 ARDOUR::CleanupReport rep;
4225 if (_session->cleanup_trash_sources (rep)) {
4229 display_cleanup_results (rep, _("deleted file"), true);
4233 ARDOUR_UI::cleanup_peakfiles ()
4235 if (_session == 0) {
4236 /* shouldn't happen: menu item is insensitive */
4240 if (! _session->can_cleanup_peakfiles ()) {
4244 // get all region-views in this session
4246 TrackViewList empty;
4248 editor->get_regions_after(rs, (samplepos_t) 0, empty);
4249 std::list<RegionView*> views = rs.by_layer();
4251 // remove displayed audio-region-views waveforms
4252 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4253 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4254 if (!arv) { continue ; }
4255 arv->delete_waves();
4258 // cleanup peak files:
4259 // - stop pending peakfile threads
4260 // - close peakfiles if any
4261 // - remove peak dir in session
4262 // - setup peakfiles (background thread)
4263 _session->cleanup_peakfiles ();
4265 // re-add waves to ARV
4266 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4267 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4268 if (!arv) { continue ; }
4269 arv->create_waves();
4273 PresentationInfo::order_t
4274 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4276 if (editor->get_selection().tracks.empty()) {
4277 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4280 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4283 we want the new routes to have their order keys set starting from
4284 the highest order key in the selection + 1 (if available).
4287 if (place == RouteDialogs::AfterSelection) {
4288 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4290 order_hint = rtav->route()->presentation_info().order();
4293 } else if (place == RouteDialogs::BeforeSelection) {
4294 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4296 order_hint = rtav->route()->presentation_info().order();
4298 } else if (place == RouteDialogs::First) {
4301 /* leave order_hint at max_order */
4308 ARDOUR_UI::start_duplicate_routes ()
4310 if (!duplicate_routes_dialog) {
4311 duplicate_routes_dialog = new DuplicateRouteDialog;
4314 if (duplicate_routes_dialog->restart (_session)) {
4318 duplicate_routes_dialog->present ();
4322 ARDOUR_UI::add_route ()
4324 if (!add_route_dialog.get (false)) {
4325 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4332 if (add_route_dialog->is_visible()) {
4333 /* we're already doing this */
4337 add_route_dialog->set_position (WIN_POS_MOUSE);
4338 add_route_dialog->present();
4342 ARDOUR_UI::add_route_dialog_response (int r)
4345 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4349 if (!AudioEngine::instance()->running ()) {
4351 case AddRouteDialog::Add:
4352 case AddRouteDialog::AddAndClose:
4357 add_route_dialog->ArdourDialog::on_response (r);
4358 ARDOUR_UI_UTILS::engine_is_running ();
4365 case AddRouteDialog::Add:
4366 add_route_dialog->reset_name_edited ();
4368 case AddRouteDialog::AddAndClose:
4369 add_route_dialog->ArdourDialog::on_response (r);
4372 add_route_dialog->ArdourDialog::on_response (r);
4376 std::string template_path = add_route_dialog->get_template_path();
4377 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4378 meta_route_setup (template_path.substr (11));
4382 if ((count = add_route_dialog->count()) <= 0) {
4386 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4387 const string name_template = add_route_dialog->name_template ();
4388 DisplaySuspender ds;
4390 if (!template_path.empty ()) {
4391 if (add_route_dialog->name_template_is_default ()) {
4392 _session->new_route_from_template (count, order, template_path, string ());
4394 _session->new_route_from_template (count, order, template_path, name_template);
4399 ChanCount input_chan= add_route_dialog->channels ();
4400 ChanCount output_chan;
4401 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4402 RouteGroup* route_group = add_route_dialog->route_group ();
4403 AutoConnectOption oac = Config->get_output_auto_connect();
4404 bool strict_io = add_route_dialog->use_strict_io ();
4406 if (oac & AutoConnectMaster) {
4407 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4408 output_chan.set (DataType::MIDI, 0);
4410 output_chan = input_chan;
4413 /* XXX do something with name template */
4415 Session::ProcessorChangeBlocker pcb (_session);
4417 switch (add_route_dialog->type_wanted()) {
4418 case AddRouteDialog::AudioTrack:
4419 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);
4421 case AddRouteDialog::MidiTrack:
4422 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4424 case AddRouteDialog::MixedTrack:
4425 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4427 case AddRouteDialog::AudioBus:
4428 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4430 case AddRouteDialog::MidiBus:
4431 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4433 case AddRouteDialog::VCAMaster:
4434 _session->vca_manager().create_vca (count, name_template);
4436 case AddRouteDialog::FoldbackBus:
4437 session_add_foldback_bus (count, name_template);
4443 ARDOUR_UI::stop_video_server (bool ask_confirm)
4445 if (!video_server_process && ask_confirm) {
4446 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4448 if (video_server_process) {
4450 ArdourDialog confirm (_("Stop Video-Server"), true);
4451 Label m (_("Do you really want to stop the Video Server?"));
4452 confirm.get_vbox()->pack_start (m, true, true);
4453 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4454 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4455 confirm.show_all ();
4456 if (confirm.run() == RESPONSE_CANCEL) {
4460 delete video_server_process;
4461 video_server_process =0;
4466 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4468 ARDOUR_UI::start_video_server( float_window, true);
4472 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4478 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4479 if (video_server_process) {
4480 popup_error(_("The Video Server is already started."));
4482 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4488 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4490 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4492 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4494 video_server_dialog->set_transient_for (*float_window);
4497 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4498 video_server_dialog->hide();
4500 ResponseType r = (ResponseType) video_server_dialog->run ();
4501 video_server_dialog->hide();
4502 if (r != RESPONSE_ACCEPT) { return false; }
4503 if (video_server_dialog->show_again()) {
4504 Config->set_show_video_server_dialog(false);
4508 std::string icsd_exec = video_server_dialog->get_exec_path();
4509 std::string icsd_docroot = video_server_dialog->get_docroot();
4510 #ifndef PLATFORM_WINDOWS
4511 if (icsd_docroot.empty()) {
4512 icsd_docroot = VideoUtils::video_get_docroot (Config);
4517 #ifdef PLATFORM_WINDOWS
4518 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4519 /* OK, allow all drive letters */
4522 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4523 warning << _("Specified docroot is not an existing directory.") << endmsg;
4526 #ifndef PLATFORM_WINDOWS
4527 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4528 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4529 warning << _("Given Video Server is not an executable file.") << endmsg;
4533 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4534 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4535 warning << _("Given Video Server is not an executable file.") << endmsg;
4541 argp=(char**) calloc(9,sizeof(char*));
4542 argp[0] = strdup(icsd_exec.c_str());
4543 argp[1] = strdup("-P");
4544 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4545 argp[3] = strdup("-p");
4546 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4547 argp[5] = strdup("-C");
4548 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4549 argp[7] = strdup(icsd_docroot.c_str());
4551 stop_video_server();
4553 #ifdef PLATFORM_WINDOWS
4554 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4555 /* OK, allow all drive letters */
4558 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4559 Config->set_video_advanced_setup(false);
4561 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4562 Config->set_video_server_url(url_str);
4563 Config->set_video_server_docroot(icsd_docroot);
4564 Config->set_video_advanced_setup(true);
4567 if (video_server_process) {
4568 delete video_server_process;
4571 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4572 if (video_server_process->start()) {
4573 warning << _("Cannot launch the video-server") << endmsg;
4576 int timeout = 120; // 6 sec
4577 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4578 Glib::usleep (50000);
4580 if (--timeout <= 0 || !video_server_process->is_running()) break;
4583 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4585 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4586 delete video_server_process;
4587 video_server_process = 0;
4595 ARDOUR_UI::add_video (Gtk::Window* float_window)
4601 if (!start_video_server(float_window, false)) {
4602 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4607 add_video_dialog->set_transient_for (*float_window);
4610 if (add_video_dialog->is_visible()) {
4611 /* we're already doing this */
4615 ResponseType r = (ResponseType) add_video_dialog->run ();
4616 add_video_dialog->hide();
4617 if (r != RESPONSE_ACCEPT) { return; }
4619 bool local_file, orig_local_file;
4620 std::string path = add_video_dialog->file_name(local_file);
4622 std::string orig_path = path;
4623 orig_local_file = local_file;
4625 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4627 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4628 warning << string_compose(_("could not open %1"), path) << endmsg;
4631 if (!local_file && path.length() == 0) {
4632 warning << _("no video-file selected") << endmsg;
4636 std::string audio_from_video;
4637 bool detect_ltc = false;
4639 switch (add_video_dialog->import_option()) {
4640 case VTL_IMPORT_TRANSCODE:
4642 TranscodeVideoDialog *transcode_video_dialog;
4643 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4644 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4645 transcode_video_dialog->hide();
4646 if (r != RESPONSE_ACCEPT) {
4647 delete transcode_video_dialog;
4651 audio_from_video = transcode_video_dialog->get_audiofile();
4653 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4656 else if (!audio_from_video.empty()) {
4657 editor->embed_audio_from_video(
4659 video_timeline->get_offset(),
4660 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4663 switch (transcode_video_dialog->import_option()) {
4664 case VTL_IMPORT_TRANSCODED:
4665 path = transcode_video_dialog->get_filename();
4668 case VTL_IMPORT_REFERENCE:
4671 delete transcode_video_dialog;
4674 delete transcode_video_dialog;
4678 case VTL_IMPORT_NONE:
4682 /* strip _session->session_directory().video_path() from video file if possible */
4683 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4684 path=path.substr(_session->session_directory().video_path().size());
4685 if (path.at(0) == G_DIR_SEPARATOR) {
4686 path=path.substr(1);
4690 video_timeline->set_update_session_fps(auto_set_session_fps);
4692 if (video_timeline->video_file_info(path, local_file)) {
4693 XMLNode* node = new XMLNode(X_("Videotimeline"));
4694 node->set_property (X_("Filename"), path);
4695 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4696 node->set_property (X_("LocalFile"), local_file);
4697 if (orig_local_file) {
4698 node->set_property (X_("OriginalVideoFile"), orig_path);
4700 node->remove_property (X_("OriginalVideoFile"));
4702 _session->add_extra_xml (*node);
4703 _session->set_dirty ();
4705 if (!audio_from_video.empty() && detect_ltc) {
4706 std::vector<LTCFileReader::LTCMap> ltc_seq;
4709 /* TODO ask user about TV standard (LTC alignment if any) */
4710 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4711 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4713 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15);
4715 /* TODO seek near end of file, and read LTC until end.
4716 * if it fails to find any LTC samples, scan complete file
4718 * calculate drift of LTC compared to video-duration,
4719 * ask user for reference (timecode from start/mid/end)
4722 // LTCFileReader will have written error messages
4725 ::g_unlink(audio_from_video.c_str());
4727 if (ltc_seq.size() == 0) {
4728 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4730 /* the very first TC in the file is somteimes not aligned properly */
4731 int i = ltc_seq.size() -1;
4732 ARDOUR::sampleoffset_t video_start_offset =
4733 _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4734 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4735 video_timeline->set_offset(video_start_offset);
4739 _session->maybe_update_session_range(
4740 std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0),
4741 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0));
4744 if (add_video_dialog->launch_xjadeo() && local_file) {
4745 editor->set_xjadeo_sensitive(true);
4746 editor->toggle_xjadeo_proc(1);
4748 editor->toggle_xjadeo_proc(0);
4750 editor->toggle_ruler_video(true);
4755 ARDOUR_UI::remove_video ()
4757 video_timeline->close_session();
4758 editor->toggle_ruler_video(false);
4761 video_timeline->set_offset_locked(false);
4762 video_timeline->set_offset(0);
4764 /* delete session state */
4765 XMLNode* node = new XMLNode(X_("Videotimeline"));
4766 _session->add_extra_xml(*node);
4767 node = new XMLNode(X_("Videomonitor"));
4768 _session->add_extra_xml(*node);
4769 node = new XMLNode(X_("Videoexport"));
4770 _session->add_extra_xml(*node);
4771 stop_video_server();
4775 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4777 if (localcacheonly) {
4778 video_timeline->vmon_update();
4780 video_timeline->flush_cache();
4782 editor->queue_visual_videotimeline_update();
4786 ARDOUR_UI::export_video (bool range)
4788 if (ARDOUR::Config->get_show_video_export_info()) {
4789 ExportVideoInfobox infobox (_session);
4790 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4791 if (infobox.show_again()) {
4792 ARDOUR::Config->set_show_video_export_info(false);
4795 case GTK_RESPONSE_YES:
4796 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4802 export_video_dialog->set_session (_session);
4803 export_video_dialog->apply_state(editor->get_selection().time, range);
4804 export_video_dialog->run ();
4805 export_video_dialog->hide ();
4809 ARDOUR_UI::preferences_settings () const
4814 node = _session->instant_xml(X_("Preferences"));
4816 node = Config->instant_xml(X_("Preferences"));
4820 node = new XMLNode (X_("Preferences"));
4827 ARDOUR_UI::mixer_settings () const
4832 node = _session->instant_xml(X_("Mixer"));
4834 node = Config->instant_xml(X_("Mixer"));
4838 node = new XMLNode (X_("Mixer"));
4845 ARDOUR_UI::main_window_settings () const
4850 node = _session->instant_xml(X_("Main"));
4852 node = Config->instant_xml(X_("Main"));
4856 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4857 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4862 node = new XMLNode (X_("Main"));
4869 ARDOUR_UI::editor_settings () const
4874 node = _session->instant_xml(X_("Editor"));
4876 node = Config->instant_xml(X_("Editor"));
4880 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4881 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4886 node = new XMLNode (X_("Editor"));
4893 ARDOUR_UI::keyboard_settings () const
4897 node = Config->extra_xml(X_("Keyboard"));
4900 node = new XMLNode (X_("Keyboard"));
4907 ARDOUR_UI::create_xrun_marker (samplepos_t where)
4910 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4911 _session->locations()->add (location);
4916 ARDOUR_UI::halt_on_xrun_message ()
4918 cerr << "HALT on xrun\n";
4919 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4924 ARDOUR_UI::xrun_handler (samplepos_t where)
4930 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4932 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4933 create_xrun_marker(where);
4936 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4937 halt_on_xrun_message ();
4942 ARDOUR_UI::disk_overrun_handler ()
4944 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4946 if (!have_disk_speed_dialog_displayed) {
4947 have_disk_speed_dialog_displayed = true;
4948 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4949 The disk system on your computer\n\
4950 was not able to keep up with %1.\n\
4952 Specifically, it failed to write data to disk\n\
4953 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4954 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4960 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4961 static MessageDialog *scan_dlg = NULL;
4962 static ProgressBar *scan_pbar = NULL;
4963 static HBox *scan_tbox = NULL;
4964 static Gtk::Button *scan_timeout_button;
4967 ARDOUR_UI::cancel_plugin_scan ()
4969 PluginManager::instance().cancel_plugin_scan();
4973 ARDOUR_UI::cancel_plugin_timeout ()
4975 PluginManager::instance().cancel_plugin_timeout();
4976 scan_timeout_button->set_sensitive (false);
4980 ARDOUR_UI::plugin_scan_timeout (int timeout)
4982 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4986 scan_pbar->set_sensitive (false);
4987 scan_timeout_button->set_sensitive (true);
4988 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4991 scan_pbar->set_sensitive (false);
4992 scan_timeout_button->set_sensitive (false);
4998 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5000 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5004 const bool cancelled = PluginManager::instance().cancelled();
5005 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5006 if (cancelled && scan_dlg->is_mapped()) {
5011 if (cancelled || !can_cancel) {
5016 static Gtk::Button *cancel_button;
5018 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5019 VBox* vbox = scan_dlg->get_vbox();
5020 vbox->set_size_request(400,-1);
5021 scan_dlg->set_title (_("Scanning for plugins"));
5023 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5024 cancel_button->set_name ("EditorGTKButton");
5025 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5026 cancel_button->show();
5028 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5030 scan_tbox = manage( new HBox() );
5032 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5033 scan_timeout_button->set_name ("EditorGTKButton");
5034 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5035 scan_timeout_button->show();
5037 scan_pbar = manage(new ProgressBar());
5038 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5039 scan_pbar->set_text(_("Scan Timeout"));
5042 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5043 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5045 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5048 assert(scan_dlg && scan_tbox && cancel_button);
5050 if (type == X_("closeme")) {
5054 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5057 if (!can_cancel || !cancelled) {
5058 scan_timeout_button->set_sensitive(false);
5060 cancel_button->set_sensitive(can_cancel && !cancelled);
5066 ARDOUR_UI::gui_idle_handler ()
5069 /* due to idle calls, gtk_events_pending() may always return true */
5070 while (gtk_events_pending() && --timeout) {
5071 gtk_main_iteration ();
5076 ARDOUR_UI::disk_underrun_handler ()
5078 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5080 if (!have_disk_speed_dialog_displayed) {
5081 have_disk_speed_dialog_displayed = true;
5082 MessageDialog* msg = new MessageDialog (
5083 _main_window, string_compose (_("The disk system on your computer\n\
5084 was not able to keep up with %1.\n\
5086 Specifically, it failed to read data from disk\n\
5087 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5088 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5094 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5096 have_disk_speed_dialog_displayed = false;
5101 ARDOUR_UI::session_dialog (std::string msg)
5103 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5107 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5114 ARDOUR_UI::pending_state_dialog ()
5116 HBox* hbox = manage (new HBox());
5117 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5118 ArdourDialog dialog (_("Crash Recovery"), true);
5119 Label message (string_compose (_("\
5120 This session appears to have been in the\n\
5121 middle of recording when %1 or\n\
5122 the computer was shutdown.\n\
5124 %1 can recover any captured audio for\n\
5125 you, or it can ignore it. Please decide\n\
5126 what you would like to do.\n"), PROGRAM_NAME));
5127 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5128 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5129 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5130 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5131 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5132 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5133 dialog.set_default_response (RESPONSE_ACCEPT);
5134 dialog.set_position (WIN_POS_CENTER);
5139 switch (dialog.run ()) {
5140 case RESPONSE_ACCEPT:
5148 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
5150 HBox* hbox = new HBox();
5151 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5152 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5153 Label message (string_compose (_("\
5154 This session was created with a sample rate of %1 Hz, but\n\
5155 %2 is currently running at %3 Hz. If you load this session,\n\
5156 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5158 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5159 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5160 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5161 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5162 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5163 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5164 dialog.set_default_response (RESPONSE_ACCEPT);
5165 dialog.set_position (WIN_POS_CENTER);
5170 switch (dialog.run()) {
5171 case RESPONSE_ACCEPT:
5181 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
5183 MessageDialog msg (string_compose (_("\
5184 This session was created with a sample rate of %1 Hz, but\n\
5185 %2 is currently running at %3 Hz.\n\
5186 Audio will be recorded and played at the wrong sample rate.\n\
5187 Re-Configure the Audio Engine in\n\
5188 Menu > Window > Audio/Midi Setup"),
5189 desired, PROGRAM_NAME, actual),
5191 Gtk::MESSAGE_WARNING);
5196 ARDOUR_UI::use_config ()
5198 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5200 set_transport_controllable_state (*node);
5205 ARDOUR_UI::update_transport_clocks (samplepos_t pos)
5207 switch (UIConfiguration::instance().get_primary_clock_delta_mode()) {
5209 primary_clock->set (pos);
5211 case DeltaEditPoint:
5212 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5214 case DeltaOriginMarker:
5216 Location* loc = _session->locations()->clock_origin_location ();
5217 primary_clock->set (pos, false, loc ? loc->start() : 0);
5222 switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) {
5224 secondary_clock->set (pos);
5226 case DeltaEditPoint:
5227 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5229 case DeltaOriginMarker:
5231 Location* loc = _session->locations()->clock_origin_location ();
5232 secondary_clock->set (pos, false, loc ? loc->start() : 0);
5237 if (big_clock_window) {
5238 big_clock->set (pos);
5240 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5245 ARDOUR_UI::record_state_changed ()
5247 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5250 /* why bother - the clock isn't visible */
5254 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5256 if (big_clock_window) {
5257 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5258 big_clock->set_active (true);
5260 big_clock->set_active (false);
5267 ARDOUR_UI::first_idle ()
5270 _session->allow_auto_play (true);
5274 editor->first_idle();
5277 /* in 1 second, hide the splash screen
5279 * Consider hiding it *now*. If a user opens opens a dialog
5280 * during that one second while the splash is still visible,
5281 * the dialog will push-back the splash.
5282 * Closing the dialog later will pop it back.
5284 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5286 Keyboard::set_can_save_keybindings (true);
5291 ARDOUR_UI::store_clock_modes ()
5293 XMLNode* node = new XMLNode(X_("ClockModes"));
5295 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5296 XMLNode* child = new XMLNode (X_("Clock"));
5298 child->set_property (X_("name"), (*x)->name());
5299 child->set_property (X_("mode"), (*x)->mode());
5300 child->set_property (X_("on"), (*x)->on());
5302 node->add_child_nocopy (*child);
5305 _session->add_extra_xml (*node);
5306 _session->set_dirty ();
5310 ARDOUR_UI::setup_profile ()
5312 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5313 Profile->set_small_screen ();
5316 if (g_getenv ("TRX")) {
5317 Profile->set_trx ();
5320 if (g_getenv ("MIXBUS")) {
5321 Profile->set_mixbus ();
5326 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5328 MissingFileDialog dialog (s, str, type);
5333 int result = dialog.run ();
5340 return 1; // quit entire session load
5343 result = dialog.get_action ();
5349 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5351 AmbiguousFileDialog dialog (file, hits);
5358 return dialog.get_which ();
5361 /** Allocate our thread-local buffers */
5363 ARDOUR_UI::get_process_buffers ()
5365 _process_thread->get_buffers ();
5368 /** Drop our thread-local buffers */
5370 ARDOUR_UI::drop_process_buffers ()
5372 _process_thread->drop_buffers ();
5376 ARDOUR_UI::feedback_detected ()
5378 _feedback_exists = true;
5382 ARDOUR_UI::successful_graph_sort ()
5384 _feedback_exists = false;
5388 ARDOUR_UI::midi_panic ()
5391 _session->midi_panic();
5396 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5398 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5399 const char* end_big = "</span>";
5400 const char* start_mono = "<tt>";
5401 const char* end_mono = "</tt>";
5403 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5404 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5405 "From now on, use the backup copy with older versions of %3"),
5406 xml_path, backup_path, PROGRAM_NAME,
5408 start_mono, end_mono), true);
5414 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5416 using namespace Menu_Helpers;
5418 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5419 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5420 i->set_active (editor_meter->meter_type () == type);
5424 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5426 using namespace Gtk::Menu_Helpers;
5428 Gtk::Menu* m = manage (new Menu);
5429 MenuList& items = m->items ();
5431 RadioMenuItem::Group group;
5433 _suspend_editor_meter_callbacks = true;
5434 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5435 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5436 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5437 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5438 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5439 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5440 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5441 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5442 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5443 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5444 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5446 m->popup (ev->button, ev->time);
5447 _suspend_editor_meter_callbacks = false;
5451 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5453 if (ev->button == 3 && editor_meter) {
5454 popup_editor_meter_menu (ev);
5461 ARDOUR_UI::reset_peak_display ()
5463 if (!_session || !_session->master_out() || !editor_meter) return;
5464 editor_meter->clear_meters();
5465 editor_meter_max_peak = -INFINITY;
5466 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5470 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5472 if (!_session || !_session->master_out()) return;
5473 if (group == _session->master_out()->route_group()) {
5474 reset_peak_display ();
5479 ARDOUR_UI::reset_route_peak_display (Route* route)
5481 if (!_session || !_session->master_out()) return;
5482 if (_session->master_out().get() == route) {
5483 reset_peak_display ();
5488 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5490 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5491 audio_midi_setup->set_position (WIN_POS_CENTER);
5493 if (desired_sample_rate != 0) {
5494 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5495 audio_midi_setup->try_autostart ();
5496 if (ARDOUR::AudioEngine::instance()->running()) {
5503 int response = audio_midi_setup->run();
5505 case Gtk::RESPONSE_DELETE_EVENT:
5506 // after latency callibration engine may run,
5507 // Running() signal was emitted, but dialog will not
5508 // have emitted a response. The user needs to close
5509 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5510 if (!AudioEngine::instance()->running()) {
5515 if (!AudioEngine::instance()->running()) {
5518 audio_midi_setup->hide ();
5526 ARDOUR_UI::transport_numpad_timeout ()
5528 _numpad_locate_happening = false;
5529 if (_numpad_timeout_connection.connected() )
5530 _numpad_timeout_connection.disconnect();
5535 ARDOUR_UI::transport_numpad_decimal ()
5537 _numpad_timeout_connection.disconnect();
5539 if (_numpad_locate_happening) {
5540 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5541 _numpad_locate_happening = false;
5543 _pending_locate_num = 0;
5544 _numpad_locate_happening = true;
5545 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5550 ARDOUR_UI::transport_numpad_event (int num)
5552 if ( _numpad_locate_happening ) {
5553 _pending_locate_num = _pending_locate_num*10 + num;
5556 case 0: toggle_roll(false, false); break;
5557 case 1: transport_rewind(1); break;
5558 case 2: transport_forward(1); break;
5559 case 3: transport_record(true); break;
5560 case 4: toggle_session_auto_loop(); break;
5561 case 5: transport_record(false); toggle_session_auto_loop(); break;
5562 case 6: toggle_punch(); break;
5563 case 7: toggle_click(); break;
5564 case 8: toggle_auto_return(); break;
5565 case 9: toggle_follow_edits(); break;
5571 ARDOUR_UI::set_flat_buttons ()
5573 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5577 ARDOUR_UI::audioengine_became_silent ()
5579 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5581 Gtk::MESSAGE_WARNING,
5585 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5587 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5588 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5589 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5590 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5591 Gtk::HBox pay_button_box;
5592 Gtk::HBox subscribe_button_box;
5594 pay_button_box.pack_start (pay_button, true, false);
5595 subscribe_button_box.pack_start (subscribe_button, true, false);
5597 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 */
5599 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5600 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5602 msg.get_vbox()->pack_start (pay_label);
5603 msg.get_vbox()->pack_start (pay_button_box);
5604 msg.get_vbox()->pack_start (subscribe_label);
5605 msg.get_vbox()->pack_start (subscribe_button_box);
5607 msg.get_vbox()->show_all ();
5609 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5610 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5611 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5616 case Gtk::RESPONSE_YES:
5617 AudioEngine::instance()->reset_silence_countdown ();
5620 case Gtk::RESPONSE_NO:
5622 save_state_canfail ("");
5626 case Gtk::RESPONSE_CANCEL:
5628 /* don't reset, save session and exit */
5634 ARDOUR_UI::hide_application ()
5636 Application::instance ()-> hide ();
5640 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5642 /* icons, titles, WM stuff */
5644 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5646 if (window_icons.empty()) {
5647 Glib::RefPtr<Gdk::Pixbuf> icon;
5648 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5649 window_icons.push_back (icon);
5651 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5652 window_icons.push_back (icon);
5654 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5655 window_icons.push_back (icon);
5657 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5658 window_icons.push_back (icon);
5662 if (!window_icons.empty()) {
5663 window.set_default_icon_list (window_icons);
5666 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5668 if (!name.empty()) {
5672 window.set_title (title.get_string());
5673 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5675 window.set_flags (CAN_FOCUS);
5676 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5678 /* This is a hack to ensure that GTK-accelerators continue to
5679 * work. Once we switch over to entirely native bindings, this will be
5680 * unnecessary and should be removed
5682 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5684 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5685 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5686 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5687 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5691 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5693 Gtkmm2ext::Bindings* bindings = 0;
5694 Gtk::Window* window = 0;
5696 /* until we get ardour bindings working, we are not handling key
5700 if (ev->type != GDK_KEY_PRESS) {
5704 if (event_window == &_main_window) {
5706 window = event_window;
5708 /* find current tab contents */
5710 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5712 /* see if it uses the ardour binding system */
5715 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5718 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5722 window = event_window;
5724 /* see if window uses ardour binding system */
5726 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5729 /* An empty binding set is treated as if it doesn't exist */
5731 if (bindings && bindings->empty()) {
5735 return key_press_focus_accelerator_handler (*window, ev, bindings);
5738 static Gtkmm2ext::Bindings*
5739 get_bindings_from_widget_heirarchy (GtkWidget** w)
5744 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5747 *w = gtk_widget_get_parent (*w);
5750 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5754 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5756 GtkWindow* win = window.gobj();
5757 GtkWidget* focus = gtk_window_get_focus (win);
5758 GtkWidget* binding_widget = focus;
5759 bool special_handling_of_unmodified_accelerators = false;
5760 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5764 /* some widget has keyboard focus */
5766 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5768 /* A particular kind of focusable widget currently has keyboard
5769 * focus. All unmodified key events should go to that widget
5770 * first and not be used as an accelerator by default
5773 special_handling_of_unmodified_accelerators = true;
5777 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5778 if (focus_bindings) {
5779 bindings = focus_bindings;
5780 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5785 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",
5788 Gtkmm2ext::show_gdk_event_state (ev->state),
5789 special_handling_of_unmodified_accelerators,
5790 Keyboard::some_magic_widget_has_focus(),
5792 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5793 ((ev->state & mask) ? "yes" : "no"),
5794 window.get_title()));
5796 /* This exists to allow us to override the way GTK handles
5797 key events. The normal sequence is:
5799 a) event is delivered to a GtkWindow
5800 b) accelerators/mnemonics are activated
5801 c) if (b) didn't handle the event, propagate to
5802 the focus widget and/or focus chain
5804 The problem with this is that if the accelerators include
5805 keys without modifiers, such as the space bar or the
5806 letter "e", then pressing the key while typing into
5807 a text entry widget results in the accelerator being
5808 activated, instead of the desired letter appearing
5811 There is no good way of fixing this, but this
5812 represents a compromise. The idea is that
5813 key events involving modifiers (not Shift)
5814 get routed into the activation pathway first, then
5815 get propagated to the focus widget if necessary.
5817 If the key event doesn't involve modifiers,
5818 we deliver to the focus widget first, thus allowing
5819 it to get "normal text" without interference
5822 Of course, this can also be problematic: if there
5823 is a widget with focus, then it will swallow
5824 all "normal text" accelerators.
5828 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5830 /* no special handling or there are modifiers in effect: accelerate first */
5832 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5833 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5834 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5836 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5837 KeyboardKey k (ev->state, ev->keyval);
5841 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5843 if (bindings->activate (k, Bindings::Press)) {
5844 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5848 if (binding_widget) {
5849 binding_widget = gtk_widget_get_parent (binding_widget);
5850 if (binding_widget) {
5851 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5860 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5862 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5863 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5867 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5869 if (gtk_window_propagate_key_event (win, ev)) {
5870 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5876 /* no modifiers, propagate first */
5878 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5880 if (gtk_window_propagate_key_event (win, ev)) {
5881 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5885 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5886 KeyboardKey k (ev->state, ev->keyval);
5890 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5893 if (bindings->activate (k, Bindings::Press)) {
5894 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5898 if (binding_widget) {
5899 binding_widget = gtk_widget_get_parent (binding_widget);
5900 if (binding_widget) {
5901 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5910 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5912 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5913 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5918 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5923 ARDOUR_UI::load_bindings ()
5925 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5926 error << _("Global keybindings are missing") << endmsg;
5931 ARDOUR_UI::cancel_solo ()
5934 _session->cancel_all_solo ();
5939 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5941 /* this resets focus to the first focusable parent of the given widget,
5942 * or, if there is no focusable parent, cancels focus in the toplevel
5943 * window that the given widget is packed into (if there is one).
5950 Gtk::Widget* top = w->get_toplevel();
5952 if (!top || !top->is_toplevel()) {
5956 w = w->get_parent ();
5960 if (w->is_toplevel()) {
5961 /* Setting the focus widget to a Gtk::Window causes all
5962 * subsequent calls to ::has_focus() on the nominal
5963 * focus widget in that window to return
5964 * false. Workaround: never set focus to the toplevel
5970 if (w->get_can_focus ()) {
5971 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5972 win->set_focus (*w);
5975 w = w->get_parent ();
5978 if (top == &_main_window) {
5982 /* no focusable parent found, cancel focus in top level window.
5983 C++ API cannot be used for this. Thanks, references.
5986 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);
5991 ARDOUR_UI::monitor_dim_all ()
5993 boost::shared_ptr<Route> mon = _session->monitor_out ();
5997 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
5999 Glib::RefPtr<Action> act = global_actions.find_action (X_("Monitor"), "monitor-dim-all");
6000 assert (act); Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
6001 assert (tact); _monitor->set_dim_all (tact->get_active());
6005 ARDOUR_UI::monitor_cut_all ()
6007 boost::shared_ptr<Route> mon = _session->monitor_out ();
6011 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6013 Glib::RefPtr<Action> act = global_actions.find_action (X_("Monitor"), "monitor-cut-all");
6014 assert (act); Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
6015 assert (tact); _monitor->set_cut_all (tact->get_active());
6019 ARDOUR_UI::monitor_mono ()
6021 boost::shared_ptr<Route> mon = _session->monitor_out ();
6025 boost::shared_ptr<ARDOUR::MonitorProcessor> _monitor = mon->monitor_control ();
6027 Glib::RefPtr<Action> act = global_actions.find_action (X_("Monitor"), "monitor-mono");
6028 assert (act); Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
6029 assert (tact);_monitor->set_mono (tact->get_active());