2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/types_convert.h"
65 #include "pbd/file_utils.h"
66 #include "pbd/localtime_r.h"
67 #include "pbd/pthread_utils.h"
68 #include "pbd/replace_all.h"
69 #include "pbd/scoped_file_descriptor.h"
70 #include "pbd/xml++.h"
72 #include "gtkmm2ext/application.h"
73 #include "gtkmm2ext/bindings.h"
74 #include "gtkmm2ext/gtk_ui.h"
75 #include "gtkmm2ext/utils.h"
76 #include "gtkmm2ext/click_box.h"
77 #include "gtkmm2ext/fastmeter.h"
78 #include "gtkmm2ext/popup.h"
79 #include "gtkmm2ext/window_title.h"
81 #include "ardour/ardour.h"
82 #include "ardour/audio_backend.h"
83 #include "ardour/audio_track.h"
84 #include "ardour/audioengine.h"
85 #include "ardour/audiofilesource.h"
86 #include "ardour/automation_watch.h"
87 #include "ardour/diskstream.h"
88 #include "ardour/filename_extensions.h"
89 #include "ardour/filesystem_paths.h"
90 #include "ardour/ltc_file_reader.h"
91 #include "ardour/midi_track.h"
92 #include "ardour/port.h"
93 #include "ardour/plugin_manager.h"
94 #include "ardour/process_thread.h"
95 #include "ardour/profile.h"
96 #include "ardour/recent_sessions.h"
97 #include "ardour/record_enable_control.h"
98 #include "ardour/session_directory.h"
99 #include "ardour/session_route.h"
100 #include "ardour/session_state_utils.h"
101 #include "ardour/session_utils.h"
102 #include "ardour/source_factory.h"
103 #include "ardour/slave.h"
104 #include "ardour/system_exec.h"
105 #include "ardour/track.h"
106 #include "ardour/vca_manager.h"
107 #include "ardour/utils.h"
109 #include "LuaBridge/LuaBridge.h"
111 #ifdef WINDOWS_VST_SUPPORT
114 #ifdef AUDIOUNIT_SUPPORT
115 #include "ardour/audio_unit.h"
118 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
123 #include "timecode/time.h"
125 typedef uint64_t microseconds_t;
129 #include "enums_convert.h"
131 #include "add_route_dialog.h"
132 #include "ambiguous_file_dialog.h"
133 #include "ardour_ui.h"
134 #include "audio_clock.h"
135 #include "audio_region_view.h"
136 #include "big_clock_window.h"
137 #include "bundle_manager.h"
138 #include "duplicate_routes_dialog.h"
140 #include "engine_dialog.h"
141 #include "export_video_dialog.h"
142 #include "export_video_infobox.h"
143 #include "gain_meter.h"
144 #include "global_port_matrix.h"
145 #include "gui_object.h"
146 #include "gui_thread.h"
147 #include "idleometer.h"
148 #include "keyboard.h"
149 #include "keyeditor.h"
150 #include "location_ui.h"
151 #include "lua_script_manager.h"
152 #include "luawindow.h"
153 #include "main_clock.h"
154 #include "missing_file_dialog.h"
155 #include "missing_plugin_dialog.h"
156 #include "mixer_ui.h"
157 #include "meterbridge.h"
158 #include "meter_patterns.h"
159 #include "mouse_cursors.h"
162 #include "pingback.h"
163 #include "processor_box.h"
164 #include "prompter.h"
165 #include "public_editor.h"
166 #include "rc_option_editor.h"
167 #include "route_time_axis.h"
168 #include "route_params_ui.h"
169 #include "save_as_dialog.h"
170 #include "script_selector.h"
171 #include "session_archive_dialog.h"
172 #include "session_dialog.h"
173 #include "session_metadata_dialog.h"
174 #include "session_option_editor.h"
175 #include "speaker_dialog.h"
178 #include "time_axis_view_item.h"
179 #include "time_info_box.h"
182 #include "utils_videotl.h"
183 #include "video_server_dialog.h"
184 #include "add_video_dialog.h"
185 #include "transcode_video_dialog.h"
187 #include "pbd/i18n.h"
189 using namespace ARDOUR;
190 using namespace ARDOUR_UI_UTILS;
192 using namespace Gtkmm2ext;
195 using namespace Editing;
197 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
199 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
200 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
203 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
205 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
206 "Would you like these files to be copied and used for %1 %2.x?\n\n"
207 "(This will require you to restart %1.)"),
208 PROGRAM_NAME, PROGRAM_VERSION, version),
209 false, /* no markup */
212 true /* modal, though it hardly matters since it is the only window */
215 msg.set_default_response (Gtk::RESPONSE_YES);
218 return (msg.run() == Gtk::RESPONSE_YES);
222 libxml_generic_error_func (void* /* parsing_context*/,
230 vsnprintf (buf, sizeof (buf), msg, ap);
231 error << buf << endmsg;
236 libxml_structured_error_func (void* /* parsing_context*/,
244 replace_all (msg, "\n", "");
247 if (err->file && err->line) {
248 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
251 error << ':' << err->int2;
256 error << X_("XML error: ") << msg << endmsg;
262 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
263 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
264 , session_loaded (false)
265 , gui_object_state (new GUIObjectState)
266 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
267 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
268 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
270 , global_actions (X_("global"))
271 , ignore_dual_punch (false)
272 , main_window_visibility (0)
277 , _mixer_on_top (false)
278 , _initial_verbose_plugin_scan (false)
279 , first_time_engine_run (true)
280 , secondary_clock_spacer (0)
281 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
282 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
283 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
284 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
285 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
286 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
287 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
288 , auto_input_button (ArdourButton::led_default_elements)
290 , auto_return_button (ArdourButton::led_default_elements)
291 , follow_edits_button (ArdourButton::led_default_elements)
292 , auditioning_alert_button (_("Audition"))
293 , solo_alert_button (_("Solo"))
294 , feedback_alert_button (_("Feedback"))
295 , error_alert_button ( ArdourButton::just_led_default_elements )
297 , editor_meter_peak_display()
298 , _suspend_editor_meter_callbacks (false)
299 , _numpad_locate_happening (false)
300 , _session_is_new (false)
301 , last_key_press_time (0)
305 , rc_option_editor (0)
306 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
307 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
308 , about (X_("about"), _("About"))
309 , location_ui (X_("locations"), S_("Ranges|Locations"))
310 , route_params (X_("inspector"), _("Tracks and Busses"))
311 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
312 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
313 , lua_script_window (X_("script-manager"), _("Script Manager"))
314 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
315 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
316 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
317 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
318 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
319 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
320 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
321 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
322 , video_server_process (0)
324 , have_configure_timeout (false)
325 , last_configure_time (0)
327 , have_disk_speed_dialog_displayed (false)
328 , _status_bar_visibility (X_("status-bar"))
329 , _feedback_exists (false)
330 , _log_not_acknowledged (LogLevelNone)
331 , duplicate_routes_dialog (0)
332 , editor_visibility_button (S_("Window|Editor"))
333 , mixer_visibility_button (S_("Window|Mixer"))
334 , prefs_visibility_button (S_("Window|Preferences"))
336 Gtkmm2ext::init (localedir);
338 UIConfiguration::instance().post_gui_init ();
340 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
342 /* "touch" the been-here-before path now that config has been migrated */
343 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
345 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
347 /* configuration was modified, exit immediately */
352 if (string (VERSIONSTRING).find (".pre") != string::npos) {
353 /* check this is not being run from ./ardev etc. */
354 if (!running_from_source_tree ()) {
355 pre_release_dialog ();
359 if (theArdourUI == 0) {
363 /* track main window visibility */
365 main_window_visibility = new VisibilityTracker (_main_window);
367 /* stop libxml from spewing to stdout/stderr */
369 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
370 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
372 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
373 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
374 UIConfiguration::instance().map_parameters (pc);
376 roll_button.set_controllable (roll_controllable);
377 stop_button.set_controllable (stop_controllable);
378 goto_start_button.set_controllable (goto_start_controllable);
379 goto_end_button.set_controllable (goto_end_controllable);
380 auto_loop_button.set_controllable (auto_loop_controllable);
381 play_selection_button.set_controllable (play_selection_controllable);
382 rec_button.set_controllable (rec_controllable);
384 roll_button.set_name ("transport button");
385 stop_button.set_name ("transport button");
386 goto_start_button.set_name ("transport button");
387 goto_end_button.set_name ("transport button");
388 auto_loop_button.set_name ("transport button");
389 play_selection_button.set_name ("transport button");
390 rec_button.set_name ("transport recenable button");
391 midi_panic_button.set_name ("transport button");
393 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
394 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
396 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
398 /* handle dialog requests */
400 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
402 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
404 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
406 /* handle Audio/MIDI setup when session requires it */
408 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
410 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
412 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
414 /* handle sr mismatch with a dialog - cross-thread from engine */
415 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
417 /* handle requests to quit (coming from JACK session) */
419 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
421 /* tell the user about feedback */
423 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
424 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
426 /* handle requests to deal with missing files */
428 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
430 /* and ambiguous files */
432 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
434 /* also plugin scan messages */
435 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
436 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
438 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
440 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
443 /* lets get this party started */
445 setup_gtk_ardour_enums ();
448 SessionEvent::create_per_thread_pool ("GUI", 4096);
450 /* we like keyboards */
452 keyboard = new ArdourKeyboard(*this);
454 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
456 keyboard->set_state (*node, Stateful::loading_state_version);
459 UIConfiguration::instance().reset_dpi ();
461 TimeAxisViewItem::set_constant_heights ();
463 /* Set this up so that our window proxies can register actions */
465 ActionManager::init ();
467 /* The following must happen after ARDOUR::init() so that Config is set up */
469 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
472 key_editor.set_state (*ui_xml, 0);
473 session_option_editor.set_state (*ui_xml, 0);
474 speaker_config_window.set_state (*ui_xml, 0);
475 about.set_state (*ui_xml, 0);
476 add_route_dialog.set_state (*ui_xml, 0);
477 add_video_dialog.set_state (*ui_xml, 0);
478 route_params.set_state (*ui_xml, 0);
479 bundle_manager.set_state (*ui_xml, 0);
480 location_ui.set_state (*ui_xml, 0);
481 big_clock_window.set_state (*ui_xml, 0);
482 audio_port_matrix.set_state (*ui_xml, 0);
483 midi_port_matrix.set_state (*ui_xml, 0);
484 export_video_dialog.set_state (*ui_xml, 0);
485 lua_script_window.set_state (*ui_xml, 0);
486 idleometer.set_state (*ui_xml, 0);
489 /* Separate windows */
491 WM::Manager::instance().register_window (&key_editor);
492 WM::Manager::instance().register_window (&session_option_editor);
493 WM::Manager::instance().register_window (&speaker_config_window);
494 WM::Manager::instance().register_window (&about);
495 WM::Manager::instance().register_window (&add_route_dialog);
496 WM::Manager::instance().register_window (&add_video_dialog);
497 WM::Manager::instance().register_window (&route_params);
498 WM::Manager::instance().register_window (&audio_midi_setup);
499 WM::Manager::instance().register_window (&export_video_dialog);
500 WM::Manager::instance().register_window (&lua_script_window);
501 WM::Manager::instance().register_window (&bundle_manager);
502 WM::Manager::instance().register_window (&location_ui);
503 WM::Manager::instance().register_window (&big_clock_window);
504 WM::Manager::instance().register_window (&audio_port_matrix);
505 WM::Manager::instance().register_window (&midi_port_matrix);
506 WM::Manager::instance().register_window (&idleometer);
508 /* do not retain position for add route dialog */
509 add_route_dialog.set_state_mask (WindowProxy::Size);
511 /* Trigger setting up the color scheme and loading the GTK RC file */
513 UIConfiguration::instance().load_rc_file (false);
515 _process_thread = new ProcessThread ();
516 _process_thread->init ();
518 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
524 ARDOUR_UI::pre_release_dialog ()
526 ArdourDialog d (_("Pre-Release Warning"), true, false);
527 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
529 Label* label = manage (new Label);
530 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
531 There are still several issues and bugs to be worked on,\n\
532 as well as general workflow improvements, before this can be considered\n\
533 release software. So, a few guidelines:\n\
535 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
536 though it may be so, depending on your workflow.\n\
537 2) Please wait for a helpful writeup of new features.\n\
538 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
539 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
540 making sure to note the product version number as 5.0-pre.\n\
541 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
542 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
543 can get there directly from within the program via the Help->Chat menu option.\n\
545 Full information on all the above can be found on the support page at\n\
547 http://ardour.org/support\n\
548 "), PROGRAM_NAME, VERSIONSTRING));
550 d.get_vbox()->set_border_width (12);
551 d.get_vbox()->pack_start (*label, false, false, 12);
552 d.get_vbox()->show_all ();
557 GlobalPortMatrixWindow*
558 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
563 return new GlobalPortMatrixWindow (_session, type);
567 ARDOUR_UI::attach_to_engine ()
569 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
570 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
574 ARDOUR_UI::engine_stopped ()
576 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
577 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
578 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
579 update_sample_rate (0);
584 ARDOUR_UI::engine_running ()
586 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
587 if (first_time_engine_run) {
589 first_time_engine_run = false;
593 _session->reset_xrun_count ();
595 update_disk_space ();
597 update_xrun_count ();
598 update_sample_rate (AudioEngine::instance()->sample_rate());
599 update_timecode_format ();
600 update_peak_thread_work ();
601 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
602 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
606 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
608 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
609 /* we can't rely on the original string continuing to exist when we are called
610 again in the GUI thread, so make a copy and note that we need to
613 char *copy = strdup (reason);
614 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
618 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
619 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
621 update_sample_rate (0);
625 /* if the reason is a non-empty string, it means that the backend was shutdown
626 rather than just Ardour.
629 if (strlen (reason)) {
630 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
632 msgstr = string_compose (_("\
633 The audio backend has either been shutdown or it\n\
634 disconnected %1 because %1\n\
635 was not fast enough. Try to restart\n\
636 the audio backend and save the session."), PROGRAM_NAME);
639 MessageDialog msg (_main_window, msgstr);
640 pop_back_splash (msg);
644 free (const_cast<char*> (reason));
649 ARDOUR_UI::post_engine ()
651 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
653 #ifdef AUDIOUNIT_SUPPORT
655 if (AUPluginInfo::au_get_crashlog(au_msg)) {
656 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
657 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
658 info << au_msg << endmsg;
662 ARDOUR::init_post_engine ();
664 /* connect to important signals */
666 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
667 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
668 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
669 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
670 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
672 if (setup_windows ()) {
673 throw failed_constructor ();
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) {
692 vector<string> paths;
693 vector<string> labels;
694 vector<string> tooltips;
696 vector<Glib::RefPtr<Gtk::Action> > actions;
698 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
700 vector<string>::iterator k;
701 vector<string>::iterator p;
703 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
708 cout << *p << " => " << *k << endl;
712 halt_connection.disconnect ();
713 AudioEngine::instance()->stop ();
717 /* this being a GUI and all, we want peakfiles */
719 AudioFileSource::set_build_peakfiles (true);
720 AudioFileSource::set_build_missing_peakfiles (true);
722 /* set default clock modes */
724 primary_clock->set_mode (AudioClock::Timecode);
725 secondary_clock->set_mode (AudioClock::BBT);
727 /* start the time-of-day-clock */
730 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
731 update_wall_clock ();
732 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
737 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
738 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
739 Config->map_parameters (pc);
741 UIConfiguration::instance().map_parameters (pc);
745 ARDOUR_UI::~ARDOUR_UI ()
747 UIConfiguration::instance().save_state();
751 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
752 // don't bother at 'real' exit. the OS cleans up for us.
753 delete big_clock; big_clock = 0;
754 delete primary_clock; primary_clock = 0;
755 delete secondary_clock; secondary_clock = 0;
756 delete _process_thread; _process_thread = 0;
757 delete time_info_box; time_info_box = 0;
758 delete meterbridge; meterbridge = 0;
759 delete luawindow; luawindow = 0;
760 delete editor; editor = 0;
761 delete mixer; mixer = 0;
762 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
764 delete gui_object_state; gui_object_state = 0;
765 delete main_window_visibility;
766 FastMeter::flush_pattern_cache ();
767 PixFader::flush_pattern_cache ();
771 /* Small trick to flush main-thread event pool.
772 * Other thread-pools are destroyed at pthread_exit(),
773 * but tmain thread termination is too late to trigger Pool::~Pool()
775 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.
776 delete ev->event_pool();
781 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
783 if (Splash::instance()) {
784 Splash::instance()->pop_back_for (win);
789 ARDOUR_UI::configure_timeout ()
791 if (last_configure_time == 0) {
792 /* no configure events yet */
796 /* force a gap of 0.5 seconds since the last configure event
799 if (get_microseconds() - last_configure_time < 500000) {
802 have_configure_timeout = false;
803 save_ardour_state ();
809 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
811 if (have_configure_timeout) {
812 last_configure_time = get_microseconds();
814 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
815 have_configure_timeout = true;
822 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
826 if (node.get_property ("roll", str)){
827 roll_controllable->set_id (str);
829 if (node.get_property ("stop", str)) {
830 stop_controllable->set_id (str);
832 if (node.get_property ("goto-start", str)) {
833 goto_start_controllable->set_id (str);
835 if (node.get_property ("goto-end", str)) {
836 goto_end_controllable->set_id (str);
838 if (node.get_property ("auto-loop", str)) {
839 auto_loop_controllable->set_id (str);
841 if (node.get_property ("play-selection", str)) {
842 play_selection_controllable->set_id (str);
844 if (node.get_property ("rec", str)) {
845 rec_controllable->set_id (str);
847 if (node.get_property ("shuttle", str)) {
848 shuttle_box.controllable()->set_id (str);
853 ARDOUR_UI::get_transport_controllable_state ()
855 XMLNode* node = new XMLNode(X_("TransportControllables"));
857 node->set_property (X_("roll"), roll_controllable->id());
858 node->set_property (X_("stop"), stop_controllable->id());
859 node->set_property (X_("goto_start"), goto_start_controllable->id());
860 node->set_property (X_("goto_end"), goto_end_controllable->id());
861 node->set_property (X_("auto_loop"), auto_loop_controllable->id());
862 node->set_property (X_("play_selection"), play_selection_controllable->id());
863 node->set_property (X_("rec"), rec_controllable->id());
864 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
870 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
873 _session->save_state (snapshot_name);
878 ARDOUR_UI::autosave_session ()
880 if (g_main_depth() > 1) {
881 /* inside a recursive main loop,
882 give up because we may not be able to
888 if (!Config->get_periodic_safety_backups()) {
893 _session->maybe_write_autosave();
900 ARDOUR_UI::session_dirty_changed ()
907 ARDOUR_UI::update_autosave ()
909 if (_session && _session->dirty()) {
910 if (_autosave_connection.connected()) {
911 _autosave_connection.disconnect();
914 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
915 Config->get_periodic_safety_backup_interval() * 1000);
918 if (_autosave_connection.connected()) {
919 _autosave_connection.disconnect();
925 ARDOUR_UI::check_announcements ()
928 string _annc_filename;
931 _annc_filename = PROGRAM_NAME "_announcements_osx_";
932 #elif defined PLATFORM_WINDOWS
933 _annc_filename = PROGRAM_NAME "_announcements_windows_";
935 _annc_filename = PROGRAM_NAME "_announcements_linux_";
937 _annc_filename.append (VERSIONSTRING);
939 _announce_string = "";
941 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
942 FILE* fin = g_fopen (path.c_str(), "rb");
944 while (!feof (fin)) {
947 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
950 _announce_string.append (tmp, len);
955 pingback (VERSIONSTRING, path);
960 _hide_splash (gpointer arg)
962 ((ARDOUR_UI*)arg)->hide_splash();
967 ARDOUR_UI::starting ()
969 Application* app = Application::instance ();
971 bool brand_new_user = ArdourStartup::required ();
973 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
974 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
976 if (ARDOUR_COMMAND_LINE::check_announcements) {
977 check_announcements ();
982 /* we need to create this early because it may need to set the
983 * audio backend end up.
987 audio_midi_setup.get (true);
989 std::cerr << "audio-midi engine setup failed."<< std::endl;
993 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
994 nsm = new NSM_Client;
995 if (!nsm->init (nsm_url)) {
996 /* the ardour executable may have different names:
998 * waf's obj.target for distro versions: eg ardour4, ardourvst4
999 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1000 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1002 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1004 const char *process_name = g_getenv ("ARDOUR_SELF");
1005 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1008 // wait for announce reply from nsm server
1009 for ( i = 0; i < 5000; ++i) {
1013 if (nsm->is_active()) {
1018 error << _("NSM server did not announce itself") << endmsg;
1021 // wait for open command from nsm server
1022 for ( i = 0; i < 5000; ++i) {
1024 Glib::usleep (1000);
1025 if (nsm->client_id ()) {
1031 error << _("NSM: no client ID provided") << endmsg;
1035 if (_session && nsm) {
1036 _session->set_nsm_state( nsm->is_active() );
1038 error << _("NSM: no session created") << endmsg;
1042 // nsm requires these actions disabled
1043 vector<string> action_names;
1044 action_names.push_back("SaveAs");
1045 action_names.push_back("Rename");
1046 action_names.push_back("New");
1047 action_names.push_back("Open");
1048 action_names.push_back("Recent");
1049 action_names.push_back("Close");
1051 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1052 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1054 act->set_sensitive (false);
1061 error << _("NSM: initialization failed") << endmsg;
1067 if (brand_new_user) {
1068 _initial_verbose_plugin_scan = true;
1073 _initial_verbose_plugin_scan = false;
1074 switch (s.response ()) {
1075 case Gtk::RESPONSE_OK:
1082 // TODO: maybe IFF brand_new_user
1083 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1084 std::string dspd (Config->get_default_session_parent_dir());
1085 Searchpath ds (ARDOUR::ardour_data_search_path());
1086 ds.add_subdirectory_to_paths ("sessions");
1087 vector<string> demos;
1088 find_files_matching_pattern (demos, ds, "*.tar.xz");
1090 ARDOUR::RecentSessions rs;
1091 ARDOUR::read_recent_sessions (rs);
1093 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1094 /* "demo-session" must be inside "demo-session.tar.xz"
1097 std::string name = basename_nosuffix (basename_nosuffix (*i));
1098 std::string path = Glib::build_filename (dspd, name);
1099 /* skip if session-dir already exists */
1100 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1103 /* skip sessions that are already in 'recent'.
1104 * eg. a new user changed <session-default-dir> shorly after installation
1106 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1107 if ((*r).first == name) {
1112 PBD::FileArchive ar (*i);
1113 if (0 == ar.inflate (dspd)) {
1114 store_recent_sessions (name, path);
1115 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1121 #ifdef NO_PLUGIN_STATE
1123 ARDOUR::RecentSessions rs;
1124 ARDOUR::read_recent_sessions (rs);
1126 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1128 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1130 /* already used Ardour, have sessions ... warn about plugin state */
1132 ArdourDialog d (_("Free/Demo Version Warning"), true);
1134 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1135 CheckButton c (_("Don't warn me about this again"));
1137 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"),
1138 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1139 _("It will not restore OR save any plugin settings"),
1140 _("If you load an existing session with plugin settings\n"
1141 "they will not be used and will be lost."),
1142 _("To get full access to updates without this limitation\n"
1143 "consider becoming a subscriber for a low cost every month.")));
1144 l.set_justify (JUSTIFY_CENTER);
1146 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1148 d.get_vbox()->pack_start (l, true, true);
1149 d.get_vbox()->pack_start (b, false, false, 12);
1150 d.get_vbox()->pack_start (c, false, false, 12);
1152 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1153 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1157 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1159 if (d.run () != RESPONSE_OK) {
1165 /* go get a session */
1167 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1169 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1170 std::cerr << "Cannot get session parameters."<< std::endl;
1177 WM::Manager::instance().show_visible ();
1179 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1180 * editor window, and we may want stuff to be hidden.
1182 _status_bar_visibility.update ();
1184 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1186 if (splash && splash->is_visible()) {
1187 // in 1 second, hide the splash screen
1188 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1191 /* all other dialogs are created conditionally */
1197 ARDOUR_UI::check_memory_locking ()
1199 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1200 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1204 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1206 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1208 struct rlimit limits;
1210 long pages, page_size;
1212 size_t pages_len=sizeof(pages);
1213 if ((page_size = getpagesize()) < 0 ||
1214 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1216 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1221 ram = (int64_t) pages * (int64_t) page_size;
1224 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1228 if (limits.rlim_cur != RLIM_INFINITY) {
1230 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1234 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1235 "This might cause %1 to run out of memory before your system "
1236 "runs out of memory. \n\n"
1237 "You can view the memory limit with 'ulimit -l', "
1238 "and it is normally controlled by %2"),
1241 X_("/etc/login.conf")
1243 X_(" /etc/security/limits.conf")
1247 msg.set_default_response (RESPONSE_OK);
1249 VBox* vbox = msg.get_vbox();
1251 CheckButton cb (_("Do not show this window again"));
1252 hbox.pack_start (cb, true, false);
1253 vbox->pack_start (hbox);
1258 pop_back_splash (msg);
1262 if (cb.get_active()) {
1263 XMLNode node (X_("no-memory-warning"));
1264 Config->add_instant_xml (node);
1269 #endif // !__APPLE__
1274 ARDOUR_UI::queue_finish ()
1276 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1280 ARDOUR_UI::idle_finish ()
1283 return false; /* do not call again */
1290 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1292 if (_session->dirty()) {
1293 vector<string> actions;
1294 actions.push_back (_("Don't quit"));
1295 actions.push_back (_("Just quit"));
1296 actions.push_back (_("Save and quit"));
1297 switch (ask_about_saving_session(actions)) {
1302 /* use the default name */
1303 if (save_state_canfail ("")) {
1304 /* failed - don't quit */
1305 MessageDialog msg (_main_window,
1306 string_compose (_("\
1307 %1 was unable to save your session.\n\n\
1308 If you still wish to quit, please use the\n\n\
1309 \"Just quit\" option."), PROGRAM_NAME));
1310 pop_back_splash(msg);
1320 second_connection.disconnect ();
1321 point_one_second_connection.disconnect ();
1322 point_zero_something_second_connection.disconnect();
1323 fps_connection.disconnect();
1326 delete ARDOUR_UI::instance()->video_timeline;
1327 ARDOUR_UI::instance()->video_timeline = NULL;
1328 stop_video_server();
1330 /* Save state before deleting the session, as that causes some
1331 windows to be destroyed before their visible state can be
1334 save_ardour_state ();
1336 if (key_editor.get (false)) {
1337 key_editor->disconnect ();
1340 close_all_dialogs ();
1343 _session->set_clean ();
1344 _session->remove_pending_capture_state ();
1349 halt_connection.disconnect ();
1350 AudioEngine::instance()->stop ();
1351 #ifdef WINDOWS_VST_SUPPORT
1352 fst_stop_threading();
1358 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1360 ArdourDialog window (_("Unsaved Session"));
1361 Gtk::HBox dhbox; // the hbox for the image and text
1362 Gtk::Label prompt_label;
1363 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1367 assert (actions.size() >= 3);
1369 window.add_button (actions[0], RESPONSE_REJECT);
1370 window.add_button (actions[1], RESPONSE_APPLY);
1371 window.add_button (actions[2], RESPONSE_ACCEPT);
1373 window.set_default_response (RESPONSE_ACCEPT);
1375 Gtk::Button noquit_button (msg);
1376 noquit_button.set_name ("EditorGTKButton");
1380 if (_session->snap_name() == _session->name()) {
1381 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?"),
1382 _session->snap_name());
1384 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?"),
1385 _session->snap_name());
1388 prompt_label.set_text (prompt);
1389 prompt_label.set_name (X_("PrompterLabel"));
1390 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1392 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1393 dhbox.set_homogeneous (false);
1394 dhbox.pack_start (*dimage, false, false, 5);
1395 dhbox.pack_start (prompt_label, true, false, 5);
1396 window.get_vbox()->pack_start (dhbox);
1398 window.set_name (_("Prompter"));
1399 window.set_modal (true);
1400 window.set_resizable (false);
1403 prompt_label.show();
1408 ResponseType r = (ResponseType) window.run();
1413 case RESPONSE_ACCEPT: // save and get out of here
1415 case RESPONSE_APPLY: // get out of here
1426 ARDOUR_UI::every_second ()
1429 update_xrun_count ();
1430 update_buffer_load ();
1431 update_disk_space ();
1432 update_timecode_format ();
1433 update_peak_thread_work ();
1435 if (nsm && nsm->is_active ()) {
1438 if (!_was_dirty && _session->dirty ()) {
1442 else if (_was_dirty && !_session->dirty ()){
1450 ARDOUR_UI::every_point_one_seconds ()
1452 // TODO get rid of this..
1453 // ShuttleControl is updated directly via TransportStateChange signal
1457 ARDOUR_UI::every_point_zero_something_seconds ()
1459 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1461 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1462 float mpeak = editor_meter->update_meters();
1463 if (mpeak > editor_meter_max_peak) {
1464 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1465 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1472 ARDOUR_UI::set_fps_timeout_connection ()
1474 unsigned int interval = 40;
1475 if (!_session) return;
1476 if (_session->timecode_frames_per_second() != 0) {
1477 /* ideally we'll use a select() to sleep and not accumulate
1478 * idle time to provide a regular periodic signal.
1479 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1480 * However, that'll require a dedicated thread and cross-thread
1481 * signals to the GUI Thread..
1483 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1484 * _session->frame_rate() / _session->nominal_frame_rate()
1485 / _session->timecode_frames_per_second()
1487 #ifdef PLATFORM_WINDOWS
1488 // the smallest windows scheduler time-slice is ~15ms.
1489 // periodic GUI timeouts shorter than that will cause
1490 // WaitForSingleObject to spinlock (100% of one CPU Core)
1491 // and gtk never enters idle mode.
1492 // also changing timeBeginPeriod(1) does not affect that in
1493 // any beneficial way, so we just limit the max rate for now.
1494 interval = std::max(30u, interval); // at most ~33Hz.
1496 interval = std::max(8u, interval); // at most 120Hz.
1499 fps_connection.disconnect();
1500 Timers::set_fps_interval (interval);
1504 ARDOUR_UI::update_sample_rate (framecnt_t)
1508 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1510 if (!AudioEngine::instance()->connected()) {
1512 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1516 framecnt_t rate = AudioEngine::instance()->sample_rate();
1519 /* no sample rate available */
1520 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1523 if (fmod (rate, 1000.0) != 0.0) {
1524 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1525 (float) rate / 1000.0f,
1526 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1528 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1530 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1534 sample_rate_label.set_markup (buf);
1538 ARDOUR_UI::update_format ()
1541 format_label.set_text ("");
1546 s << _("File:") << X_(" <span foreground=\"green\">");
1548 switch (_session->config.get_native_file_header_format ()) {
1580 switch (_session->config.get_native_file_data_format ()) {
1594 format_label.set_markup (s.str ());
1598 ARDOUR_UI::update_xrun_count ()
1602 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1603 should also be changed.
1607 const unsigned int x = _session->get_xrun_count ();
1609 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1611 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1614 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1616 xrun_label.set_markup (buf);
1617 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1621 ARDOUR_UI::update_cpu_load ()
1625 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1626 should also be changed.
1629 double const c = AudioEngine::instance()->get_dsp_load ();
1630 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1631 cpu_load_label.set_markup (buf);
1635 ARDOUR_UI::update_peak_thread_work ()
1638 const int c = SourceFactory::peak_work_queue_length ();
1640 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1641 peak_thread_work_label.set_markup (buf);
1643 peak_thread_work_label.set_markup (X_(""));
1648 ARDOUR_UI::update_buffer_load ()
1652 uint32_t const playback = _session ? _session->playback_load () : 100;
1653 uint32_t const capture = _session ? _session->capture_load () : 100;
1655 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1656 should also be changed.
1662 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1663 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1664 playback <= 5 ? X_("red") : X_("green"),
1666 capture <= 5 ? X_("red") : X_("green"),
1670 buffer_load_label.set_markup (buf);
1672 buffer_load_label.set_text ("");
1677 ARDOUR_UI::count_recenabled_streams (Route& route)
1679 Track* track = dynamic_cast<Track*>(&route);
1680 if (track && track->rec_enable_control()->get_value()) {
1681 rec_enabled_streams += track->n_inputs().n_total();
1686 ARDOUR_UI::update_disk_space()
1688 if (_session == 0) {
1692 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1694 framecnt_t fr = _session->frame_rate();
1697 /* skip update - no SR available */
1702 /* Available space is unknown */
1703 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1704 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1705 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1707 rec_enabled_streams = 0;
1708 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1710 framecnt_t frames = opt_frames.get_value_or (0);
1712 if (rec_enabled_streams) {
1713 frames /= rec_enabled_streams;
1720 hrs = frames / (fr * 3600);
1723 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1725 frames -= hrs * fr * 3600;
1726 mins = frames / (fr * 60);
1727 frames -= mins * fr * 60;
1730 bool const low = (hrs == 0 && mins <= 30);
1734 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1735 low ? X_("red") : X_("green"),
1741 disk_space_label.set_markup (buf);
1745 ARDOUR_UI::update_timecode_format ()
1751 TimecodeSlave* tcslave;
1752 SyncSource sync_src = Config->get_sync_source();
1754 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1755 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1760 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1761 matching ? X_("green") : X_("red"),
1762 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1764 snprintf (buf, sizeof (buf), "TC: n/a");
1767 timecode_format_label.set_markup (buf);
1771 ARDOUR_UI::update_wall_clock ()
1775 static int last_min = -1;
1778 tm_now = localtime (&now);
1779 if (last_min != tm_now->tm_min) {
1781 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1782 wall_clock_label.set_text (buf);
1783 last_min = tm_now->tm_min;
1790 ARDOUR_UI::open_recent_session ()
1792 bool can_return = (_session != 0);
1794 SessionDialog recent_session_dialog;
1798 ResponseType r = (ResponseType) recent_session_dialog.run ();
1801 case RESPONSE_ACCEPT:
1805 recent_session_dialog.hide();
1812 recent_session_dialog.hide();
1816 std::string path = recent_session_dialog.session_folder();
1817 std::string state = recent_session_dialog.session_name (should_be_new);
1819 if (should_be_new == true) {
1823 _session_is_new = false;
1825 if (load_session (path, state) == 0) {
1831 if (splash && splash->is_visible()) {
1832 // in 1 second, hide the splash screen
1833 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1838 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1840 if (!AudioEngine::instance()->connected()) {
1841 MessageDialog msg (parent, string_compose (
1842 _("%1 is not connected to any audio backend.\n"
1843 "You cannot open or close sessions in this condition"),
1845 pop_back_splash (msg);
1853 ARDOUR_UI::open_session ()
1855 if (!check_audioengine (_main_window)) {
1859 /* ardour sessions are folders */
1860 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1861 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1862 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1863 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1866 string session_parent_dir = Glib::path_get_dirname(_session->path());
1867 open_session_selector.set_current_folder(session_parent_dir);
1869 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1872 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1874 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1875 string default_session_folder = Config->get_default_session_parent_dir();
1876 open_session_selector.add_shortcut_folder (default_session_folder);
1878 catch (Glib::Error & e) {
1879 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1882 FileFilter session_filter;
1883 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1884 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1885 open_session_selector.add_filter (session_filter);
1887 FileFilter archive_filter;
1888 archive_filter.add_pattern (X_("*.tar.xz"));
1889 archive_filter.set_name (_("Session Archives"));
1891 open_session_selector.add_filter (archive_filter);
1893 open_session_selector.set_filter (session_filter);
1895 int response = open_session_selector.run();
1896 open_session_selector.hide ();
1898 if (response == Gtk::RESPONSE_CANCEL) {
1902 string session_path = open_session_selector.get_filename();
1906 if (session_path.length() > 0) {
1907 int rv = ARDOUR::inflate_session (session_path,
1908 Config->get_default_session_parent_dir(), path, name);
1910 _session_is_new = false;
1911 load_session (path, name);
1914 MessageDialog msg (_main_window,
1915 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1918 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1919 _session_is_new = isnew;
1920 load_session (path, name);
1926 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1932 _session->vca_manager().create_vca (n, name_template);
1936 ARDOUR_UI::session_add_mixed_track (
1937 const ChanCount& input,
1938 const ChanCount& output,
1939 RouteGroup* route_group,
1941 const string& name_template,
1943 PluginInfoPtr instrument,
1944 Plugin::PresetRecord* pset,
1945 ARDOUR::PresentationInfo::order_t order)
1947 if (_session == 0) {
1948 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1952 if (Profile->get_mixbus ()) {
1957 list<boost::shared_ptr<MidiTrack> > tracks;
1958 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1960 if (tracks.size() != how_many) {
1961 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1966 display_insufficient_ports_message ();
1972 ARDOUR_UI::session_add_midi_bus (
1973 RouteGroup* route_group,
1975 const string& name_template,
1977 PluginInfoPtr instrument,
1978 Plugin::PresetRecord* pset,
1979 ARDOUR::PresentationInfo::order_t order)
1981 if (_session == 0) {
1982 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1986 if (Profile->get_mixbus ()) {
1992 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
1993 if (routes.size() != how_many) {
1994 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1999 display_insufficient_ports_message ();
2005 ARDOUR_UI::session_add_midi_route (
2007 RouteGroup* route_group,
2009 const string& name_template,
2011 PluginInfoPtr instrument,
2012 Plugin::PresetRecord* pset,
2013 ARDOUR::PresentationInfo::order_t order)
2015 ChanCount one_midi_channel;
2016 one_midi_channel.set (DataType::MIDI, 1);
2019 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2021 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2026 ARDOUR_UI::session_add_audio_route (
2028 int32_t input_channels,
2029 int32_t output_channels,
2030 ARDOUR::TrackMode mode,
2031 RouteGroup* route_group,
2033 string const & name_template,
2035 ARDOUR::PresentationInfo::order_t order)
2037 list<boost::shared_ptr<AudioTrack> > tracks;
2040 if (_session == 0) {
2041 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2047 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2049 if (tracks.size() != how_many) {
2050 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2056 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2058 if (routes.size() != how_many) {
2059 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2066 display_insufficient_ports_message ();
2071 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2072 (*i)->set_strict_io (true);
2074 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2075 (*i)->set_strict_io (true);
2081 ARDOUR_UI::display_insufficient_ports_message ()
2083 MessageDialog msg (_main_window,
2084 string_compose (_("There are insufficient ports available\n\
2085 to create a new track or bus.\n\
2086 You should save %1, exit and\n\
2087 restart with more ports."), PROGRAM_NAME));
2088 pop_back_splash (msg);
2093 ARDOUR_UI::transport_goto_start ()
2096 _session->goto_start();
2098 /* force displayed area in editor to start no matter
2099 what "follow playhead" setting is.
2103 editor->center_screen (_session->current_start_frame ());
2109 ARDOUR_UI::transport_goto_zero ()
2112 _session->request_locate (0);
2114 /* force displayed area in editor to start no matter
2115 what "follow playhead" setting is.
2119 editor->reset_x_origin (0);
2125 ARDOUR_UI::transport_goto_wallclock ()
2127 if (_session && editor) {
2134 localtime_r (&now, &tmnow);
2136 framecnt_t frame_rate = _session->frame_rate();
2138 if (frame_rate == 0) {
2139 /* no frame rate available */
2143 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2144 frames += tmnow.tm_min * (60 * frame_rate);
2145 frames += tmnow.tm_sec * frame_rate;
2147 _session->request_locate (frames, _session->transport_rolling ());
2149 /* force displayed area in editor to start no matter
2150 what "follow playhead" setting is.
2154 editor->center_screen (frames);
2160 ARDOUR_UI::transport_goto_end ()
2163 framepos_t const frame = _session->current_end_frame();
2164 _session->request_locate (frame);
2166 /* force displayed area in editor to start no matter
2167 what "follow playhead" setting is.
2171 editor->center_screen (frame);
2177 ARDOUR_UI::transport_stop ()
2183 if (_session->is_auditioning()) {
2184 _session->cancel_audition ();
2188 _session->request_stop (false, true);
2191 /** Check if any tracks are record enabled. If none are, record enable all of them.
2192 * @return true if track record-enabled status was changed, false otherwise.
2195 ARDOUR_UI::trx_record_enable_all_tracks ()
2201 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2202 bool none_record_enabled = true;
2204 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2205 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2208 if (t->rec_enable_control()->get_value()) {
2209 none_record_enabled = false;
2214 if (none_record_enabled) {
2215 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2218 return none_record_enabled;
2222 ARDOUR_UI::transport_record (bool roll)
2225 switch (_session->record_status()) {
2226 case Session::Disabled:
2227 if (_session->ntracks() == 0) {
2228 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."));
2232 if (Profile->get_trx()) {
2233 roll = trx_record_enable_all_tracks ();
2235 _session->maybe_enable_record ();
2240 case Session::Recording:
2242 _session->request_stop();
2244 _session->disable_record (false, true);
2248 case Session::Enabled:
2249 _session->disable_record (false, true);
2255 ARDOUR_UI::transport_roll ()
2261 if (_session->is_auditioning()) {
2266 if (_session->config.get_external_sync()) {
2267 switch (Config->get_sync_source()) {
2271 /* transport controlled by the master */
2277 bool rolling = _session->transport_rolling();
2279 if (_session->get_play_loop()) {
2281 /* If loop playback is not a mode, then we should cancel
2282 it when this action is requested. If it is a mode
2283 we just leave it in place.
2286 if (!Config->get_loop_is_mode()) {
2287 /* XXX it is not possible to just leave seamless loop and keep
2288 playing at present (nov 4th 2009)
2290 if (!Config->get_seamless_loop()) {
2291 /* stop loop playback and stop rolling */
2292 _session->request_play_loop (false, true);
2293 } else if (rolling) {
2294 /* stop loop playback but keep rolling */
2295 _session->request_play_loop (false, false);
2299 } else if (_session->get_play_range () ) {
2300 /* stop playing a range if we currently are */
2301 _session->request_play_range (0, true);
2305 _session->request_transport_speed (1.0f);
2310 ARDOUR_UI::get_smart_mode() const
2312 return ( editor->get_smart_mode() );
2317 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2323 if (_session->is_auditioning()) {
2324 _session->cancel_audition ();
2328 if (_session->config.get_external_sync()) {
2329 switch (Config->get_sync_source()) {
2333 /* transport controlled by the master */
2338 bool rolling = _session->transport_rolling();
2339 bool affect_transport = true;
2341 if (rolling && roll_out_of_bounded_mode) {
2342 /* drop out of loop/range playback but leave transport rolling */
2343 if (_session->get_play_loop()) {
2344 if (_session->actively_recording()) {
2346 /* just stop using the loop, then actually stop
2349 _session->request_play_loop (false, affect_transport);
2352 if (Config->get_seamless_loop()) {
2353 /* the disk buffers contain copies of the loop - we can't
2354 just keep playing, so stop the transport. the user
2355 can restart as they wish.
2357 affect_transport = true;
2359 /* disk buffers are normal, so we can keep playing */
2360 affect_transport = false;
2362 _session->request_play_loop (false, affect_transport);
2364 } else if (_session->get_play_range ()) {
2365 affect_transport = false;
2366 _session->request_play_range (0, true);
2370 if (affect_transport) {
2372 _session->request_stop (with_abort, true);
2374 } else if (!with_abort) { /* with_abort == true means the
2375 * command was intended to stop
2376 * transport, not start.
2379 /* the only external sync condition we can be in here
2380 * would be Engine (JACK) sync, in which case we still
2384 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2385 _session->request_play_range (&editor->get_selection().time, true);
2386 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2388 _session->request_transport_speed (1.0f);
2394 ARDOUR_UI::toggle_session_auto_loop ()
2400 Location * looploc = _session->locations()->auto_loop_location();
2406 if (_session->get_play_loop()) {
2408 /* looping enabled, our job is to disable it */
2410 _session->request_play_loop (false);
2414 /* looping not enabled, our job is to enable it.
2416 loop-is-NOT-mode: this action always starts the transport rolling.
2417 loop-IS-mode: this action simply sets the loop play mechanism, but
2418 does not start transport.
2420 if (Config->get_loop_is_mode()) {
2421 _session->request_play_loop (true, false);
2423 _session->request_play_loop (true, true);
2427 //show the loop markers
2428 looploc->set_hidden (false, this);
2432 ARDOUR_UI::transport_play_selection ()
2438 editor->play_selection ();
2442 ARDOUR_UI::transport_play_preroll ()
2447 editor->play_with_preroll ();
2451 ARDOUR_UI::transport_rec_preroll ()
2456 editor->rec_with_preroll ();
2460 ARDOUR_UI::transport_rec_count_in ()
2465 editor->rec_with_count_in ();
2469 ARDOUR_UI::transport_rewind (int option)
2471 float current_transport_speed;
2474 current_transport_speed = _session->transport_speed();
2476 if (current_transport_speed >= 0.0f) {
2479 _session->request_transport_speed (-1.0f);
2482 _session->request_transport_speed (-4.0f);
2485 _session->request_transport_speed (-0.5f);
2490 _session->request_transport_speed (current_transport_speed * 1.5f);
2496 ARDOUR_UI::transport_forward (int option)
2502 float current_transport_speed = _session->transport_speed();
2504 if (current_transport_speed <= 0.0f) {
2507 _session->request_transport_speed (1.0f);
2510 _session->request_transport_speed (4.0f);
2513 _session->request_transport_speed (0.5f);
2518 _session->request_transport_speed (current_transport_speed * 1.5f);
2523 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2529 boost::shared_ptr<Route> r;
2531 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2533 boost::shared_ptr<Track> t;
2535 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2536 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2542 ARDOUR_UI::map_transport_state ()
2545 auto_loop_button.unset_active_state ();
2546 play_selection_button.unset_active_state ();
2547 roll_button.unset_active_state ();
2548 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2549 layered_button.set_sensitive (false);
2553 shuttle_box.map_transport_state ();
2555 float sp = _session->transport_speed();
2561 if (_session->get_play_range()) {
2563 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2564 roll_button.unset_active_state ();
2565 auto_loop_button.unset_active_state ();
2567 } else if (_session->get_play_loop ()) {
2569 auto_loop_button.set_active (true);
2570 play_selection_button.set_active (false);
2571 if (Config->get_loop_is_mode()) {
2572 roll_button.set_active (true);
2574 roll_button.set_active (false);
2579 roll_button.set_active (true);
2580 play_selection_button.set_active (false);
2581 auto_loop_button.set_active (false);
2584 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2585 /* light up both roll and play-selection if they are joined */
2586 roll_button.set_active (true);
2587 play_selection_button.set_active (true);
2589 layered_button.set_sensitive (!_session->actively_recording ());
2591 stop_button.set_active (false);
2595 layered_button.set_sensitive (true);
2596 stop_button.set_active (true);
2597 roll_button.set_active (false);
2598 play_selection_button.set_active (false);
2599 if (Config->get_loop_is_mode ()) {
2600 auto_loop_button.set_active (_session->get_play_loop());
2602 auto_loop_button.set_active (false);
2604 update_disk_space ();
2609 ARDOUR_UI::blink_handler (bool blink_on)
2611 transport_rec_enable_blink (blink_on);
2612 sync_blink (blink_on);
2614 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2617 error_blink (blink_on);
2618 solo_blink (blink_on);
2619 audition_blink (blink_on);
2620 feedback_blink (blink_on);
2624 ARDOUR_UI::update_clocks ()
2626 if (!_session) return;
2628 if (editor && !editor->dragging_playhead()) {
2629 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2634 ARDOUR_UI::start_clocking ()
2636 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2637 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2639 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2644 ARDOUR_UI::stop_clocking ()
2646 clock_signal_connection.disconnect ();
2650 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2654 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2656 label->set_text (buf);
2657 bar->set_fraction (fraction);
2659 /* process events, redraws, etc. */
2661 while (gtk_events_pending()) {
2662 gtk_main_iteration ();
2665 return true; /* continue with save-as */
2669 ARDOUR_UI::save_session_as ()
2675 if (!save_as_dialog) {
2676 save_as_dialog = new SaveAsDialog;
2679 save_as_dialog->set_name (_session->name());
2681 int response = save_as_dialog->run ();
2683 save_as_dialog->hide ();
2686 case Gtk::RESPONSE_OK:
2695 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2696 sa.new_name = save_as_dialog->new_name ();
2697 sa.switch_to = save_as_dialog->switch_to();
2698 sa.copy_media = save_as_dialog->copy_media();
2699 sa.copy_external = save_as_dialog->copy_external();
2700 sa.include_media = save_as_dialog->include_media ();
2702 /* Only bother with a progress dialog if we're going to copy
2703 media into the save-as target. Without that choice, this
2704 will be very fast because we're only talking about a few kB's to
2705 perhaps a couple of MB's of data.
2708 ArdourDialog progress_dialog (_("Save As"), true);
2711 if (sa.include_media && sa.copy_media) {
2713 Gtk::Label* label = manage (new Gtk::Label());
2714 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2716 progress_dialog.get_vbox()->pack_start (*label);
2717 progress_dialog.get_vbox()->pack_start (*progress_bar);
2719 progress_bar->show ();
2721 /* this signal will be emitted from within this, the calling thread,
2722 * after every file is copied. It provides information on percentage
2723 * complete (in terms of total data to copy), the number of files
2724 * copied so far, and the total number to copy.
2727 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2729 progress_dialog.show_all ();
2730 progress_dialog.present ();
2733 if (_session->save_as (sa)) {
2735 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2739 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2740 * the trick is this: if the new session was copy with media included,
2741 * then Session::save_as() will have already done a neat trick to avoid
2742 * us having to unload and load the new state. But if the media was not
2743 * included, then this is required (it avoids us having to otherwise
2744 * drop all references to media (sources).
2747 if (!sa.include_media && sa.switch_to) {
2748 unload_session (false);
2749 load_session (sa.final_session_folder_name, sa.new_name);
2755 ARDOUR_UI::archive_session ()
2763 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2765 SessionArchiveDialog sad;
2766 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2767 int response = sad.run ();
2769 if (response != Gtk::RESPONSE_OK) {
2774 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2775 MessageDialog msg (_("Session Archiving failed."));
2781 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2785 struct tm local_time;
2788 localtime_r (&n, &local_time);
2789 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2791 save_state (timebuf, switch_to_it);
2796 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2800 prompter.get_result (snapname);
2802 bool do_save = (snapname.length() != 0);
2805 char illegal = Session::session_name_is_legal(snapname);
2807 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2808 "snapshot names may not contain a '%1' character"), illegal));
2814 vector<std::string> p;
2815 get_state_files_in_directory (_session->session_directory().root_path(), p);
2816 vector<string> n = get_file_names_no_extension (p);
2818 if (find (n.begin(), n.end(), snapname) != n.end()) {
2820 do_save = overwrite_file_dialog (prompter,
2821 _("Confirm Snapshot Overwrite"),
2822 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2826 save_state (snapname, switch_to_it);
2836 /** Ask the user for the name of a new snapshot and then take it.
2840 ARDOUR_UI::snapshot_session (bool switch_to_it)
2842 ArdourPrompter prompter (true);
2844 prompter.set_name ("Prompter");
2845 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2847 prompter.set_title (_("Snapshot and switch"));
2848 prompter.set_prompt (_("New session name"));
2850 prompter.set_title (_("Take Snapshot"));
2851 prompter.set_prompt (_("Name of new snapshot"));
2855 prompter.set_initial_text (_session->snap_name());
2857 Glib::DateTime tm (g_date_time_new_now_local ());
2858 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2861 bool finished = false;
2863 switch (prompter.run()) {
2864 case RESPONSE_ACCEPT:
2866 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2877 /** Ask the user for a new session name and then rename the session to it.
2881 ARDOUR_UI::rename_session ()
2887 ArdourPrompter prompter (true);
2890 prompter.set_name ("Prompter");
2891 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2892 prompter.set_title (_("Rename Session"));
2893 prompter.set_prompt (_("New session name"));
2896 switch (prompter.run()) {
2897 case RESPONSE_ACCEPT:
2899 prompter.get_result (name);
2901 bool do_rename = (name.length() != 0);
2904 char illegal = Session::session_name_is_legal (name);
2907 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2908 "session names may not contain a '%1' character"), illegal));
2913 switch (_session->rename (name)) {
2915 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2916 msg.set_position (WIN_POS_MOUSE);
2924 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2925 msg.set_position (WIN_POS_MOUSE);
2941 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2943 if (!_session || _session->deletion_in_progress()) {
2947 XMLNode* node = new XMLNode (X_("UI"));
2949 WM::Manager::instance().add_state (*node);
2951 node->add_child_nocopy (gui_object_state->get_state());
2953 _session->add_extra_xml (*node);
2955 if (export_video_dialog) {
2956 _session->add_extra_xml (export_video_dialog->get_state());
2959 save_state_canfail (name, switch_to_it);
2963 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2968 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2973 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2978 ARDOUR_UI::primary_clock_value_changed ()
2981 _session->request_locate (primary_clock->current_time ());
2986 ARDOUR_UI::big_clock_value_changed ()
2989 _session->request_locate (big_clock->current_time ());
2994 ARDOUR_UI::secondary_clock_value_changed ()
2997 _session->request_locate (secondary_clock->current_time ());
3002 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3004 if (_session == 0) {
3008 if (_session->step_editing()) {
3012 Session::RecordState const r = _session->record_status ();
3013 bool const h = _session->have_rec_enabled_track ();
3015 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3017 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3019 rec_button.set_active_state (Gtkmm2ext::Off);
3021 } else if (r == Session::Recording && h) {
3022 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3024 rec_button.unset_active_state ();
3029 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3033 prompter.get_result (name);
3035 if (name.length()) {
3036 int failed = _session->save_template (name);
3038 if (failed == -2) { /* file already exists. */
3039 bool overwrite = overwrite_file_dialog (prompter,
3040 _("Confirm Template Overwrite"),
3041 _("A template already exists with that name. Do you want to overwrite it?"));
3044 _session->save_template (name, true);
3056 ARDOUR_UI::save_template ()
3058 ArdourPrompter prompter (true);
3060 if (!check_audioengine (_main_window)) {
3064 prompter.set_name (X_("Prompter"));
3065 prompter.set_title (_("Save Template"));
3066 prompter.set_prompt (_("Name for template:"));
3067 prompter.set_initial_text(_session->name() + _("-template"));
3068 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3070 bool finished = false;
3072 switch (prompter.run()) {
3073 case RESPONSE_ACCEPT:
3074 finished = process_save_template_prompter (prompter);
3085 ARDOUR_UI::edit_metadata ()
3087 SessionMetadataEditor dialog;
3088 dialog.set_session (_session);
3089 dialog.grab_focus ();
3094 ARDOUR_UI::import_metadata ()
3096 SessionMetadataImporter dialog;
3097 dialog.set_session (_session);
3102 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3104 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3106 MessageDialog msg (str,
3108 Gtk::MESSAGE_WARNING,
3109 Gtk::BUTTONS_YES_NO,
3113 msg.set_name (X_("OpenExistingDialog"));
3114 msg.set_title (_("Open Existing Session"));
3115 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3116 msg.set_position (Gtk::WIN_POS_CENTER);
3117 pop_back_splash (msg);
3119 switch (msg.run()) {
3128 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3130 BusProfile bus_profile;
3134 bus_profile.master_out_channels = 2;
3135 bus_profile.input_ac = AutoConnectPhysical;
3136 bus_profile.output_ac = AutoConnectMaster;
3137 bus_profile.requested_physical_in = 0; // use all available
3138 bus_profile.requested_physical_out = 0; // use all available
3142 /* get settings from advanced section of NSD */
3144 if (sd.create_master_bus()) {
3145 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3147 bus_profile.master_out_channels = 0;
3150 if (sd.connect_inputs()) {
3151 bus_profile.input_ac = AutoConnectPhysical;
3153 bus_profile.input_ac = AutoConnectOption (0);
3156 bus_profile.output_ac = AutoConnectOption (0);
3158 if (sd.connect_outputs ()) {
3159 if (sd.connect_outs_to_master()) {
3160 bus_profile.output_ac = AutoConnectMaster;
3161 } else if (sd.connect_outs_to_physical()) {
3162 bus_profile.output_ac = AutoConnectPhysical;
3166 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3167 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3170 if (build_session (session_path, session_name, bus_profile)) {
3178 ARDOUR_UI::load_from_application_api (const std::string& path)
3180 /* OS X El Capitan (and probably later) now somehow passes the command
3181 line arguments to an app via the openFile delegate protocol. Ardour
3182 already does its own command line processing, and having both
3183 pathways active causes crashes. So, if the command line was already
3184 set, do nothing here.
3187 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3191 ARDOUR_COMMAND_LINE::session_name = path;
3193 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3195 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3197 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3198 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3199 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3200 * -> SessionDialog is not displayed
3203 if (_session_dialog) {
3204 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3205 std::string session_path = path;
3206 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3207 session_path = Glib::path_get_dirname (session_path);
3209 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3210 _session_dialog->set_provided_session (session_name, session_path);
3211 _session_dialog->response (RESPONSE_NONE);
3212 _session_dialog->hide();
3217 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3218 /* /path/to/foo => /path/to/foo, foo */
3219 rv = load_session (path, basename_nosuffix (path));
3221 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3222 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3225 // if load_session fails -> pop up SessionDialog.
3227 ARDOUR_COMMAND_LINE::session_name = "";
3229 if (get_session_parameters (true, false)) {
3235 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3237 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3239 string session_name;
3240 string session_path;
3241 string template_name;
3243 bool likely_new = false;
3244 bool cancel_not_quit;
3246 /* deal with any existing DIRTY session now, rather than later. don't
3247 * treat a non-dirty session this way, so that it stays visible
3248 * as we bring up the new session dialog.
3251 if (_session && ARDOUR_UI::instance()->video_timeline) {
3252 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3255 /* if there is already a session, relabel the button
3256 on the SessionDialog so that we don't Quit directly
3258 cancel_not_quit = (_session != 0);
3260 if (_session && _session->dirty()) {
3261 if (unload_session (false)) {
3262 /* unload cancelled by user */
3265 ARDOUR_COMMAND_LINE::session_name = "";
3268 if (!load_template.empty()) {
3269 should_be_new = true;
3270 template_name = load_template;
3273 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3274 session_path = ARDOUR_COMMAND_LINE::session_name;
3276 if (!session_path.empty()) {
3277 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3278 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3279 /* session/snapshot file, change path to be dir */
3280 session_path = Glib::path_get_dirname (session_path);
3285 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3287 _session_dialog = &session_dialog;
3290 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3292 /* if they named a specific statefile, use it, otherwise they are
3293 just giving a session folder, and we want to use it as is
3294 to find the session.
3297 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3299 if (suffix != string::npos) {
3300 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3301 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3302 session_name = Glib::path_get_basename (session_name);
3304 session_path = ARDOUR_COMMAND_LINE::session_name;
3305 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3310 session_dialog.clear_given ();
3313 if (should_be_new || session_name.empty()) {
3314 /* need the dialog to get info from user */
3316 cerr << "run dialog\n";
3318 switch (session_dialog.run()) {
3319 case RESPONSE_ACCEPT:
3322 /* this is used for async * app->ShouldLoad(). */
3323 continue; // while loop
3326 if (quit_on_cancel) {
3327 // JE - Currently (July 2014) this section can only get reached if the
3328 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3329 // point does NOT indicate an abnormal termination). Therefore, let's
3330 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3332 pthread_cancel_all ();
3340 session_dialog.hide ();
3343 /* if we run the startup dialog again, offer more than just "new session" */
3345 should_be_new = false;
3347 session_name = session_dialog.session_name (likely_new);
3348 session_path = session_dialog.session_folder ();
3355 int rv = ARDOUR::inflate_session (session_name,
3356 Config->get_default_session_parent_dir(), session_path, session_name);
3358 MessageDialog msg (session_dialog,
3359 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3364 session_dialog.set_provided_session (session_name, session_path);
3368 // XXX check archive, inflate
3369 string::size_type suffix = session_name.find (statefile_suffix);
3371 if (suffix != string::npos) {
3372 session_name = session_name.substr (0, suffix);
3375 /* this shouldn't happen, but we catch it just in case it does */
3377 if (session_name.empty()) {
3381 if (session_dialog.use_session_template()) {
3382 template_name = session_dialog.session_template_name();
3383 _session_is_new = true;
3386 if (session_name[0] == G_DIR_SEPARATOR ||
3387 #ifdef PLATFORM_WINDOWS
3388 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3390 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3391 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3396 /* absolute path or cwd-relative path specified for session name: infer session folder
3397 from what was given.
3400 session_path = Glib::path_get_dirname (session_name);
3401 session_name = Glib::path_get_basename (session_name);
3405 session_path = session_dialog.session_folder();
3407 char illegal = Session::session_name_is_legal (session_name);
3410 MessageDialog msg (session_dialog,
3411 string_compose (_("To ensure compatibility with various systems\n"
3412 "session names may not contain a '%1' character"),
3415 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3420 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3423 if (likely_new && !nsm) {
3425 std::string existing = Glib::build_filename (session_path, session_name);
3427 if (!ask_about_loading_existing_session (existing)) {
3428 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3433 _session_is_new = false;
3438 pop_back_splash (session_dialog);
3439 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3441 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3445 char illegal = Session::session_name_is_legal(session_name);
3448 pop_back_splash (session_dialog);
3449 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3450 "session names may not contain a '%1' character"), illegal));
3452 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3456 _session_is_new = true;
3459 if (likely_new && template_name.empty()) {
3461 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3465 ret = load_session (session_path, session_name, template_name);
3468 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3472 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3473 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3477 /* clear this to avoid endless attempts to load the
3481 ARDOUR_COMMAND_LINE::session_name = "";
3485 _session_dialog = NULL;
3491 ARDOUR_UI::close_session()
3493 if (!check_audioengine (_main_window)) {
3497 if (unload_session (true)) {
3501 ARDOUR_COMMAND_LINE::session_name = "";
3503 if (get_session_parameters (true, false)) {
3506 if (splash && splash->is_visible()) {
3507 // in 1 second, hide the splash screen
3508 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3512 /** @param snap_name Snapshot name (without .ardour suffix).
3513 * @return -2 if the load failed because we are not connected to the AudioEngine.
3516 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3518 Session *new_session;
3523 unload_status = unload_session ();
3525 if (unload_status < 0) {
3527 } else if (unload_status > 0) {
3533 session_loaded = false;
3535 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3538 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3541 /* this one is special */
3543 catch (AudioEngine::PortRegistrationFailure& err) {
3545 MessageDialog msg (err.what(),
3548 Gtk::BUTTONS_CLOSE);
3550 msg.set_title (_("Port Registration Error"));
3551 msg.set_secondary_text (_("Click the Close button to try again."));
3552 msg.set_position (Gtk::WIN_POS_CENTER);
3553 pop_back_splash (msg);
3556 int response = msg.run ();
3561 case RESPONSE_CANCEL:
3568 catch (SessionException e) {
3569 MessageDialog msg (string_compose(
3570 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3571 path, snap_name, e.what()),
3576 msg.set_title (_("Loading Error"));
3577 msg.set_position (Gtk::WIN_POS_CENTER);
3578 pop_back_splash (msg);
3590 MessageDialog msg (string_compose(
3591 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3597 msg.set_title (_("Loading Error"));
3598 msg.set_position (Gtk::WIN_POS_CENTER);
3599 pop_back_splash (msg);
3611 list<string> const u = new_session->unknown_processors ();
3613 MissingPluginDialog d (_session, u);
3618 if (!new_session->writable()) {
3619 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3624 msg.set_title (_("Read-only Session"));
3625 msg.set_position (Gtk::WIN_POS_CENTER);
3626 pop_back_splash (msg);
3633 /* Now the session been created, add the transport controls */
3634 new_session->add_controllable(roll_controllable);
3635 new_session->add_controllable(stop_controllable);
3636 new_session->add_controllable(goto_start_controllable);
3637 new_session->add_controllable(goto_end_controllable);
3638 new_session->add_controllable(auto_loop_controllable);
3639 new_session->add_controllable(play_selection_controllable);
3640 new_session->add_controllable(rec_controllable);
3642 set_session (new_session);
3644 session_loaded = true;
3647 _session->set_clean ();
3650 #ifdef WINDOWS_VST_SUPPORT
3651 fst_stop_threading();
3655 Timers::TimerSuspender t;
3659 #ifdef WINDOWS_VST_SUPPORT
3660 fst_start_threading();
3669 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3671 Session *new_session;
3674 session_loaded = false;
3675 x = unload_session ();
3683 _session_is_new = true;
3686 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3689 catch (SessionException e) {
3690 cerr << "Here are the errors associated with this failed session:\n";
3692 cerr << "---------\n";
3693 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3694 msg.set_title (_("Loading Error"));
3695 msg.set_position (Gtk::WIN_POS_CENTER);
3696 pop_back_splash (msg);
3701 cerr << "Here are the errors associated with this failed session:\n";
3703 cerr << "---------\n";
3704 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3705 msg.set_title (_("Loading Error"));
3706 msg.set_position (Gtk::WIN_POS_CENTER);
3707 pop_back_splash (msg);
3712 /* Give the new session the default GUI state, if such things exist */
3715 n = Config->instant_xml (X_("Editor"));
3717 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3718 new_session->add_instant_xml (*n, false);
3720 n = Config->instant_xml (X_("Mixer"));
3722 new_session->add_instant_xml (*n, false);
3725 n = Config->instant_xml (X_("Preferences"));
3727 new_session->add_instant_xml (*n, false);
3730 /* Put the playhead at 0 and scroll fully left */
3731 n = new_session->instant_xml (X_("Editor"));
3733 n->set_property (X_("playhead"), X_("0"));
3734 n->set_property (X_("left-frame"), X_("0"));
3737 set_session (new_session);
3739 session_loaded = true;
3741 new_session->save_state(new_session->name());
3747 ARDOUR_UI::launch_chat ()
3749 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3751 dialog.set_title (_("About the Chat"));
3752 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."));
3754 switch (dialog.run()) {
3757 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3758 #elif defined PLATFORM_WINDOWS
3759 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3761 open_uri("http://webchat.freenode.net/?channels=ardour");
3770 ARDOUR_UI::launch_manual ()
3772 PBD::open_uri (Config->get_tutorial_manual_url());
3776 ARDOUR_UI::launch_reference ()
3778 PBD::open_uri (Config->get_reference_manual_url());
3782 ARDOUR_UI::launch_tracker ()
3784 PBD::open_uri ("http://tracker.ardour.org");
3788 ARDOUR_UI::launch_subscribe ()
3790 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3794 ARDOUR_UI::launch_cheat_sheet ()
3797 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3799 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3804 ARDOUR_UI::launch_website ()
3806 PBD::open_uri ("http://ardour.org");
3810 ARDOUR_UI::launch_website_dev ()
3812 PBD::open_uri ("http://ardour.org/development.html");
3816 ARDOUR_UI::launch_forums ()
3818 PBD::open_uri ("https://community.ardour.org/forums");
3822 ARDOUR_UI::launch_howto_report ()
3824 PBD::open_uri ("http://ardour.org/reporting_bugs");
3828 ARDOUR_UI::loading_message (const std::string& msg)
3830 if (ARDOUR_COMMAND_LINE::no_splash) {
3838 splash->message (msg);
3842 ARDOUR_UI::show_splash ()
3846 splash = new Splash;
3856 ARDOUR_UI::hide_splash ()
3863 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3867 removed = rep.paths.size();
3870 MessageDialog msgd (_main_window,
3871 _("No files were ready for clean-up"),
3875 msgd.set_title (_("Clean-up"));
3876 msgd.set_secondary_text (_("If this seems suprising, \n\
3877 check for any existing snapshots.\n\
3878 These may still include regions that\n\
3879 require some unused files to continue to exist."));
3885 ArdourDialog results (_("Clean-up"), true, false);
3887 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3888 CleanupResultsModelColumns() {
3892 Gtk::TreeModelColumn<std::string> visible_name;
3893 Gtk::TreeModelColumn<std::string> fullpath;
3897 CleanupResultsModelColumns results_columns;
3898 Glib::RefPtr<Gtk::ListStore> results_model;
3899 Gtk::TreeView results_display;
3901 results_model = ListStore::create (results_columns);
3902 results_display.set_model (results_model);
3903 results_display.append_column (list_title, results_columns.visible_name);
3905 results_display.set_name ("CleanupResultsList");
3906 results_display.set_headers_visible (true);
3907 results_display.set_headers_clickable (false);
3908 results_display.set_reorderable (false);
3910 Gtk::ScrolledWindow list_scroller;
3913 Gtk::HBox dhbox; // the hbox for the image and text
3914 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3915 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3917 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3919 const string dead_directory = _session->session_directory().dead_path();
3922 %1 - number of files removed
3923 %2 - location of "dead"
3924 %3 - size of files affected
3925 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3928 const char* bprefix;
3929 double space_adjusted = 0;
3931 if (rep.space < 1000) {
3933 space_adjusted = rep.space;
3934 } else if (rep.space < 1000000) {
3935 bprefix = _("kilo");
3936 space_adjusted = floorf((float)rep.space / 1000.0);
3937 } else if (rep.space < 1000000 * 1000) {
3938 bprefix = _("mega");
3939 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3941 bprefix = _("giga");
3942 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3946 txt.set_markup (string_compose (P_("\
3947 The following file was deleted from %2,\n\
3948 releasing %3 %4bytes of disk space", "\
3949 The following %1 files were deleted from %2,\n\
3950 releasing %3 %4bytes of disk space", removed),
3951 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3953 txt.set_markup (string_compose (P_("\
3954 The following file was not in use and \n\
3955 has been moved to: %2\n\n\
3956 After a restart of %5\n\n\
3957 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3958 will release an additional %3 %4bytes of disk space.\n", "\
3959 The following %1 files were not in use and \n\
3960 have been moved to: %2\n\n\
3961 After a restart of %5\n\n\
3962 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3963 will release an additional %3 %4bytes of disk space.\n", removed),
3964 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3967 dhbox.pack_start (*dimage, true, false, 5);
3968 dhbox.pack_start (txt, true, false, 5);
3970 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3971 TreeModel::Row row = *(results_model->append());
3972 row[results_columns.visible_name] = *i;
3973 row[results_columns.fullpath] = *i;
3976 list_scroller.add (results_display);
3977 list_scroller.set_size_request (-1, 150);
3978 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3980 dvbox.pack_start (dhbox, true, false, 5);
3981 dvbox.pack_start (list_scroller, true, false, 5);
3982 ddhbox.pack_start (dvbox, true, false, 5);
3984 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3985 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3986 results.set_default_response (RESPONSE_CLOSE);
3987 results.set_position (Gtk::WIN_POS_MOUSE);
3989 results_display.show();
3990 list_scroller.show();
3997 //results.get_vbox()->show();
3998 results.set_resizable (false);
4005 ARDOUR_UI::cleanup ()
4007 if (_session == 0) {
4008 /* shouldn't happen: menu item is insensitive */
4013 MessageDialog checker (_("Are you sure you want to clean-up?"),
4015 Gtk::MESSAGE_QUESTION,
4018 checker.set_title (_("Clean-up"));
4020 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4021 ALL undo/redo information will be lost if you clean-up.\n\
4022 Clean-up will move all unused files to a \"dead\" location."));
4024 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4025 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4026 checker.set_default_response (RESPONSE_CANCEL);
4028 checker.set_name (_("CleanupDialog"));
4029 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4030 checker.set_position (Gtk::WIN_POS_MOUSE);
4032 switch (checker.run()) {
4033 case RESPONSE_ACCEPT:
4039 ARDOUR::CleanupReport rep;
4041 editor->prepare_for_cleanup ();
4043 /* do not allow flush until a session is reloaded */
4045 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4047 act->set_sensitive (false);
4050 if (_session->cleanup_sources (rep)) {
4051 editor->finish_cleanup ();
4055 editor->finish_cleanup ();
4058 display_cleanup_results (rep, _("Cleaned Files"), false);
4062 ARDOUR_UI::flush_trash ()
4064 if (_session == 0) {
4065 /* shouldn't happen: menu item is insensitive */
4069 ARDOUR::CleanupReport rep;
4071 if (_session->cleanup_trash_sources (rep)) {
4075 display_cleanup_results (rep, _("deleted file"), true);
4079 ARDOUR_UI::cleanup_peakfiles ()
4081 if (_session == 0) {
4082 /* shouldn't happen: menu item is insensitive */
4086 if (! _session->can_cleanup_peakfiles ()) {
4090 // get all region-views in this session
4092 TrackViewList empty;
4094 editor->get_regions_after(rs, (framepos_t) 0, empty);
4095 std::list<RegionView*> views = rs.by_layer();
4097 // remove displayed audio-region-views waveforms
4098 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4099 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4100 if (!arv) { continue ; }
4101 arv->delete_waves();
4104 // cleanup peak files:
4105 // - stop pending peakfile threads
4106 // - close peakfiles if any
4107 // - remove peak dir in session
4108 // - setup peakfiles (background thread)
4109 _session->cleanup_peakfiles ();
4111 // re-add waves to ARV
4112 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4113 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4114 if (!arv) { continue ; }
4115 arv->create_waves();
4119 PresentationInfo::order_t
4120 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4122 if (editor->get_selection().tracks.empty()) {
4123 return PresentationInfo::max_order;
4126 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4129 we want the new routes to have their order keys set starting from
4130 the highest order key in the selection + 1 (if available).
4133 if (place == RouteDialogs::AfterSelection) {
4134 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4136 order_hint = rtav->route()->presentation_info().order();
4139 } else if (place == RouteDialogs::BeforeSelection) {
4140 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4142 order_hint = rtav->route()->presentation_info().order();
4144 } else if (place == RouteDialogs::First) {
4147 /* leave order_hint at max_order */
4154 ARDOUR_UI::start_duplicate_routes ()
4156 if (!duplicate_routes_dialog) {
4157 duplicate_routes_dialog = new DuplicateRouteDialog;
4160 if (duplicate_routes_dialog->restart (_session)) {
4164 duplicate_routes_dialog->present ();
4168 ARDOUR_UI::add_route ()
4170 if (!add_route_dialog.get (false)) {
4171 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4178 if (add_route_dialog->is_visible()) {
4179 /* we're already doing this */
4183 add_route_dialog->set_position (WIN_POS_MOUSE);
4184 add_route_dialog->present();
4188 ARDOUR_UI::add_route_dialog_finished (int r)
4192 add_route_dialog->hide();
4195 case RESPONSE_ACCEPT:
4202 if ((count = add_route_dialog->count()) <= 0) {
4206 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4207 string template_path = add_route_dialog->track_template();
4208 DisplaySuspender ds;
4210 if (!template_path.empty()) {
4211 if (add_route_dialog->name_template_is_default()) {
4212 _session->new_route_from_template (count, order, template_path, string());
4214 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4219 ChanCount input_chan= add_route_dialog->channels ();
4220 ChanCount output_chan;
4221 string name_template = add_route_dialog->name_template ();
4222 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4223 RouteGroup* route_group = add_route_dialog->route_group ();
4224 AutoConnectOption oac = Config->get_output_auto_connect();
4225 bool strict_io = add_route_dialog->use_strict_io ();
4227 if (oac & AutoConnectMaster) {
4228 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4229 output_chan.set (DataType::MIDI, 0);
4231 output_chan = input_chan;
4234 /* XXX do something with name template */
4236 Session::ProcessorChangeBlocker pcb (_session);
4238 switch (add_route_dialog->type_wanted()) {
4239 case AddRouteDialog::AudioTrack:
4240 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4242 case AddRouteDialog::MidiTrack:
4243 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4245 case AddRouteDialog::MixedTrack:
4246 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4248 case AddRouteDialog::AudioBus:
4249 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4251 case AddRouteDialog::MidiBus:
4252 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4254 case AddRouteDialog::VCAMaster:
4255 session_add_vca (name_template, count);
4261 ARDOUR_UI::stop_video_server (bool ask_confirm)
4263 if (!video_server_process && ask_confirm) {
4264 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4266 if (video_server_process) {
4268 ArdourDialog confirm (_("Stop Video-Server"), true);
4269 Label m (_("Do you really want to stop the Video Server?"));
4270 confirm.get_vbox()->pack_start (m, true, true);
4271 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4272 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4273 confirm.show_all ();
4274 if (confirm.run() == RESPONSE_CANCEL) {
4278 delete video_server_process;
4279 video_server_process =0;
4284 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4286 ARDOUR_UI::start_video_server( float_window, true);
4290 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4296 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4297 if (video_server_process) {
4298 popup_error(_("The Video Server is already started."));
4300 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4306 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4308 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4310 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4312 video_server_dialog->set_transient_for (*float_window);
4315 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4316 video_server_dialog->hide();
4318 ResponseType r = (ResponseType) video_server_dialog->run ();
4319 video_server_dialog->hide();
4320 if (r != RESPONSE_ACCEPT) { return false; }
4321 if (video_server_dialog->show_again()) {
4322 Config->set_show_video_server_dialog(false);
4326 std::string icsd_exec = video_server_dialog->get_exec_path();
4327 std::string icsd_docroot = video_server_dialog->get_docroot();
4328 #ifndef PLATFORM_WINDOWS
4329 if (icsd_docroot.empty()) {
4330 icsd_docroot = VideoUtils::video_get_docroot (Config);
4335 #ifdef PLATFORM_WINDOWS
4336 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4337 /* OK, allow all drive letters */
4340 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4341 warning << _("Specified docroot is not an existing directory.") << endmsg;
4344 #ifndef PLATFORM_WINDOWS
4345 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4346 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4347 warning << _("Given Video Server is not an executable file.") << endmsg;
4351 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4352 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4353 warning << _("Given Video Server is not an executable file.") << endmsg;
4359 argp=(char**) calloc(9,sizeof(char*));
4360 argp[0] = strdup(icsd_exec.c_str());
4361 argp[1] = strdup("-P");
4362 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4363 argp[3] = strdup("-p");
4364 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4365 argp[5] = strdup("-C");
4366 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4367 argp[7] = strdup(icsd_docroot.c_str());
4369 stop_video_server();
4371 #ifdef PLATFORM_WINDOWS
4372 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4373 /* OK, allow all drive letters */
4376 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4377 Config->set_video_advanced_setup(false);
4379 std::ostringstream osstream;
4380 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4381 Config->set_video_server_url(osstream.str());
4382 Config->set_video_server_docroot(icsd_docroot);
4383 Config->set_video_advanced_setup(true);
4386 if (video_server_process) {
4387 delete video_server_process;
4390 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4391 if (video_server_process->start()) {
4392 warning << _("Cannot launch the video-server") << endmsg;
4395 int timeout = 120; // 6 sec
4396 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4397 Glib::usleep (50000);
4399 if (--timeout <= 0 || !video_server_process->is_running()) break;
4402 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4404 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4405 delete video_server_process;
4406 video_server_process = 0;
4414 ARDOUR_UI::add_video (Gtk::Window* float_window)
4420 if (!start_video_server(float_window, false)) {
4421 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4426 add_video_dialog->set_transient_for (*float_window);
4429 if (add_video_dialog->is_visible()) {
4430 /* we're already doing this */
4434 ResponseType r = (ResponseType) add_video_dialog->run ();
4435 add_video_dialog->hide();
4436 if (r != RESPONSE_ACCEPT) { return; }
4438 bool local_file, orig_local_file;
4439 std::string path = add_video_dialog->file_name(local_file);
4441 std::string orig_path = path;
4442 orig_local_file = local_file;
4444 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4446 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4447 warning << string_compose(_("could not open %1"), path) << endmsg;
4450 if (!local_file && path.length() == 0) {
4451 warning << _("no video-file selected") << endmsg;
4455 std::string audio_from_video;
4456 bool detect_ltc = false;
4458 switch (add_video_dialog->import_option()) {
4459 case VTL_IMPORT_TRANSCODE:
4461 TranscodeVideoDialog *transcode_video_dialog;
4462 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4463 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4464 transcode_video_dialog->hide();
4465 if (r != RESPONSE_ACCEPT) {
4466 delete transcode_video_dialog;
4470 audio_from_video = transcode_video_dialog->get_audiofile();
4472 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4475 else if (!audio_from_video.empty()) {
4476 editor->embed_audio_from_video(
4478 video_timeline->get_offset(),
4479 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4482 switch (transcode_video_dialog->import_option()) {
4483 case VTL_IMPORT_TRANSCODED:
4484 path = transcode_video_dialog->get_filename();
4487 case VTL_IMPORT_REFERENCE:
4490 delete transcode_video_dialog;
4493 delete transcode_video_dialog;
4497 case VTL_IMPORT_NONE:
4501 /* strip _session->session_directory().video_path() from video file if possible */
4502 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4503 path=path.substr(_session->session_directory().video_path().size());
4504 if (path.at(0) == G_DIR_SEPARATOR) {
4505 path=path.substr(1);
4509 video_timeline->set_update_session_fps(auto_set_session_fps);
4511 if (video_timeline->video_file_info(path, local_file)) {
4512 XMLNode* node = new XMLNode(X_("Videotimeline"));
4513 node->set_property (X_("Filename"), path);
4514 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4515 node->set_property (X_("LocalFile"), local_file);
4516 if (orig_local_file) {
4517 node->set_property (X_("OriginalVideoFile"), orig_path);
4519 node->remove_property (X_("OriginalVideoFile"));
4521 _session->add_extra_xml (*node);
4522 _session->set_dirty ();
4524 if (!audio_from_video.empty() && detect_ltc) {
4525 std::vector<LTCFileReader::LTCMap> ltc_seq;
4528 /* TODO ask user about TV standard (LTC alignment if any) */
4529 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4530 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4532 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4534 /* TODO seek near end of file, and read LTC until end.
4535 * if it fails to find any LTC frames, scan complete file
4537 * calculate drift of LTC compared to video-duration,
4538 * ask user for reference (timecode from start/mid/end)
4541 // LTCFileReader will have written error messages
4544 ::g_unlink(audio_from_video.c_str());
4546 if (ltc_seq.size() == 0) {
4547 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4549 /* the very first TC in the file is somteimes not aligned properly */
4550 int i = ltc_seq.size() -1;
4551 ARDOUR::frameoffset_t video_start_offset =
4552 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4553 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4554 video_timeline->set_offset(video_start_offset);
4558 _session->maybe_update_session_range(
4559 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4560 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4563 if (add_video_dialog->launch_xjadeo() && local_file) {
4564 editor->set_xjadeo_sensitive(true);
4565 editor->toggle_xjadeo_proc(1);
4567 editor->toggle_xjadeo_proc(0);
4569 editor->toggle_ruler_video(true);
4574 ARDOUR_UI::remove_video ()
4576 video_timeline->close_session();
4577 editor->toggle_ruler_video(false);
4580 video_timeline->set_offset_locked(false);
4581 video_timeline->set_offset(0);
4583 /* delete session state */
4584 XMLNode* node = new XMLNode(X_("Videotimeline"));
4585 _session->add_extra_xml(*node);
4586 node = new XMLNode(X_("Videomonitor"));
4587 _session->add_extra_xml(*node);
4588 node = new XMLNode(X_("Videoexport"));
4589 _session->add_extra_xml(*node);
4590 stop_video_server();
4594 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4596 if (localcacheonly) {
4597 video_timeline->vmon_update();
4599 video_timeline->flush_cache();
4601 editor->queue_visual_videotimeline_update();
4605 ARDOUR_UI::export_video (bool range)
4607 if (ARDOUR::Config->get_show_video_export_info()) {
4608 ExportVideoInfobox infobox (_session);
4609 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4610 if (infobox.show_again()) {
4611 ARDOUR::Config->set_show_video_export_info(false);
4614 case GTK_RESPONSE_YES:
4615 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4621 export_video_dialog->set_session (_session);
4622 export_video_dialog->apply_state(editor->get_selection().time, range);
4623 export_video_dialog->run ();
4624 export_video_dialog->hide ();
4628 ARDOUR_UI::preferences_settings () const
4633 node = _session->instant_xml(X_("Preferences"));
4635 node = Config->instant_xml(X_("Preferences"));
4639 node = new XMLNode (X_("Preferences"));
4646 ARDOUR_UI::mixer_settings () const
4651 node = _session->instant_xml(X_("Mixer"));
4653 node = Config->instant_xml(X_("Mixer"));
4657 node = new XMLNode (X_("Mixer"));
4664 ARDOUR_UI::main_window_settings () const
4669 node = _session->instant_xml(X_("Main"));
4671 node = Config->instant_xml(X_("Main"));
4675 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4676 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4681 node = new XMLNode (X_("Main"));
4688 ARDOUR_UI::editor_settings () const
4693 node = _session->instant_xml(X_("Editor"));
4695 node = Config->instant_xml(X_("Editor"));
4699 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4700 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4705 node = new XMLNode (X_("Editor"));
4712 ARDOUR_UI::keyboard_settings () const
4716 node = Config->extra_xml(X_("Keyboard"));
4719 node = new XMLNode (X_("Keyboard"));
4726 ARDOUR_UI::create_xrun_marker (framepos_t where)
4729 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4730 _session->locations()->add (location);
4735 ARDOUR_UI::halt_on_xrun_message ()
4737 cerr << "HALT on xrun\n";
4738 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4743 ARDOUR_UI::xrun_handler (framepos_t where)
4749 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4751 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4752 create_xrun_marker(where);
4755 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4756 halt_on_xrun_message ();
4761 ARDOUR_UI::disk_overrun_handler ()
4763 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4765 if (!have_disk_speed_dialog_displayed) {
4766 have_disk_speed_dialog_displayed = true;
4767 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4768 The disk system on your computer\n\
4769 was not able to keep up with %1.\n\
4771 Specifically, it failed to write data to disk\n\
4772 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4773 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4779 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4780 static MessageDialog *scan_dlg = NULL;
4781 static ProgressBar *scan_pbar = NULL;
4782 static HBox *scan_tbox = NULL;
4783 static Gtk::Button *scan_timeout_button;
4786 ARDOUR_UI::cancel_plugin_scan ()
4788 PluginManager::instance().cancel_plugin_scan();
4792 ARDOUR_UI::cancel_plugin_timeout ()
4794 PluginManager::instance().cancel_plugin_timeout();
4795 scan_timeout_button->set_sensitive (false);
4799 ARDOUR_UI::plugin_scan_timeout (int timeout)
4801 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4805 scan_pbar->set_sensitive (false);
4806 scan_timeout_button->set_sensitive (true);
4807 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4810 scan_pbar->set_sensitive (false);
4811 scan_timeout_button->set_sensitive (false);
4817 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4819 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4823 const bool cancelled = PluginManager::instance().cancelled();
4824 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4825 if (cancelled && scan_dlg->is_mapped()) {
4830 if (cancelled || !can_cancel) {
4835 static Gtk::Button *cancel_button;
4837 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4838 VBox* vbox = scan_dlg->get_vbox();
4839 vbox->set_size_request(400,-1);
4840 scan_dlg->set_title (_("Scanning for plugins"));
4842 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4843 cancel_button->set_name ("EditorGTKButton");
4844 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4845 cancel_button->show();
4847 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4849 scan_tbox = manage( new HBox() );
4851 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4852 scan_timeout_button->set_name ("EditorGTKButton");
4853 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4854 scan_timeout_button->show();
4856 scan_pbar = manage(new ProgressBar());
4857 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4858 scan_pbar->set_text(_("Scan Timeout"));
4861 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4862 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4864 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4867 assert(scan_dlg && scan_tbox && cancel_button);
4869 if (type == X_("closeme")) {
4873 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4876 if (!can_cancel || !cancelled) {
4877 scan_timeout_button->set_sensitive(false);
4879 cancel_button->set_sensitive(can_cancel && !cancelled);
4885 ARDOUR_UI::gui_idle_handler ()
4888 /* due to idle calls, gtk_events_pending() may always return true */
4889 while (gtk_events_pending() && --timeout) {
4890 gtk_main_iteration ();
4895 ARDOUR_UI::disk_underrun_handler ()
4897 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4899 if (!have_disk_speed_dialog_displayed) {
4900 have_disk_speed_dialog_displayed = true;
4901 MessageDialog* msg = new MessageDialog (
4902 _main_window, string_compose (_("The disk system on your computer\n\
4903 was not able to keep up with %1.\n\
4905 Specifically, it failed to read data from disk\n\
4906 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4907 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4913 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4915 have_disk_speed_dialog_displayed = false;
4920 ARDOUR_UI::session_dialog (std::string msg)
4922 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4926 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4933 ARDOUR_UI::pending_state_dialog ()
4935 HBox* hbox = manage (new HBox());
4936 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4937 ArdourDialog dialog (_("Crash Recovery"), true);
4938 Label message (string_compose (_("\
4939 This session appears to have been in the\n\
4940 middle of recording when %1 or\n\
4941 the computer was shutdown.\n\
4943 %1 can recover any captured audio for\n\
4944 you, or it can ignore it. Please decide\n\
4945 what you would like to do.\n"), PROGRAM_NAME));
4946 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4947 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4948 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4949 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4950 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4951 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4952 dialog.set_default_response (RESPONSE_ACCEPT);
4953 dialog.set_position (WIN_POS_CENTER);
4958 switch (dialog.run ()) {
4959 case RESPONSE_ACCEPT:
4967 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4969 HBox* hbox = new HBox();
4970 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4971 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4972 Label message (string_compose (_("\
4973 This session was created with a sample rate of %1 Hz, but\n\
4974 %2 is currently running at %3 Hz. If you load this session,\n\
4975 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4977 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4978 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4979 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4980 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4981 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4982 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4983 dialog.set_default_response (RESPONSE_ACCEPT);
4984 dialog.set_position (WIN_POS_CENTER);
4989 switch (dialog.run()) {
4990 case RESPONSE_ACCEPT:
5000 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5002 MessageDialog msg (string_compose (_("\
5003 This session was created with a sample rate of %1 Hz, but\n\
5004 %2 is currently running at %3 Hz.\n\
5005 Audio will be recorded and played at the wrong sample rate.\n\
5006 Re-Configure the Audio Engine in\n\
5007 Menu > Window > Audio/Midi Setup"),
5008 desired, PROGRAM_NAME, actual),
5010 Gtk::MESSAGE_WARNING);
5015 ARDOUR_UI::use_config ()
5017 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5019 set_transport_controllable_state (*node);
5024 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5026 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5027 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5029 primary_clock->set (pos);
5032 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5033 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5035 secondary_clock->set (pos);
5038 if (big_clock_window) {
5039 big_clock->set (pos);
5041 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5045 ARDOUR_UI::step_edit_status_change (bool yn)
5047 // XXX should really store pre-step edit status of things
5048 // we make insensitive
5051 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5052 rec_button.set_sensitive (false);
5054 rec_button.unset_active_state ();;
5055 rec_button.set_sensitive (true);
5060 ARDOUR_UI::record_state_changed ()
5062 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5065 /* why bother - the clock isn't visible */
5069 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5071 if (big_clock_window) {
5072 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5073 big_clock->set_active (true);
5075 big_clock->set_active (false);
5082 ARDOUR_UI::first_idle ()
5085 _session->allow_auto_play (true);
5089 editor->first_idle();
5092 Keyboard::set_can_save_keybindings (true);
5097 ARDOUR_UI::store_clock_modes ()
5099 XMLNode* node = new XMLNode(X_("ClockModes"));
5101 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5102 XMLNode* child = new XMLNode (X_("Clock"));
5104 child->set_property (X_("name"), (*x)->name());
5105 child->set_property (X_("mode"), (*x)->mode());
5106 child->set_property (X_("on"), (*x)->on());
5108 node->add_child_nocopy (*child);
5111 _session->add_extra_xml (*node);
5112 _session->set_dirty ();
5115 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5116 : Controllable (name), ui (u), type(tp)
5122 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5125 /* do nothing: these are radio-style actions */
5129 const char *action = 0;
5133 action = X_("Roll");
5136 action = X_("Stop");
5139 action = X_("GotoStart");
5142 action = X_("GotoEnd");
5145 action = X_("Loop");
5148 action = X_("PlaySelection");
5151 action = X_("Record");
5161 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5169 ARDOUR_UI::TransportControllable::get_value (void) const
5196 ARDOUR_UI::setup_profile ()
5198 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5199 Profile->set_small_screen ();
5202 if (g_getenv ("TRX")) {
5203 Profile->set_trx ();
5206 if (g_getenv ("MIXBUS")) {
5207 Profile->set_mixbus ();
5212 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5214 MissingFileDialog dialog (s, str, type);
5219 int result = dialog.run ();
5226 return 1; // quit entire session load
5229 result = dialog.get_action ();
5235 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5237 AmbiguousFileDialog dialog (file, hits);
5244 return dialog.get_which ();
5247 /** Allocate our thread-local buffers */
5249 ARDOUR_UI::get_process_buffers ()
5251 _process_thread->get_buffers ();
5254 /** Drop our thread-local buffers */
5256 ARDOUR_UI::drop_process_buffers ()
5258 _process_thread->drop_buffers ();
5262 ARDOUR_UI::feedback_detected ()
5264 _feedback_exists = true;
5268 ARDOUR_UI::successful_graph_sort ()
5270 _feedback_exists = false;
5274 ARDOUR_UI::midi_panic ()
5277 _session->midi_panic();
5282 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5284 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5285 const char* end_big = "</span>";
5286 const char* start_mono = "<tt>";
5287 const char* end_mono = "</tt>";
5289 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5290 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5291 "From now on, use the backup copy with older versions of %3"),
5292 xml_path, backup_path, PROGRAM_NAME,
5294 start_mono, end_mono), true);
5300 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5302 using namespace Menu_Helpers;
5304 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5305 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5306 i->set_active (editor_meter->meter_type () == type);
5310 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5312 using namespace Gtk::Menu_Helpers;
5314 Gtk::Menu* m = manage (new Menu);
5315 MenuList& items = m->items ();
5317 RadioMenuItem::Group group;
5319 _suspend_editor_meter_callbacks = true;
5320 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5321 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5322 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5323 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5324 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5325 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5326 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5327 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5328 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5329 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5330 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5332 m->popup (ev->button, ev->time);
5333 _suspend_editor_meter_callbacks = false;
5337 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5339 if (ev->button == 3 && editor_meter) {
5340 popup_editor_meter_menu (ev);
5347 ARDOUR_UI::reset_peak_display ()
5349 if (!_session || !_session->master_out() || !editor_meter) return;
5350 editor_meter->clear_meters();
5351 editor_meter_max_peak = -INFINITY;
5352 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5356 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5358 if (!_session || !_session->master_out()) return;
5359 if (group == _session->master_out()->route_group()) {
5360 reset_peak_display ();
5365 ARDOUR_UI::reset_route_peak_display (Route* route)
5367 if (!_session || !_session->master_out()) return;
5368 if (_session->master_out().get() == route) {
5369 reset_peak_display ();
5374 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5376 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5377 audio_midi_setup->set_position (WIN_POS_CENTER);
5379 if (desired_sample_rate != 0) {
5380 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5381 audio_midi_setup->try_autostart ();
5382 if (ARDOUR::AudioEngine::instance()->running()) {
5389 int response = audio_midi_setup->run();
5390 printf("RESPONSE %d\n", response);
5392 case Gtk::RESPONSE_DELETE_EVENT:
5395 if (!AudioEngine::instance()->running()) {
5398 audio_midi_setup->hide ();
5406 ARDOUR_UI::transport_numpad_timeout ()
5408 _numpad_locate_happening = false;
5409 if (_numpad_timeout_connection.connected() )
5410 _numpad_timeout_connection.disconnect();
5415 ARDOUR_UI::transport_numpad_decimal ()
5417 _numpad_timeout_connection.disconnect();
5419 if (_numpad_locate_happening) {
5420 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5421 _numpad_locate_happening = false;
5423 _pending_locate_num = 0;
5424 _numpad_locate_happening = true;
5425 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5430 ARDOUR_UI::transport_numpad_event (int num)
5432 if ( _numpad_locate_happening ) {
5433 _pending_locate_num = _pending_locate_num*10 + num;
5436 case 0: toggle_roll(false, false); break;
5437 case 1: transport_rewind(1); break;
5438 case 2: transport_forward(1); break;
5439 case 3: transport_record(true); break;
5440 case 4: toggle_session_auto_loop(); break;
5441 case 5: transport_record(false); toggle_session_auto_loop(); break;
5442 case 6: toggle_punch(); break;
5443 case 7: toggle_click(); break;
5444 case 8: toggle_auto_return(); break;
5445 case 9: toggle_follow_edits(); break;
5451 ARDOUR_UI::set_flat_buttons ()
5453 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5457 ARDOUR_UI::audioengine_became_silent ()
5459 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5461 Gtk::MESSAGE_WARNING,
5465 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5467 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5468 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5469 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5470 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5471 Gtk::HBox pay_button_box;
5472 Gtk::HBox subscribe_button_box;
5474 pay_button_box.pack_start (pay_button, true, false);
5475 subscribe_button_box.pack_start (subscribe_button, true, false);
5477 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 */
5479 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5480 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5482 msg.get_vbox()->pack_start (pay_label);
5483 msg.get_vbox()->pack_start (pay_button_box);
5484 msg.get_vbox()->pack_start (subscribe_label);
5485 msg.get_vbox()->pack_start (subscribe_button_box);
5487 msg.get_vbox()->show_all ();
5489 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5490 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5491 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5496 case Gtk::RESPONSE_YES:
5497 AudioEngine::instance()->reset_silence_countdown ();
5500 case Gtk::RESPONSE_NO:
5502 save_state_canfail ("");
5506 case Gtk::RESPONSE_CANCEL:
5508 /* don't reset, save session and exit */
5514 ARDOUR_UI::hide_application ()
5516 Application::instance ()-> hide ();
5520 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5522 /* icons, titles, WM stuff */
5524 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5526 if (window_icons.empty()) {
5527 Glib::RefPtr<Gdk::Pixbuf> icon;
5528 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5529 window_icons.push_back (icon);
5531 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5532 window_icons.push_back (icon);
5534 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5535 window_icons.push_back (icon);
5537 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5538 window_icons.push_back (icon);
5542 if (!window_icons.empty()) {
5543 window.set_default_icon_list (window_icons);
5546 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5548 if (!name.empty()) {
5552 window.set_title (title.get_string());
5553 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5555 window.set_flags (CAN_FOCUS);
5556 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5558 /* This is a hack to ensure that GTK-accelerators continue to
5559 * work. Once we switch over to entirely native bindings, this will be
5560 * unnecessary and should be removed
5562 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5564 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5565 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5566 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5567 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5571 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5573 Gtkmm2ext::Bindings* bindings = 0;
5574 Gtk::Window* window = 0;
5576 /* until we get ardour bindings working, we are not handling key
5580 if (ev->type != GDK_KEY_PRESS) {
5584 if (event_window == &_main_window) {
5586 window = event_window;
5588 /* find current tab contents */
5590 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5592 /* see if it uses the ardour binding system */
5595 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5598 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5602 window = event_window;
5604 /* see if window uses ardour binding system */
5606 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5609 /* An empty binding set is treated as if it doesn't exist */
5611 if (bindings && bindings->empty()) {
5615 return key_press_focus_accelerator_handler (*window, ev, bindings);
5618 static Gtkmm2ext::Bindings*
5619 get_bindings_from_widget_heirarchy (GtkWidget** w)
5624 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5627 *w = gtk_widget_get_parent (*w);
5630 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5634 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5636 GtkWindow* win = window.gobj();
5637 GtkWidget* focus = gtk_window_get_focus (win);
5638 GtkWidget* binding_widget = focus;
5639 bool special_handling_of_unmodified_accelerators = false;
5640 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5644 /* some widget has keyboard focus */
5646 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5648 /* A particular kind of focusable widget currently has keyboard
5649 * focus. All unmodified key events should go to that widget
5650 * first and not be used as an accelerator by default
5653 special_handling_of_unmodified_accelerators = true;
5657 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5658 if (focus_bindings) {
5659 bindings = focus_bindings;
5660 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5665 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",
5668 Gtkmm2ext::show_gdk_event_state (ev->state),
5669 special_handling_of_unmodified_accelerators,
5670 Keyboard::some_magic_widget_has_focus(),
5672 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5673 ((ev->state & mask) ? "yes" : "no"),
5674 window.get_title()));
5676 /* This exists to allow us to override the way GTK handles
5677 key events. The normal sequence is:
5679 a) event is delivered to a GtkWindow
5680 b) accelerators/mnemonics are activated
5681 c) if (b) didn't handle the event, propagate to
5682 the focus widget and/or focus chain
5684 The problem with this is that if the accelerators include
5685 keys without modifiers, such as the space bar or the
5686 letter "e", then pressing the key while typing into
5687 a text entry widget results in the accelerator being
5688 activated, instead of the desired letter appearing
5691 There is no good way of fixing this, but this
5692 represents a compromise. The idea is that
5693 key events involving modifiers (not Shift)
5694 get routed into the activation pathway first, then
5695 get propagated to the focus widget if necessary.
5697 If the key event doesn't involve modifiers,
5698 we deliver to the focus widget first, thus allowing
5699 it to get "normal text" without interference
5702 Of course, this can also be problematic: if there
5703 is a widget with focus, then it will swallow
5704 all "normal text" accelerators.
5708 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5710 /* no special handling or there are modifiers in effect: accelerate first */
5712 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5713 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5714 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5716 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5717 KeyboardKey k (ev->state, ev->keyval);
5721 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5723 if (bindings->activate (k, Bindings::Press)) {
5724 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5728 if (binding_widget) {
5729 binding_widget = gtk_widget_get_parent (binding_widget);
5730 if (binding_widget) {
5731 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5740 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5742 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5743 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5747 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5749 if (gtk_window_propagate_key_event (win, ev)) {
5750 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5756 /* no modifiers, propagate first */
5758 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5760 if (gtk_window_propagate_key_event (win, ev)) {
5761 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5765 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5766 KeyboardKey k (ev->state, ev->keyval);
5770 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5773 if (bindings->activate (k, Bindings::Press)) {
5774 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5778 if (binding_widget) {
5779 binding_widget = gtk_widget_get_parent (binding_widget);
5780 if (binding_widget) {
5781 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5790 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5792 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5793 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5798 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5803 ARDOUR_UI::load_bindings ()
5805 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5806 error << _("Global keybindings are missing") << endmsg;
5811 ARDOUR_UI::cancel_solo ()
5814 _session->cancel_all_solo ();
5819 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5821 /* this resets focus to the first focusable parent of the given widget,
5822 * or, if there is no focusable parent, cancels focus in the toplevel
5823 * window that the given widget is packed into (if there is one).
5830 Gtk::Widget* top = w->get_toplevel();
5832 if (!top || !top->is_toplevel()) {
5836 w = w->get_parent ();
5840 if (w->is_toplevel()) {
5841 /* Setting the focus widget to a Gtk::Window causes all
5842 * subsequent calls to ::has_focus() on the nominal
5843 * focus widget in that window to return
5844 * false. Workaround: never set focus to the toplevel
5850 if (w->get_can_focus ()) {
5851 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5852 win->set_focus (*w);
5855 w = w->get_parent ();
5858 if (top == &_main_window) {
5862 /* no focusable parent found, cancel focus in top level window.
5863 C++ API cannot be used for this. Thanks, references.
5866 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);