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/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/xml++.h"
70 #include "gtkmm2ext/application.h"
71 #include "gtkmm2ext/bindings.h"
72 #include "gtkmm2ext/gtk_ui.h"
73 #include "gtkmm2ext/utils.h"
74 #include "gtkmm2ext/click_box.h"
75 #include "gtkmm2ext/fastmeter.h"
76 #include "gtkmm2ext/popup.h"
77 #include "gtkmm2ext/window_title.h"
79 #include "ardour/ardour.h"
80 #include "ardour/audio_backend.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/automation_watch.h"
85 #include "ardour/diskstream.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/filesystem_paths.h"
88 #include "ardour/ltc_file_reader.h"
89 #include "ardour/midi_track.h"
90 #include "ardour/port.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/process_thread.h"
93 #include "ardour/profile.h"
94 #include "ardour/recent_sessions.h"
95 #include "ardour/record_enable_control.h"
96 #include "ardour/session_directory.h"
97 #include "ardour/session_route.h"
98 #include "ardour/session_state_utils.h"
99 #include "ardour/session_utils.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/slave.h"
102 #include "ardour/system_exec.h"
103 #include "ardour/track.h"
104 #include "ardour/vca_manager.h"
105 #include "ardour/utils.h"
107 #include "LuaBridge/LuaBridge.h"
109 #ifdef WINDOWS_VST_SUPPORT
112 #ifdef AUDIOUNIT_SUPPORT
113 #include "ardour/audio_unit.h"
116 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
121 #include "timecode/time.h"
123 typedef uint64_t microseconds_t;
128 #include "add_route_dialog.h"
129 #include "ambiguous_file_dialog.h"
130 #include "ardour_ui.h"
131 #include "audio_clock.h"
132 #include "audio_region_view.h"
133 #include "big_clock_window.h"
134 #include "bundle_manager.h"
135 #include "duplicate_routes_dialog.h"
137 #include "engine_dialog.h"
138 #include "export_video_dialog.h"
139 #include "export_video_infobox.h"
140 #include "gain_meter.h"
141 #include "global_port_matrix.h"
142 #include "gui_object.h"
143 #include "gui_thread.h"
144 #include "keyboard.h"
145 #include "keyeditor.h"
146 #include "location_ui.h"
147 #include "lua_script_manager.h"
148 #include "luawindow.h"
149 #include "main_clock.h"
150 #include "missing_file_dialog.h"
151 #include "missing_plugin_dialog.h"
152 #include "mixer_ui.h"
153 #include "meterbridge.h"
154 #include "mouse_cursors.h"
157 #include "pingback.h"
158 #include "processor_box.h"
159 #include "prompter.h"
160 #include "public_editor.h"
161 #include "rc_option_editor.h"
162 #include "route_time_axis.h"
163 #include "route_params_ui.h"
164 #include "save_as_dialog.h"
165 #include "script_selector.h"
166 #include "session_archive_dialog.h"
167 #include "session_dialog.h"
168 #include "session_metadata_dialog.h"
169 #include "session_option_editor.h"
170 #include "speaker_dialog.h"
173 #include "theme_manager.h"
174 #include "time_axis_view_item.h"
175 #include "time_info_box.h"
178 #include "video_server_dialog.h"
179 #include "add_video_dialog.h"
180 #include "transcode_video_dialog.h"
182 #include "pbd/i18n.h"
184 using namespace ARDOUR;
185 using namespace ARDOUR_UI_UTILS;
187 using namespace Gtkmm2ext;
190 using namespace Editing;
192 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
194 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
195 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
198 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
200 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
201 "Would you like these files to be copied and used for %1 %2.x?\n\n"
202 "(This will require you to restart %1.)"),
203 PROGRAM_NAME, PROGRAM_VERSION, version),
204 false, /* no markup */
207 true /* modal, though it hardly matters since it is the only window */
210 msg.set_default_response (Gtk::RESPONSE_YES);
213 return (msg.run() == Gtk::RESPONSE_YES);
217 libxml_generic_error_func (void* /* parsing_context*/,
225 vsnprintf (buf, sizeof (buf), msg, ap);
226 error << buf << endmsg;
231 libxml_structured_error_func (void* /* parsing_context*/,
239 replace_all (msg, "\n", "");
242 if (err->file && err->line) {
243 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
246 error << ':' << err->int2;
251 error << X_("XML error: ") << msg << endmsg;
257 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
258 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
259 , session_loaded (false)
260 , gui_object_state (new GUIObjectState)
261 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
262 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
263 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
265 , global_actions (X_("global"))
266 , ignore_dual_punch (false)
267 , main_window_visibility (0)
272 , _mixer_on_top (false)
273 , _initial_verbose_plugin_scan (false)
274 , first_time_engine_run (true)
275 , secondary_clock_spacer (0)
276 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
277 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
278 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
279 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
280 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
281 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
282 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
284 , auto_return_button (ArdourButton::led_default_elements)
285 , follow_edits_button (ArdourButton::led_default_elements)
286 , auto_input_button (ArdourButton::led_default_elements)
287 , auditioning_alert_button (_("Audition"))
288 , solo_alert_button (_("Solo"))
289 , feedback_alert_button (_("Feedback"))
290 , error_alert_button ( ArdourButton::just_led_default_elements )
292 , editor_meter_peak_display()
293 , _numpad_locate_happening (false)
294 , _session_is_new (false)
295 , last_key_press_time (0)
299 , rc_option_editor (0)
300 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
301 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
302 , about (X_("about"), _("About"))
303 , location_ui (X_("locations"), S_("Ranges|Locations"))
304 , route_params (X_("inspector"), _("Tracks and Busses"))
305 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
306 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
307 , lua_script_window (X_("script-manager"), _("Script Manager"))
308 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
309 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
310 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
311 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
312 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
313 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
314 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
315 , video_server_process (0)
317 , have_configure_timeout (false)
318 , last_configure_time (0)
320 , have_disk_speed_dialog_displayed (false)
321 , _status_bar_visibility (X_("status-bar"))
322 , _feedback_exists (false)
323 , _log_not_acknowledged (LogLevelNone)
324 , duplicate_routes_dialog (0)
325 , editor_visibility_button (S_("Window|Editor"))
326 , mixer_visibility_button (S_("Window|Mixer"))
327 , prefs_visibility_button (S_("Window|Preferences"))
329 Gtkmm2ext::init (localedir);
331 UIConfiguration::instance().post_gui_init ();
333 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
334 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
336 /* configuration was modified, exit immediately */
341 if (string (VERSIONSTRING).find (".pre") != string::npos) {
342 /* check this is not being run from ./ardev etc. */
343 if (!running_from_source_tree ()) {
344 pre_release_dialog ();
348 if (theArdourUI == 0) {
352 /* track main window visibility */
354 main_window_visibility = new VisibilityTracker (_main_window);
356 /* stop libxml from spewing to stdout/stderr */
358 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
359 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
361 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
362 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
363 UIConfiguration::instance().map_parameters (pc);
365 roll_button.set_controllable (roll_controllable);
366 stop_button.set_controllable (stop_controllable);
367 goto_start_button.set_controllable (goto_start_controllable);
368 goto_end_button.set_controllable (goto_end_controllable);
369 auto_loop_button.set_controllable (auto_loop_controllable);
370 play_selection_button.set_controllable (play_selection_controllable);
371 rec_button.set_controllable (rec_controllable);
373 roll_button.set_name ("transport button");
374 stop_button.set_name ("transport button");
375 goto_start_button.set_name ("transport button");
376 goto_end_button.set_name ("transport button");
377 auto_loop_button.set_name ("transport button");
378 play_selection_button.set_name ("transport button");
379 rec_button.set_name ("transport recenable button");
380 midi_panic_button.set_name ("transport button");
382 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
383 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
385 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
387 /* handle dialog requests */
389 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
391 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
393 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
395 /* handle Audio/MIDI setup when session requires it */
397 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
399 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
401 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
403 /* handle sr mismatch with a dialog - cross-thread from engine */
404 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
406 /* handle requests to quit (coming from JACK session) */
408 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
410 /* tell the user about feedback */
412 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
413 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
415 /* handle requests to deal with missing files */
417 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
419 /* and ambiguous files */
421 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
423 /* also plugin scan messages */
424 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
425 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
427 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
429 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
432 /* lets get this party started */
434 setup_gtk_ardour_enums ();
437 SessionEvent::create_per_thread_pool ("GUI", 4096);
439 /* we like keyboards */
441 keyboard = new ArdourKeyboard(*this);
443 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
445 keyboard->set_state (*node, Stateful::loading_state_version);
448 UIConfiguration::instance().reset_dpi ();
450 TimeAxisViewItem::set_constant_heights ();
452 /* Set this up so that our window proxies can register actions */
454 ActionManager::init ();
456 /* The following must happen after ARDOUR::init() so that Config is set up */
458 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
461 key_editor.set_state (*ui_xml, 0);
462 session_option_editor.set_state (*ui_xml, 0);
463 speaker_config_window.set_state (*ui_xml, 0);
464 about.set_state (*ui_xml, 0);
465 add_route_dialog.set_state (*ui_xml, 0);
466 add_video_dialog.set_state (*ui_xml, 0);
467 route_params.set_state (*ui_xml, 0);
468 bundle_manager.set_state (*ui_xml, 0);
469 location_ui.set_state (*ui_xml, 0);
470 big_clock_window.set_state (*ui_xml, 0);
471 audio_port_matrix.set_state (*ui_xml, 0);
472 midi_port_matrix.set_state (*ui_xml, 0);
473 export_video_dialog.set_state (*ui_xml, 0);
474 lua_script_window.set_state (*ui_xml, 0);
477 /* Separate windows */
479 WM::Manager::instance().register_window (&key_editor);
480 WM::Manager::instance().register_window (&session_option_editor);
481 WM::Manager::instance().register_window (&speaker_config_window);
482 WM::Manager::instance().register_window (&about);
483 WM::Manager::instance().register_window (&add_route_dialog);
484 WM::Manager::instance().register_window (&add_video_dialog);
485 WM::Manager::instance().register_window (&route_params);
486 WM::Manager::instance().register_window (&audio_midi_setup);
487 WM::Manager::instance().register_window (&export_video_dialog);
488 WM::Manager::instance().register_window (&lua_script_window);
489 WM::Manager::instance().register_window (&bundle_manager);
490 WM::Manager::instance().register_window (&location_ui);
491 WM::Manager::instance().register_window (&big_clock_window);
492 WM::Manager::instance().register_window (&audio_port_matrix);
493 WM::Manager::instance().register_window (&midi_port_matrix);
495 /* do not retain position for add route dialog */
496 add_route_dialog.set_state_mask (WindowProxy::Size);
498 /* Trigger setting up the color scheme and loading the GTK RC file */
500 UIConfiguration::instance().load_rc_file (false);
502 _process_thread = new ProcessThread ();
503 _process_thread->init ();
505 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
511 ARDOUR_UI::pre_release_dialog ()
513 ArdourDialog d (_("Pre-Release Warning"), true, false);
514 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
516 Label* label = manage (new Label);
517 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
518 There are still several issues and bugs to be worked on,\n\
519 as well as general workflow improvements, before this can be considered\n\
520 release software. So, a few guidelines:\n\
522 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
523 though it may be so, depending on your workflow.\n\
524 2) Please wait for a helpful writeup of new features.\n\
525 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
526 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
527 making sure to note the product version number as 5.0-pre.\n\
528 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
529 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
530 can get there directly from within the program via the Help->Chat menu option.\n\
532 Full information on all the above can be found on the support page at\n\
534 http://ardour.org/support\n\
535 "), PROGRAM_NAME, VERSIONSTRING));
537 d.get_vbox()->set_border_width (12);
538 d.get_vbox()->pack_start (*label, false, false, 12);
539 d.get_vbox()->show_all ();
544 GlobalPortMatrixWindow*
545 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
550 return new GlobalPortMatrixWindow (_session, type);
554 ARDOUR_UI::attach_to_engine ()
556 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
557 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
561 ARDOUR_UI::engine_stopped ()
563 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
564 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
565 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
566 update_sample_rate (0);
571 ARDOUR_UI::engine_running ()
573 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
574 if (first_time_engine_run) {
576 first_time_engine_run = false;
580 _session->reset_xrun_count ();
582 update_disk_space ();
584 update_xrun_count ();
585 update_sample_rate (AudioEngine::instance()->sample_rate());
586 update_timecode_format ();
587 update_peak_thread_work ();
588 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
589 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
593 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
595 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
596 /* we can't rely on the original string continuing to exist when we are called
597 again in the GUI thread, so make a copy and note that we need to
600 char *copy = strdup (reason);
601 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
605 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
606 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
608 update_sample_rate (0);
612 /* if the reason is a non-empty string, it means that the backend was shutdown
613 rather than just Ardour.
616 if (strlen (reason)) {
617 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
619 msgstr = string_compose (_("\
620 The audio backend has either been shutdown or it\n\
621 disconnected %1 because %1\n\
622 was not fast enough. Try to restart\n\
623 the audio backend and save the session."), PROGRAM_NAME);
626 MessageDialog msg (_main_window, msgstr);
627 pop_back_splash (msg);
631 free (const_cast<char*> (reason));
636 ARDOUR_UI::post_engine ()
638 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
640 #ifdef AUDIOUNIT_SUPPORT
642 if (AUPluginInfo::au_get_crashlog(au_msg)) {
643 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
644 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
645 info << au_msg << endmsg;
649 ARDOUR::init_post_engine ();
651 /* connect to important signals */
653 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
654 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
655 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
656 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
657 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
659 if (setup_windows ()) {
660 throw failed_constructor ();
663 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
664 XMLNode* n = Config->extra_xml (X_("UI"));
666 _status_bar_visibility.set_state (*n);
669 check_memory_locking();
671 /* this is the first point at which all the possible actions are
672 * available, because some of the available actions are dependent on
673 * aspects of the engine/backend.
676 if (ARDOUR_COMMAND_LINE::show_key_actions) {
679 vector<string> paths;
680 vector<string> labels;
681 vector<string> tooltips;
683 vector<Glib::RefPtr<Gtk::Action> > actions;
685 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
687 vector<string>::iterator k;
688 vector<string>::iterator p;
690 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
695 cout << *p << " => " << *k << endl;
699 halt_connection.disconnect ();
700 AudioEngine::instance()->stop ();
704 /* this being a GUI and all, we want peakfiles */
706 AudioFileSource::set_build_peakfiles (true);
707 AudioFileSource::set_build_missing_peakfiles (true);
709 /* set default clock modes */
711 primary_clock->set_mode (AudioClock::Timecode);
712 secondary_clock->set_mode (AudioClock::BBT);
714 /* start the time-of-day-clock */
717 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
718 update_wall_clock ();
719 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
724 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
725 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
726 Config->map_parameters (pc);
728 UIConfiguration::instance().map_parameters (pc);
732 ARDOUR_UI::~ARDOUR_UI ()
734 UIConfiguration::instance().save_state();
738 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
739 // don't bother at 'real' exit. the OS cleans up for us.
740 delete big_clock; big_clock = 0;
741 delete primary_clock; primary_clock = 0;
742 delete secondary_clock; secondary_clock = 0;
743 delete _process_thread; _process_thread = 0;
744 delete time_info_box; time_info_box = 0;
745 delete meterbridge; meterbridge = 0;
746 delete luawindow; luawindow = 0;
747 delete editor; editor = 0;
748 delete mixer; mixer = 0;
750 delete gui_object_state; gui_object_state = 0;
751 delete main_window_visibility;
752 FastMeter::flush_pattern_cache ();
753 PixFader::flush_pattern_cache ();
757 /* Small trick to flush main-thread event pool.
758 * Other thread-pools are destroyed at pthread_exit(),
759 * but tmain thread termination is too late to trigger Pool::~Pool()
761 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.
762 delete ev->event_pool();
767 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
769 if (Splash::instance()) {
770 Splash::instance()->pop_back_for (win);
775 ARDOUR_UI::configure_timeout ()
777 if (last_configure_time == 0) {
778 /* no configure events yet */
782 /* force a gap of 0.5 seconds since the last configure event
785 if (get_microseconds() - last_configure_time < 500000) {
788 have_configure_timeout = false;
789 save_ardour_state ();
795 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
797 if (have_configure_timeout) {
798 last_configure_time = get_microseconds();
800 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
801 have_configure_timeout = true;
808 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
810 XMLProperty const * prop;
812 if ((prop = node.property ("roll")) != 0) {
813 roll_controllable->set_id (prop->value());
815 if ((prop = node.property ("stop")) != 0) {
816 stop_controllable->set_id (prop->value());
818 if ((prop = node.property ("goto-start")) != 0) {
819 goto_start_controllable->set_id (prop->value());
821 if ((prop = node.property ("goto-end")) != 0) {
822 goto_end_controllable->set_id (prop->value());
824 if ((prop = node.property ("auto-loop")) != 0) {
825 auto_loop_controllable->set_id (prop->value());
827 if ((prop = node.property ("play-selection")) != 0) {
828 play_selection_controllable->set_id (prop->value());
830 if ((prop = node.property ("rec")) != 0) {
831 rec_controllable->set_id (prop->value());
833 if ((prop = node.property ("shuttle")) != 0) {
834 shuttle_box.controllable()->set_id (prop->value());
839 ARDOUR_UI::get_transport_controllable_state ()
841 XMLNode* node = new XMLNode(X_("TransportControllables"));
844 roll_controllable->id().print (buf, sizeof (buf));
845 node->add_property (X_("roll"), buf);
846 stop_controllable->id().print (buf, sizeof (buf));
847 node->add_property (X_("stop"), buf);
848 goto_start_controllable->id().print (buf, sizeof (buf));
849 node->add_property (X_("goto_start"), buf);
850 goto_end_controllable->id().print (buf, sizeof (buf));
851 node->add_property (X_("goto_end"), buf);
852 auto_loop_controllable->id().print (buf, sizeof (buf));
853 node->add_property (X_("auto_loop"), buf);
854 play_selection_controllable->id().print (buf, sizeof (buf));
855 node->add_property (X_("play_selection"), buf);
856 rec_controllable->id().print (buf, sizeof (buf));
857 node->add_property (X_("rec"), buf);
858 shuttle_box.controllable()->id().print (buf, sizeof (buf));
859 node->add_property (X_("shuttle"), buf);
865 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
868 _session->save_state (snapshot_name);
873 ARDOUR_UI::autosave_session ()
875 if (g_main_depth() > 1) {
876 /* inside a recursive main loop,
877 give up because we may not be able to
883 if (!Config->get_periodic_safety_backups()) {
888 _session->maybe_write_autosave();
895 ARDOUR_UI::session_dirty_changed ()
902 ARDOUR_UI::update_autosave ()
904 if (_session && _session->dirty()) {
905 if (_autosave_connection.connected()) {
906 _autosave_connection.disconnect();
909 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
910 Config->get_periodic_safety_backup_interval() * 1000);
913 if (_autosave_connection.connected()) {
914 _autosave_connection.disconnect();
920 ARDOUR_UI::check_announcements ()
923 string _annc_filename;
926 _annc_filename = PROGRAM_NAME "_announcements_osx_";
927 #elif defined PLATFORM_WINDOWS
928 _annc_filename = PROGRAM_NAME "_announcements_windows_";
930 _annc_filename = PROGRAM_NAME "_announcements_linux_";
932 _annc_filename.append (VERSIONSTRING);
934 _announce_string = "";
936 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
937 FILE* fin = g_fopen (path.c_str(), "rb");
939 while (!feof (fin)) {
942 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
945 _announce_string.append (tmp, len);
950 pingback (VERSIONSTRING, path);
955 _hide_splash (gpointer arg)
957 ((ARDOUR_UI*)arg)->hide_splash();
962 ARDOUR_UI::starting ()
964 Application* app = Application::instance ();
966 bool brand_new_user = ArdourStartup::required ();
968 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
969 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
971 if (ARDOUR_COMMAND_LINE::check_announcements) {
972 check_announcements ();
977 /* we need to create this early because it may need to set the
978 * audio backend end up.
982 audio_midi_setup.get (true);
984 std::cerr << "audio-midi engine setup failed."<< std::endl;
988 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
989 nsm = new NSM_Client;
990 if (!nsm->init (nsm_url)) {
991 /* the ardour executable may have different names:
993 * waf's obj.target for distro versions: eg ardour4, ardourvst4
994 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
995 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
997 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
999 const char *process_name = g_getenv ("ARDOUR_SELF");
1000 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1003 // wait for announce reply from nsm server
1004 for ( i = 0; i < 5000; ++i) {
1008 if (nsm->is_active()) {
1013 error << _("NSM server did not announce itself") << endmsg;
1016 // wait for open command from nsm server
1017 for ( i = 0; i < 5000; ++i) {
1019 Glib::usleep (1000);
1020 if (nsm->client_id ()) {
1026 error << _("NSM: no client ID provided") << endmsg;
1030 if (_session && nsm) {
1031 _session->set_nsm_state( nsm->is_active() );
1033 error << _("NSM: no session created") << endmsg;
1037 // nsm requires these actions disabled
1038 vector<string> action_names;
1039 action_names.push_back("SaveAs");
1040 action_names.push_back("Rename");
1041 action_names.push_back("New");
1042 action_names.push_back("Open");
1043 action_names.push_back("Recent");
1044 action_names.push_back("Close");
1046 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1047 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1049 act->set_sensitive (false);
1056 error << _("NSM: initialization failed") << endmsg;
1062 if (brand_new_user) {
1063 _initial_verbose_plugin_scan = true;
1068 _initial_verbose_plugin_scan = false;
1069 switch (s.response ()) {
1070 case Gtk::RESPONSE_OK:
1077 // TODO: maybe IFF brand_new_user
1078 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1079 std::string dspd (Config->get_default_session_parent_dir());
1080 Searchpath ds (ARDOUR::ardour_data_search_path());
1081 ds.add_subdirectory_to_paths ("sessions");
1082 vector<string> demos;
1083 find_files_matching_pattern (demos, ds, "*.tar.xz");
1085 ARDOUR::RecentSessions rs;
1086 ARDOUR::read_recent_sessions (rs);
1088 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1089 /* "demo-session" must be inside "demo-session.tar.xz"
1092 std::string name = basename_nosuffix (basename_nosuffix (*i));
1093 std::string path = Glib::build_filename (dspd, name);
1094 /* skip if session-dir already exists */
1095 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1098 /* skip sessions that are already in 'recent'.
1099 * eg. a new user changed <session-default-dir> shorly after installation
1101 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1102 if ((*r).first == name) {
1107 PBD::FileArchive ar (*i);
1108 if (0 == ar.inflate (dspd)) {
1109 store_recent_sessions (name, path);
1110 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1116 #ifdef NO_PLUGIN_STATE
1118 ARDOUR::RecentSessions rs;
1119 ARDOUR::read_recent_sessions (rs);
1121 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1123 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1125 /* already used Ardour, have sessions ... warn about plugin state */
1127 ArdourDialog d (_("Free/Demo Version Warning"), true);
1129 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1130 CheckButton c (_("Don't warn me about this again"));
1132 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"),
1133 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1134 _("It will not restore OR save any plugin settings"),
1135 _("If you load an existing session with plugin settings\n"
1136 "they will not be used and will be lost."),
1137 _("To get full access to updates without this limitation\n"
1138 "consider becoming a subscriber for a low cost every month.")));
1139 l.set_justify (JUSTIFY_CENTER);
1141 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1143 d.get_vbox()->pack_start (l, true, true);
1144 d.get_vbox()->pack_start (b, false, false, 12);
1145 d.get_vbox()->pack_start (c, false, false, 12);
1147 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1148 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1152 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1154 if (d.run () != RESPONSE_OK) {
1160 /* go get a session */
1162 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1164 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1165 std::cerr << "Cannot get session parameters."<< std::endl;
1172 WM::Manager::instance().show_visible ();
1174 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1175 * editor window, and we may want stuff to be hidden.
1177 _status_bar_visibility.update ();
1179 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1181 if (splash && splash->is_visible()) {
1182 // in 1 second, hide the splash screen
1183 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1186 /* all other dialogs are created conditionally */
1192 ARDOUR_UI::check_memory_locking ()
1194 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1195 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1199 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1201 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1203 struct rlimit limits;
1205 long pages, page_size;
1207 size_t pages_len=sizeof(pages);
1208 if ((page_size = getpagesize()) < 0 ||
1209 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1211 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1216 ram = (int64_t) pages * (int64_t) page_size;
1219 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1223 if (limits.rlim_cur != RLIM_INFINITY) {
1225 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1229 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1230 "This might cause %1 to run out of memory before your system "
1231 "runs out of memory. \n\n"
1232 "You can view the memory limit with 'ulimit -l', "
1233 "and it is normally controlled by %2"),
1236 X_("/etc/login.conf")
1238 X_(" /etc/security/limits.conf")
1242 msg.set_default_response (RESPONSE_OK);
1244 VBox* vbox = msg.get_vbox();
1246 CheckButton cb (_("Do not show this window again"));
1247 hbox.pack_start (cb, true, false);
1248 vbox->pack_start (hbox);
1253 pop_back_splash (msg);
1257 if (cb.get_active()) {
1258 XMLNode node (X_("no-memory-warning"));
1259 Config->add_instant_xml (node);
1264 #endif // !__APPLE__
1269 ARDOUR_UI::queue_finish ()
1271 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1275 ARDOUR_UI::idle_finish ()
1278 return false; /* do not call again */
1285 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1287 if (_session->dirty()) {
1288 vector<string> actions;
1289 actions.push_back (_("Don't quit"));
1290 actions.push_back (_("Just quit"));
1291 actions.push_back (_("Save and quit"));
1292 switch (ask_about_saving_session(actions)) {
1297 /* use the default name */
1298 if (save_state_canfail ("")) {
1299 /* failed - don't quit */
1300 MessageDialog msg (_main_window,
1301 string_compose (_("\
1302 %1 was unable to save your session.\n\n\
1303 If you still wish to quit, please use the\n\n\
1304 \"Just quit\" option."), PROGRAM_NAME));
1305 pop_back_splash(msg);
1315 second_connection.disconnect ();
1316 point_one_second_connection.disconnect ();
1317 point_zero_something_second_connection.disconnect();
1318 fps_connection.disconnect();
1321 delete ARDOUR_UI::instance()->video_timeline;
1322 ARDOUR_UI::instance()->video_timeline = NULL;
1323 stop_video_server();
1325 /* Save state before deleting the session, as that causes some
1326 windows to be destroyed before their visible state can be
1329 save_ardour_state ();
1331 if (key_editor.get (false)) {
1332 key_editor->disconnect ();
1335 close_all_dialogs ();
1338 _session->set_clean ();
1339 _session->remove_pending_capture_state ();
1344 halt_connection.disconnect ();
1345 AudioEngine::instance()->stop ();
1346 #ifdef WINDOWS_VST_SUPPORT
1347 fst_stop_threading();
1353 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1355 ArdourDialog window (_("Unsaved Session"));
1356 Gtk::HBox dhbox; // the hbox for the image and text
1357 Gtk::Label prompt_label;
1358 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1362 assert (actions.size() >= 3);
1364 window.add_button (actions[0], RESPONSE_REJECT);
1365 window.add_button (actions[1], RESPONSE_APPLY);
1366 window.add_button (actions[2], RESPONSE_ACCEPT);
1368 window.set_default_response (RESPONSE_ACCEPT);
1370 Gtk::Button noquit_button (msg);
1371 noquit_button.set_name ("EditorGTKButton");
1375 if (_session->snap_name() == _session->name()) {
1376 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?"),
1377 _session->snap_name());
1379 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?"),
1380 _session->snap_name());
1383 prompt_label.set_text (prompt);
1384 prompt_label.set_name (X_("PrompterLabel"));
1385 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1387 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1388 dhbox.set_homogeneous (false);
1389 dhbox.pack_start (*dimage, false, false, 5);
1390 dhbox.pack_start (prompt_label, true, false, 5);
1391 window.get_vbox()->pack_start (dhbox);
1393 window.set_name (_("Prompter"));
1394 window.set_modal (true);
1395 window.set_resizable (false);
1398 prompt_label.show();
1403 ResponseType r = (ResponseType) window.run();
1408 case RESPONSE_ACCEPT: // save and get out of here
1410 case RESPONSE_APPLY: // get out of here
1421 ARDOUR_UI::every_second ()
1424 update_xrun_count ();
1425 update_buffer_load ();
1426 update_disk_space ();
1427 update_timecode_format ();
1428 update_peak_thread_work ();
1430 if (nsm && nsm->is_active ()) {
1433 if (!_was_dirty && _session->dirty ()) {
1437 else if (_was_dirty && !_session->dirty ()){
1445 ARDOUR_UI::every_point_one_seconds ()
1447 // TODO get rid of this..
1448 // ShuttleControl is updated directly via TransportStateChange signal
1452 ARDOUR_UI::every_point_zero_something_seconds ()
1454 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1456 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1457 float mpeak = editor_meter->update_meters();
1458 if (mpeak > editor_meter_max_peak) {
1459 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1460 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1467 ARDOUR_UI::set_fps_timeout_connection ()
1469 unsigned int interval = 40;
1470 if (!_session) return;
1471 if (_session->timecode_frames_per_second() != 0) {
1472 /* ideally we'll use a select() to sleep and not accumulate
1473 * idle time to provide a regular periodic signal.
1474 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1475 * However, that'll require a dedicated thread and cross-thread
1476 * signals to the GUI Thread..
1478 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1479 * _session->frame_rate() / _session->nominal_frame_rate()
1480 / _session->timecode_frames_per_second()
1482 #ifdef PLATFORM_WINDOWS
1483 // the smallest windows scheduler time-slice is ~15ms.
1484 // periodic GUI timeouts shorter than that will cause
1485 // WaitForSingleObject to spinlock (100% of one CPU Core)
1486 // and gtk never enters idle mode.
1487 // also changing timeBeginPeriod(1) does not affect that in
1488 // any beneficial way, so we just limit the max rate for now.
1489 interval = std::max(30u, interval); // at most ~33Hz.
1491 interval = std::max(8u, interval); // at most 120Hz.
1494 fps_connection.disconnect();
1495 Timers::set_fps_interval (interval);
1499 ARDOUR_UI::update_sample_rate (framecnt_t)
1503 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1505 if (!AudioEngine::instance()->connected()) {
1507 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1511 framecnt_t rate = AudioEngine::instance()->sample_rate();
1514 /* no sample rate available */
1515 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1518 if (fmod (rate, 1000.0) != 0.0) {
1519 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1520 (float) rate / 1000.0f,
1521 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1523 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1525 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1529 sample_rate_label.set_markup (buf);
1533 ARDOUR_UI::update_format ()
1536 format_label.set_text ("");
1541 s << _("File:") << X_(" <span foreground=\"green\">");
1543 switch (_session->config.get_native_file_header_format ()) {
1575 switch (_session->config.get_native_file_data_format ()) {
1589 format_label.set_markup (s.str ());
1593 ARDOUR_UI::update_xrun_count ()
1597 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1598 should also be changed.
1602 const unsigned int x = _session->get_xrun_count ();
1604 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1606 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1609 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1611 xrun_label.set_markup (buf);
1612 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1616 ARDOUR_UI::update_cpu_load ()
1620 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1621 should also be changed.
1624 double const c = AudioEngine::instance()->get_dsp_load ();
1625 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1626 cpu_load_label.set_markup (buf);
1630 ARDOUR_UI::update_peak_thread_work ()
1633 const int c = SourceFactory::peak_work_queue_length ();
1635 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1636 peak_thread_work_label.set_markup (buf);
1638 peak_thread_work_label.set_markup (X_(""));
1643 ARDOUR_UI::update_buffer_load ()
1647 uint32_t const playback = _session ? _session->playback_load () : 100;
1648 uint32_t const capture = _session ? _session->capture_load () : 100;
1650 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1651 should also be changed.
1657 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1658 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1659 playback <= 5 ? X_("red") : X_("green"),
1661 capture <= 5 ? X_("red") : X_("green"),
1665 buffer_load_label.set_markup (buf);
1667 buffer_load_label.set_text ("");
1672 ARDOUR_UI::count_recenabled_streams (Route& route)
1674 Track* track = dynamic_cast<Track*>(&route);
1675 if (track && track->rec_enable_control()->get_value()) {
1676 rec_enabled_streams += track->n_inputs().n_total();
1681 ARDOUR_UI::update_disk_space()
1683 if (_session == 0) {
1687 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1689 framecnt_t fr = _session->frame_rate();
1692 /* skip update - no SR available */
1697 /* Available space is unknown */
1698 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1699 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1700 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1702 rec_enabled_streams = 0;
1703 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1705 framecnt_t frames = opt_frames.get_value_or (0);
1707 if (rec_enabled_streams) {
1708 frames /= rec_enabled_streams;
1715 hrs = frames / (fr * 3600);
1718 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1720 frames -= hrs * fr * 3600;
1721 mins = frames / (fr * 60);
1722 frames -= mins * fr * 60;
1725 bool const low = (hrs == 0 && mins <= 30);
1729 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1730 low ? X_("red") : X_("green"),
1736 disk_space_label.set_markup (buf);
1740 ARDOUR_UI::update_timecode_format ()
1746 TimecodeSlave* tcslave;
1747 SyncSource sync_src = Config->get_sync_source();
1749 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1750 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1755 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1756 matching ? X_("green") : X_("red"),
1757 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1759 snprintf (buf, sizeof (buf), "TC: n/a");
1762 timecode_format_label.set_markup (buf);
1766 ARDOUR_UI::update_wall_clock ()
1770 static int last_min = -1;
1773 tm_now = localtime (&now);
1774 if (last_min != tm_now->tm_min) {
1776 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1777 wall_clock_label.set_text (buf);
1778 last_min = tm_now->tm_min;
1785 ARDOUR_UI::open_recent_session ()
1787 bool can_return = (_session != 0);
1789 SessionDialog recent_session_dialog;
1793 ResponseType r = (ResponseType) recent_session_dialog.run ();
1796 case RESPONSE_ACCEPT:
1800 recent_session_dialog.hide();
1807 recent_session_dialog.hide();
1811 std::string path = recent_session_dialog.session_folder();
1812 std::string state = recent_session_dialog.session_name (should_be_new);
1814 if (should_be_new == true) {
1818 _session_is_new = false;
1820 if (load_session (path, state) == 0) {
1826 if (splash && splash->is_visible()) {
1827 // in 1 second, hide the splash screen
1828 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1833 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1835 if (!AudioEngine::instance()->connected()) {
1836 MessageDialog msg (parent, string_compose (
1837 _("%1 is not connected to any audio backend.\n"
1838 "You cannot open or close sessions in this condition"),
1840 pop_back_splash (msg);
1848 ARDOUR_UI::open_session ()
1850 if (!check_audioengine (_main_window)) {
1854 /* ardour sessions are folders */
1855 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1856 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1857 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1858 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1861 string session_parent_dir = Glib::path_get_dirname(_session->path());
1862 open_session_selector.set_current_folder(session_parent_dir);
1864 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1867 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1869 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1870 string default_session_folder = Config->get_default_session_parent_dir();
1871 open_session_selector.add_shortcut_folder (default_session_folder);
1873 catch (Glib::Error & e) {
1874 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1877 FileFilter session_filter;
1878 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1879 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1880 open_session_selector.add_filter (session_filter);
1882 FileFilter archive_filter;
1883 archive_filter.add_pattern (X_("*.tar.xz"));
1884 archive_filter.set_name (_("Session Archives"));
1886 open_session_selector.add_filter (archive_filter);
1888 open_session_selector.set_filter (session_filter);
1890 int response = open_session_selector.run();
1891 open_session_selector.hide ();
1893 if (response == Gtk::RESPONSE_CANCEL) {
1897 string session_path = open_session_selector.get_filename();
1901 if (session_path.length() > 0) {
1902 int rv = ARDOUR::inflate_session (session_path,
1903 Config->get_default_session_parent_dir(), path, name);
1905 _session_is_new = false;
1906 load_session (path, name);
1909 MessageDialog msg (_main_window,
1910 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1913 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1914 _session_is_new = isnew;
1915 load_session (path, name);
1921 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1927 _session->vca_manager().create_vca (n, name_template);
1931 ARDOUR_UI::session_add_mixed_track (
1932 const ChanCount& input,
1933 const ChanCount& output,
1934 RouteGroup* route_group,
1936 const string& name_template,
1938 PluginInfoPtr instrument,
1939 Plugin::PresetRecord* pset,
1940 ARDOUR::PresentationInfo::order_t order)
1942 list<boost::shared_ptr<MidiTrack> > tracks;
1944 if (_session == 0) {
1945 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1950 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1952 if (tracks.size() != how_many) {
1953 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1958 display_insufficient_ports_message ();
1963 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1964 (*i)->set_strict_io (true);
1970 ARDOUR_UI::session_add_midi_bus (
1971 RouteGroup* route_group,
1973 const string& name_template,
1975 PluginInfoPtr instrument,
1976 Plugin::PresetRecord* pset,
1977 ARDOUR::PresentationInfo::order_t order)
1981 if (_session == 0) {
1982 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1988 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1989 if (routes.size() != how_many) {
1990 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1995 display_insufficient_ports_message ();
2000 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2001 (*i)->set_strict_io (true);
2007 ARDOUR_UI::session_add_midi_route (
2009 RouteGroup* route_group,
2011 const string& name_template,
2013 PluginInfoPtr instrument,
2014 Plugin::PresetRecord* pset,
2015 ARDOUR::PresentationInfo::order_t order)
2017 ChanCount one_midi_channel;
2018 one_midi_channel.set (DataType::MIDI, 1);
2021 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2023 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2028 ARDOUR_UI::session_add_audio_route (
2030 int32_t input_channels,
2031 int32_t output_channels,
2032 ARDOUR::TrackMode mode,
2033 RouteGroup* route_group,
2035 string const & name_template,
2037 ARDOUR::PresentationInfo::order_t order)
2039 list<boost::shared_ptr<AudioTrack> > tracks;
2042 if (_session == 0) {
2043 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2049 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2051 if (tracks.size() != how_many) {
2052 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2058 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2060 if (routes.size() != how_many) {
2061 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2068 display_insufficient_ports_message ();
2073 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2074 (*i)->set_strict_io (true);
2076 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2077 (*i)->set_strict_io (true);
2083 ARDOUR_UI::display_insufficient_ports_message ()
2085 MessageDialog msg (_main_window,
2086 string_compose (_("There are insufficient ports available\n\
2087 to create a new track or bus.\n\
2088 You should save %1, exit and\n\
2089 restart with more ports."), PROGRAM_NAME));
2090 pop_back_splash (msg);
2095 ARDOUR_UI::transport_goto_start ()
2098 _session->goto_start();
2100 /* force displayed area in editor to start no matter
2101 what "follow playhead" setting is.
2105 editor->center_screen (_session->current_start_frame ());
2111 ARDOUR_UI::transport_goto_zero ()
2114 _session->request_locate (0);
2116 /* force displayed area in editor to start no matter
2117 what "follow playhead" setting is.
2121 editor->reset_x_origin (0);
2127 ARDOUR_UI::transport_goto_wallclock ()
2129 if (_session && editor) {
2136 localtime_r (&now, &tmnow);
2138 framecnt_t frame_rate = _session->frame_rate();
2140 if (frame_rate == 0) {
2141 /* no frame rate available */
2145 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2146 frames += tmnow.tm_min * (60 * frame_rate);
2147 frames += tmnow.tm_sec * frame_rate;
2149 _session->request_locate (frames, _session->transport_rolling ());
2151 /* force displayed area in editor to start no matter
2152 what "follow playhead" setting is.
2156 editor->center_screen (frames);
2162 ARDOUR_UI::transport_goto_end ()
2165 framepos_t const frame = _session->current_end_frame();
2166 _session->request_locate (frame);
2168 /* force displayed area in editor to start no matter
2169 what "follow playhead" setting is.
2173 editor->center_screen (frame);
2179 ARDOUR_UI::transport_stop ()
2185 if (_session->is_auditioning()) {
2186 _session->cancel_audition ();
2190 _session->request_stop (false, true);
2193 /** Check if any tracks are record enabled. If none are, record enable all of them.
2194 * @return true if track record-enabled status was changed, false otherwise.
2197 ARDOUR_UI::trx_record_enable_all_tracks ()
2203 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2204 bool none_record_enabled = true;
2206 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2207 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2210 if (t->rec_enable_control()->get_value()) {
2211 none_record_enabled = false;
2216 if (none_record_enabled) {
2217 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2220 return none_record_enabled;
2224 ARDOUR_UI::transport_record (bool roll)
2227 switch (_session->record_status()) {
2228 case Session::Disabled:
2229 if (_session->ntracks() == 0) {
2230 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."));
2234 if (Profile->get_trx()) {
2235 roll = trx_record_enable_all_tracks ();
2237 _session->maybe_enable_record ();
2242 case Session::Recording:
2244 _session->request_stop();
2246 _session->disable_record (false, true);
2250 case Session::Enabled:
2251 _session->disable_record (false, true);
2257 ARDOUR_UI::transport_roll ()
2263 if (_session->is_auditioning()) {
2268 if (_session->config.get_external_sync()) {
2269 switch (Config->get_sync_source()) {
2273 /* transport controlled by the master */
2279 bool rolling = _session->transport_rolling();
2281 if (_session->get_play_loop()) {
2283 /* If loop playback is not a mode, then we should cancel
2284 it when this action is requested. If it is a mode
2285 we just leave it in place.
2288 if (!Config->get_loop_is_mode()) {
2289 /* XXX it is not possible to just leave seamless loop and keep
2290 playing at present (nov 4th 2009)
2292 if (!Config->get_seamless_loop()) {
2293 /* stop loop playback and stop rolling */
2294 _session->request_play_loop (false, true);
2295 } else if (rolling) {
2296 /* stop loop playback but keep rolling */
2297 _session->request_play_loop (false, false);
2301 } else if (_session->get_play_range () ) {
2302 /* stop playing a range if we currently are */
2303 _session->request_play_range (0, true);
2307 _session->request_transport_speed (1.0f);
2312 ARDOUR_UI::get_smart_mode() const
2314 return ( editor->get_smart_mode() );
2319 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2325 if (_session->is_auditioning()) {
2326 _session->cancel_audition ();
2330 if (_session->config.get_external_sync()) {
2331 switch (Config->get_sync_source()) {
2335 /* transport controlled by the master */
2340 bool rolling = _session->transport_rolling();
2341 bool affect_transport = true;
2343 if (rolling && roll_out_of_bounded_mode) {
2344 /* drop out of loop/range playback but leave transport rolling */
2345 if (_session->get_play_loop()) {
2346 if (_session->actively_recording()) {
2348 /* just stop using the loop, then actually stop
2351 _session->request_play_loop (false, affect_transport);
2354 if (Config->get_seamless_loop()) {
2355 /* the disk buffers contain copies of the loop - we can't
2356 just keep playing, so stop the transport. the user
2357 can restart as they wish.
2359 affect_transport = true;
2361 /* disk buffers are normal, so we can keep playing */
2362 affect_transport = false;
2364 _session->request_play_loop (false, affect_transport);
2366 } else if (_session->get_play_range ()) {
2367 affect_transport = false;
2368 _session->request_play_range (0, true);
2372 if (affect_transport) {
2374 _session->request_stop (with_abort, true);
2376 } else if (!with_abort) { /* with_abort == true means the
2377 * command was intended to stop
2378 * transport, not start.
2381 /* the only external sync condition we can be in here
2382 * would be Engine (JACK) sync, in which case we still
2386 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
2387 _session->request_play_range (&editor->get_selection().time, true);
2388 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2390 _session->request_transport_speed (1.0f);
2396 ARDOUR_UI::toggle_session_auto_loop ()
2402 Location * looploc = _session->locations()->auto_loop_location();
2408 if (_session->get_play_loop()) {
2410 /* looping enabled, our job is to disable it */
2412 _session->request_play_loop (false);
2416 /* looping not enabled, our job is to enable it.
2418 loop-is-NOT-mode: this action always starts the transport rolling.
2419 loop-IS-mode: this action simply sets the loop play mechanism, but
2420 does not start transport.
2422 if (Config->get_loop_is_mode()) {
2423 _session->request_play_loop (true, false);
2425 _session->request_play_loop (true, true);
2429 //show the loop markers
2430 looploc->set_hidden (false, this);
2434 ARDOUR_UI::transport_play_selection ()
2440 editor->play_selection ();
2444 ARDOUR_UI::transport_play_preroll ()
2449 editor->play_with_preroll ();
2453 ARDOUR_UI::transport_rewind (int option)
2455 float current_transport_speed;
2458 current_transport_speed = _session->transport_speed();
2460 if (current_transport_speed >= 0.0f) {
2463 _session->request_transport_speed (-1.0f);
2466 _session->request_transport_speed (-4.0f);
2469 _session->request_transport_speed (-0.5f);
2474 _session->request_transport_speed (current_transport_speed * 1.5f);
2480 ARDOUR_UI::transport_forward (int option)
2486 float current_transport_speed = _session->transport_speed();
2488 if (current_transport_speed <= 0.0f) {
2491 _session->request_transport_speed (1.0f);
2494 _session->request_transport_speed (4.0f);
2497 _session->request_transport_speed (0.5f);
2502 _session->request_transport_speed (current_transport_speed * 1.5f);
2507 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2513 boost::shared_ptr<Route> r;
2515 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2517 boost::shared_ptr<Track> t;
2519 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2520 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2526 ARDOUR_UI::map_transport_state ()
2529 auto_loop_button.unset_active_state ();
2530 play_selection_button.unset_active_state ();
2531 roll_button.unset_active_state ();
2532 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2533 layered_button.set_sensitive (false);
2537 shuttle_box.map_transport_state ();
2539 float sp = _session->transport_speed();
2545 if (_session->get_play_range()) {
2547 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2548 roll_button.unset_active_state ();
2549 auto_loop_button.unset_active_state ();
2551 } else if (_session->get_play_loop ()) {
2553 auto_loop_button.set_active (true);
2554 play_selection_button.set_active (false);
2555 if (Config->get_loop_is_mode()) {
2556 roll_button.set_active (true);
2558 roll_button.set_active (false);
2563 roll_button.set_active (true);
2564 play_selection_button.set_active (false);
2565 auto_loop_button.set_active (false);
2568 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2569 /* light up both roll and play-selection if they are joined */
2570 roll_button.set_active (true);
2571 play_selection_button.set_active (true);
2573 layered_button.set_sensitive (!_session->actively_recording ());
2575 stop_button.set_active (false);
2579 layered_button.set_sensitive (true);
2580 stop_button.set_active (true);
2581 roll_button.set_active (false);
2582 play_selection_button.set_active (false);
2583 if (Config->get_loop_is_mode ()) {
2584 auto_loop_button.set_active (_session->get_play_loop());
2586 auto_loop_button.set_active (false);
2588 update_disk_space ();
2593 ARDOUR_UI::blink_handler (bool blink_on)
2595 transport_rec_enable_blink (blink_on);
2596 solo_blink (blink_on);
2597 sync_blink (blink_on);
2598 audition_blink (blink_on);
2599 feedback_blink (blink_on);
2600 error_blink (blink_on);
2604 ARDOUR_UI::update_clocks ()
2606 if (!_session) return;
2608 if (editor && !editor->dragging_playhead()) {
2609 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2614 ARDOUR_UI::start_clocking ()
2616 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2617 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2619 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2624 ARDOUR_UI::stop_clocking ()
2626 clock_signal_connection.disconnect ();
2630 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2634 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2636 label->set_text (buf);
2637 bar->set_fraction (fraction);
2639 /* process events, redraws, etc. */
2641 while (gtk_events_pending()) {
2642 gtk_main_iteration ();
2645 return true; /* continue with save-as */
2649 ARDOUR_UI::save_session_as ()
2655 if (!save_as_dialog) {
2656 save_as_dialog = new SaveAsDialog;
2659 save_as_dialog->set_name (_session->name());
2661 int response = save_as_dialog->run ();
2663 save_as_dialog->hide ();
2666 case Gtk::RESPONSE_OK:
2675 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2676 sa.new_name = save_as_dialog->new_name ();
2677 sa.switch_to = save_as_dialog->switch_to();
2678 sa.copy_media = save_as_dialog->copy_media();
2679 sa.copy_external = save_as_dialog->copy_external();
2680 sa.include_media = save_as_dialog->include_media ();
2682 /* Only bother with a progress dialog if we're going to copy
2683 media into the save-as target. Without that choice, this
2684 will be very fast because we're only talking about a few kB's to
2685 perhaps a couple of MB's of data.
2688 ArdourDialog progress_dialog (_("Save As"), true);
2690 if (sa.include_media && sa.copy_media) {
2693 Gtk::ProgressBar progress_bar;
2695 progress_dialog.get_vbox()->pack_start (label);
2696 progress_dialog.get_vbox()->pack_start (progress_bar);
2698 progress_bar.show ();
2700 /* this signal will be emitted from within this, the calling thread,
2701 * after every file is copied. It provides information on percentage
2702 * complete (in terms of total data to copy), the number of files
2703 * copied so far, and the total number to copy.
2708 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2710 progress_dialog.show_all ();
2711 progress_dialog.present ();
2714 if (_session->save_as (sa)) {
2716 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2720 if (!sa.include_media) {
2721 unload_session (false);
2722 load_session (sa.final_session_folder_name, sa.new_name);
2727 ARDOUR_UI::archive_session ()
2735 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2737 SessionArchiveDialog sad;
2738 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2739 int response = sad.run ();
2741 if (response != Gtk::RESPONSE_OK) {
2746 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2747 MessageDialog msg (_("Session Archiving failed."));
2753 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2757 struct tm local_time;
2760 localtime_r (&n, &local_time);
2761 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2763 save_state (timebuf, switch_to_it);
2768 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2772 prompter.get_result (snapname);
2774 bool do_save = (snapname.length() != 0);
2777 char illegal = Session::session_name_is_legal(snapname);
2779 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2780 "snapshot names may not contain a '%1' character"), illegal));
2786 vector<std::string> p;
2787 get_state_files_in_directory (_session->session_directory().root_path(), p);
2788 vector<string> n = get_file_names_no_extension (p);
2790 if (find (n.begin(), n.end(), snapname) != n.end()) {
2792 do_save = overwrite_file_dialog (prompter,
2793 _("Confirm Snapshot Overwrite"),
2794 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2798 save_state (snapname, switch_to_it);
2808 /** Ask the user for the name of a new snapshot and then take it.
2812 ARDOUR_UI::snapshot_session (bool switch_to_it)
2814 ArdourPrompter prompter (true);
2816 prompter.set_name ("Prompter");
2817 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2819 prompter.set_title (_("Snapshot and switch"));
2820 prompter.set_prompt (_("New session name"));
2822 prompter.set_title (_("Take Snapshot"));
2823 prompter.set_prompt (_("Name of new snapshot"));
2827 prompter.set_initial_text (_session->snap_name());
2829 Glib::DateTime tm (g_date_time_new_now_local ());
2830 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2833 bool finished = false;
2835 switch (prompter.run()) {
2836 case RESPONSE_ACCEPT:
2838 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2849 /** Ask the user for a new session name and then rename the session to it.
2853 ARDOUR_UI::rename_session ()
2859 ArdourPrompter prompter (true);
2862 prompter.set_name ("Prompter");
2863 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2864 prompter.set_title (_("Rename Session"));
2865 prompter.set_prompt (_("New session name"));
2868 switch (prompter.run()) {
2869 case RESPONSE_ACCEPT:
2871 prompter.get_result (name);
2873 bool do_rename = (name.length() != 0);
2876 char illegal = Session::session_name_is_legal (name);
2879 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2880 "session names may not contain a '%1' character"), illegal));
2885 switch (_session->rename (name)) {
2887 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2888 msg.set_position (WIN_POS_MOUSE);
2896 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2897 msg.set_position (WIN_POS_MOUSE);
2913 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2915 if (!_session || _session->deletion_in_progress()) {
2919 XMLNode* node = new XMLNode (X_("UI"));
2921 WM::Manager::instance().add_state (*node);
2923 node->add_child_nocopy (gui_object_state->get_state());
2925 _session->add_extra_xml (*node);
2927 if (export_video_dialog) {
2928 _session->add_extra_xml (export_video_dialog->get_state());
2931 save_state_canfail (name, switch_to_it);
2935 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2940 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2945 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2950 ARDOUR_UI::primary_clock_value_changed ()
2953 _session->request_locate (primary_clock->current_time ());
2958 ARDOUR_UI::big_clock_value_changed ()
2961 _session->request_locate (big_clock->current_time ());
2966 ARDOUR_UI::secondary_clock_value_changed ()
2969 _session->request_locate (secondary_clock->current_time ());
2974 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2976 if (_session == 0) {
2980 if (_session->step_editing()) {
2984 Session::RecordState const r = _session->record_status ();
2985 bool const h = _session->have_rec_enabled_track ();
2987 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2989 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2991 rec_button.set_active_state (Gtkmm2ext::Off);
2993 } else if (r == Session::Recording && h) {
2994 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2996 rec_button.unset_active_state ();
3001 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3005 prompter.get_result (name);
3007 if (name.length()) {
3008 int failed = _session->save_template (name);
3010 if (failed == -2) { /* file already exists. */
3011 bool overwrite = overwrite_file_dialog (prompter,
3012 _("Confirm Template Overwrite"),
3013 _("A template already exists with that name. Do you want to overwrite it?"));
3016 _session->save_template (name, true);
3028 ARDOUR_UI::save_template ()
3030 ArdourPrompter prompter (true);
3032 if (!check_audioengine (_main_window)) {
3036 prompter.set_name (X_("Prompter"));
3037 prompter.set_title (_("Save Template"));
3038 prompter.set_prompt (_("Name for template:"));
3039 prompter.set_initial_text(_session->name() + _("-template"));
3040 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3042 bool finished = false;
3044 switch (prompter.run()) {
3045 case RESPONSE_ACCEPT:
3046 finished = process_save_template_prompter (prompter);
3057 ARDOUR_UI::edit_metadata ()
3059 SessionMetadataEditor dialog;
3060 dialog.set_session (_session);
3061 dialog.grab_focus ();
3066 ARDOUR_UI::import_metadata ()
3068 SessionMetadataImporter dialog;
3069 dialog.set_session (_session);
3074 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3076 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3078 MessageDialog msg (str,
3080 Gtk::MESSAGE_WARNING,
3081 Gtk::BUTTONS_YES_NO,
3085 msg.set_name (X_("OpenExistingDialog"));
3086 msg.set_title (_("Open Existing Session"));
3087 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3088 msg.set_position (Gtk::WIN_POS_CENTER);
3089 pop_back_splash (msg);
3091 switch (msg.run()) {
3100 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3102 BusProfile bus_profile;
3106 bus_profile.master_out_channels = 2;
3107 bus_profile.input_ac = AutoConnectPhysical;
3108 bus_profile.output_ac = AutoConnectMaster;
3109 bus_profile.requested_physical_in = 0; // use all available
3110 bus_profile.requested_physical_out = 0; // use all available
3114 /* get settings from advanced section of NSD */
3116 if (sd.create_master_bus()) {
3117 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3119 bus_profile.master_out_channels = 0;
3122 if (sd.connect_inputs()) {
3123 bus_profile.input_ac = AutoConnectPhysical;
3125 bus_profile.input_ac = AutoConnectOption (0);
3128 bus_profile.output_ac = AutoConnectOption (0);
3130 if (sd.connect_outputs ()) {
3131 if (sd.connect_outs_to_master()) {
3132 bus_profile.output_ac = AutoConnectMaster;
3133 } else if (sd.connect_outs_to_physical()) {
3134 bus_profile.output_ac = AutoConnectPhysical;
3138 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3139 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3142 if (build_session (session_path, session_name, bus_profile)) {
3150 ARDOUR_UI::load_from_application_api (const std::string& path)
3152 /* OS X El Capitan (and probably later) now somehow passes the command
3153 line arguments to an app via the openFile delegate protocol. Ardour
3154 already does its own command line processing, and having both
3155 pathways active causes crashes. So, if the command line was already
3156 set, do nothing here.
3159 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3163 ARDOUR_COMMAND_LINE::session_name = path;
3165 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3167 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3169 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3170 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3171 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3172 * -> SessionDialog is not displayed
3175 if (_session_dialog) {
3176 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3177 std::string session_path = path;
3178 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3179 session_path = Glib::path_get_dirname (session_path);
3181 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3182 _session_dialog->set_provided_session (session_name, session_path);
3183 _session_dialog->response (RESPONSE_NONE);
3184 _session_dialog->hide();
3189 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3190 /* /path/to/foo => /path/to/foo, foo */
3191 rv = load_session (path, basename_nosuffix (path));
3193 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3194 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3197 // if load_session fails -> pop up SessionDialog.
3199 ARDOUR_COMMAND_LINE::session_name = "";
3201 if (get_session_parameters (true, false)) {
3207 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3209 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3211 string session_name;
3212 string session_path;
3213 string template_name;
3215 bool likely_new = false;
3216 bool cancel_not_quit;
3218 /* deal with any existing DIRTY session now, rather than later. don't
3219 * treat a non-dirty session this way, so that it stays visible
3220 * as we bring up the new session dialog.
3223 if (_session && ARDOUR_UI::instance()->video_timeline) {
3224 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3227 /* if there is already a session, relabel the button
3228 on the SessionDialog so that we don't Quit directly
3230 cancel_not_quit = (_session != 0);
3232 if (_session && _session->dirty()) {
3233 if (unload_session (false)) {
3234 /* unload cancelled by user */
3237 ARDOUR_COMMAND_LINE::session_name = "";
3240 if (!load_template.empty()) {
3241 should_be_new = true;
3242 template_name = load_template;
3245 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3246 session_path = ARDOUR_COMMAND_LINE::session_name;
3248 if (!session_path.empty()) {
3249 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3250 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3251 /* session/snapshot file, change path to be dir */
3252 session_path = Glib::path_get_dirname (session_path);
3257 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3259 _session_dialog = &session_dialog;
3262 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3264 /* if they named a specific statefile, use it, otherwise they are
3265 just giving a session folder, and we want to use it as is
3266 to find the session.
3269 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3271 if (suffix != string::npos) {
3272 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3273 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3274 session_name = Glib::path_get_basename (session_name);
3276 session_path = ARDOUR_COMMAND_LINE::session_name;
3277 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3282 session_dialog.clear_given ();
3285 if (should_be_new || session_name.empty()) {
3286 /* need the dialog to get info from user */
3288 cerr << "run dialog\n";
3290 switch (session_dialog.run()) {
3291 case RESPONSE_ACCEPT:
3294 /* this is used for async * app->ShouldLoad(). */
3295 continue; // while loop
3298 if (quit_on_cancel) {
3299 // JE - Currently (July 2014) this section can only get reached if the
3300 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3301 // point does NOT indicate an abnormal termination). Therefore, let's
3302 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3304 pthread_cancel_all ();
3312 session_dialog.hide ();
3315 /* if we run the startup dialog again, offer more than just "new session" */
3317 should_be_new = false;
3319 session_name = session_dialog.session_name (likely_new);
3320 session_path = session_dialog.session_folder ();
3327 int rv = ARDOUR::inflate_session (session_name,
3328 Config->get_default_session_parent_dir(), session_path, session_name);
3330 MessageDialog msg (session_dialog,
3331 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3336 session_dialog.set_provided_session (session_name, session_path);
3340 // XXX check archive, inflate
3341 string::size_type suffix = session_name.find (statefile_suffix);
3343 if (suffix != string::npos) {
3344 session_name = session_name.substr (0, suffix);
3347 /* this shouldn't happen, but we catch it just in case it does */
3349 if (session_name.empty()) {
3353 if (session_dialog.use_session_template()) {
3354 template_name = session_dialog.session_template_name();
3355 _session_is_new = true;
3358 if (session_name[0] == G_DIR_SEPARATOR ||
3359 #ifdef PLATFORM_WINDOWS
3360 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3362 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3363 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3368 /* absolute path or cwd-relative path specified for session name: infer session folder
3369 from what was given.
3372 session_path = Glib::path_get_dirname (session_name);
3373 session_name = Glib::path_get_basename (session_name);
3377 session_path = session_dialog.session_folder();
3379 char illegal = Session::session_name_is_legal (session_name);
3382 MessageDialog msg (session_dialog,
3383 string_compose (_("To ensure compatibility with various systems\n"
3384 "session names may not contain a '%1' character"),
3387 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3392 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3395 if (likely_new && !nsm) {
3397 std::string existing = Glib::build_filename (session_path, session_name);
3399 if (!ask_about_loading_existing_session (existing)) {
3400 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3405 _session_is_new = false;
3410 pop_back_splash (session_dialog);
3411 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3413 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3417 char illegal = Session::session_name_is_legal(session_name);
3420 pop_back_splash (session_dialog);
3421 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3422 "session names may not contain a '%1' character"), illegal));
3424 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3428 _session_is_new = true;
3431 if (likely_new && template_name.empty()) {
3433 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3437 ret = load_session (session_path, session_name, template_name);
3440 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3444 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3445 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3449 /* clear this to avoid endless attempts to load the
3453 ARDOUR_COMMAND_LINE::session_name = "";
3457 _session_dialog = NULL;
3463 ARDOUR_UI::close_session()
3465 if (!check_audioengine (_main_window)) {
3469 if (unload_session (true)) {
3473 ARDOUR_COMMAND_LINE::session_name = "";
3475 if (get_session_parameters (true, false)) {
3478 if (splash && splash->is_visible()) {
3479 // in 1 second, hide the splash screen
3480 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3484 /** @param snap_name Snapshot name (without .ardour suffix).
3485 * @return -2 if the load failed because we are not connected to the AudioEngine.
3488 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3490 Session *new_session;
3495 unload_status = unload_session ();
3497 if (unload_status < 0) {
3499 } else if (unload_status > 0) {
3505 session_loaded = false;
3507 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3510 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3513 /* this one is special */
3515 catch (AudioEngine::PortRegistrationFailure& err) {
3517 MessageDialog msg (err.what(),
3520 Gtk::BUTTONS_CLOSE);
3522 msg.set_title (_("Port Registration Error"));
3523 msg.set_secondary_text (_("Click the Close button to try again."));
3524 msg.set_position (Gtk::WIN_POS_CENTER);
3525 pop_back_splash (msg);
3528 int response = msg.run ();
3533 case RESPONSE_CANCEL:
3540 catch (SessionException e) {
3541 MessageDialog msg (string_compose(
3542 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3543 path, snap_name, e.what()),
3548 msg.set_title (_("Loading Error"));
3549 msg.set_position (Gtk::WIN_POS_CENTER);
3550 pop_back_splash (msg);
3562 MessageDialog msg (string_compose(
3563 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3569 msg.set_title (_("Loading Error"));
3570 msg.set_position (Gtk::WIN_POS_CENTER);
3571 pop_back_splash (msg);
3583 list<string> const u = new_session->unknown_processors ();
3585 MissingPluginDialog d (_session, u);
3590 if (!new_session->writable()) {
3591 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3596 msg.set_title (_("Read-only Session"));
3597 msg.set_position (Gtk::WIN_POS_CENTER);
3598 pop_back_splash (msg);
3605 /* Now the session been created, add the transport controls */
3606 new_session->add_controllable(roll_controllable);
3607 new_session->add_controllable(stop_controllable);
3608 new_session->add_controllable(goto_start_controllable);
3609 new_session->add_controllable(goto_end_controllable);
3610 new_session->add_controllable(auto_loop_controllable);
3611 new_session->add_controllable(play_selection_controllable);
3612 new_session->add_controllable(rec_controllable);
3614 set_session (new_session);
3616 session_loaded = true;
3619 _session->set_clean ();
3622 #ifdef WINDOWS_VST_SUPPORT
3623 fst_stop_threading();
3627 Timers::TimerSuspender t;
3631 #ifdef WINDOWS_VST_SUPPORT
3632 fst_start_threading();
3641 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3643 Session *new_session;
3646 session_loaded = false;
3647 x = unload_session ();
3655 _session_is_new = true;
3658 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3661 catch (SessionException e) {
3662 cerr << "Here are the errors associated with this failed session:\n";
3664 cerr << "---------\n";
3665 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3666 msg.set_title (_("Loading Error"));
3667 msg.set_position (Gtk::WIN_POS_CENTER);
3668 pop_back_splash (msg);
3673 cerr << "Here are the errors associated with this failed session:\n";
3675 cerr << "---------\n";
3676 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3677 msg.set_title (_("Loading Error"));
3678 msg.set_position (Gtk::WIN_POS_CENTER);
3679 pop_back_splash (msg);
3684 /* Give the new session the default GUI state, if such things exist */
3687 n = Config->instant_xml (X_("Editor"));
3689 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3690 new_session->add_instant_xml (*n, false);
3692 n = Config->instant_xml (X_("Mixer"));
3694 new_session->add_instant_xml (*n, false);
3697 n = Config->instant_xml (X_("Preferences"));
3699 new_session->add_instant_xml (*n, false);
3702 /* Put the playhead at 0 and scroll fully left */
3703 n = new_session->instant_xml (X_("Editor"));
3705 n->add_property (X_("playhead"), X_("0"));
3706 n->add_property (X_("left-frame"), X_("0"));
3709 set_session (new_session);
3711 session_loaded = true;
3713 new_session->save_state(new_session->name());
3719 ARDOUR_UI::launch_chat ()
3721 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3723 dialog.set_title (_("About the Chat"));
3724 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."));
3726 switch (dialog.run()) {
3729 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3730 #elif defined PLATFORM_WINDOWS
3731 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3733 open_uri("http://webchat.freenode.net/?channels=ardour");
3742 ARDOUR_UI::launch_manual ()
3744 PBD::open_uri (Config->get_tutorial_manual_url());
3748 ARDOUR_UI::launch_reference ()
3750 PBD::open_uri (Config->get_reference_manual_url());
3754 ARDOUR_UI::launch_tracker ()
3756 PBD::open_uri ("http://tracker.ardour.org");
3760 ARDOUR_UI::launch_subscribe ()
3762 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3766 ARDOUR_UI::launch_cheat_sheet ()
3769 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3771 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3776 ARDOUR_UI::launch_website ()
3778 PBD::open_uri ("http://ardour.org");
3782 ARDOUR_UI::launch_website_dev ()
3784 PBD::open_uri ("http://ardour.org/development.html");
3788 ARDOUR_UI::launch_forums ()
3790 PBD::open_uri ("https://community.ardour.org/forums");
3794 ARDOUR_UI::launch_howto_report ()
3796 PBD::open_uri ("http://ardour.org/reporting_bugs");
3800 ARDOUR_UI::loading_message (const std::string& msg)
3802 if (ARDOUR_COMMAND_LINE::no_splash) {
3810 splash->message (msg);
3814 ARDOUR_UI::show_splash ()
3818 splash = new Splash;
3828 ARDOUR_UI::hide_splash ()
3835 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3839 removed = rep.paths.size();
3842 MessageDialog msgd (_main_window,
3843 _("No files were ready for clean-up"),
3847 msgd.set_title (_("Clean-up"));
3848 msgd.set_secondary_text (_("If this seems suprising, \n\
3849 check for any existing snapshots.\n\
3850 These may still include regions that\n\
3851 require some unused files to continue to exist."));
3857 ArdourDialog results (_("Clean-up"), true, false);
3859 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3860 CleanupResultsModelColumns() {
3864 Gtk::TreeModelColumn<std::string> visible_name;
3865 Gtk::TreeModelColumn<std::string> fullpath;
3869 CleanupResultsModelColumns results_columns;
3870 Glib::RefPtr<Gtk::ListStore> results_model;
3871 Gtk::TreeView results_display;
3873 results_model = ListStore::create (results_columns);
3874 results_display.set_model (results_model);
3875 results_display.append_column (list_title, results_columns.visible_name);
3877 results_display.set_name ("CleanupResultsList");
3878 results_display.set_headers_visible (true);
3879 results_display.set_headers_clickable (false);
3880 results_display.set_reorderable (false);
3882 Gtk::ScrolledWindow list_scroller;
3885 Gtk::HBox dhbox; // the hbox for the image and text
3886 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3887 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3889 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3891 const string dead_directory = _session->session_directory().dead_path();
3894 %1 - number of files removed
3895 %2 - location of "dead"
3896 %3 - size of files affected
3897 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3900 const char* bprefix;
3901 double space_adjusted = 0;
3903 if (rep.space < 1000) {
3905 space_adjusted = rep.space;
3906 } else if (rep.space < 1000000) {
3907 bprefix = _("kilo");
3908 space_adjusted = floorf((float)rep.space / 1000.0);
3909 } else if (rep.space < 1000000 * 1000) {
3910 bprefix = _("mega");
3911 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3913 bprefix = _("giga");
3914 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3918 txt.set_markup (string_compose (P_("\
3919 The following file was deleted from %2,\n\
3920 releasing %3 %4bytes of disk space", "\
3921 The following %1 files were deleted from %2,\n\
3922 releasing %3 %4bytes of disk space", removed),
3923 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3925 txt.set_markup (string_compose (P_("\
3926 The following file was not in use and \n\
3927 has been moved to: %2\n\n\
3928 After a restart of %5\n\n\
3929 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3930 will release an additional %3 %4bytes of disk space.\n", "\
3931 The following %1 files were not in use and \n\
3932 have been moved to: %2\n\n\
3933 After a restart of %5\n\n\
3934 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3935 will release an additional %3 %4bytes of disk space.\n", removed),
3936 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3939 dhbox.pack_start (*dimage, true, false, 5);
3940 dhbox.pack_start (txt, true, false, 5);
3942 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3943 TreeModel::Row row = *(results_model->append());
3944 row[results_columns.visible_name] = *i;
3945 row[results_columns.fullpath] = *i;
3948 list_scroller.add (results_display);
3949 list_scroller.set_size_request (-1, 150);
3950 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3952 dvbox.pack_start (dhbox, true, false, 5);
3953 dvbox.pack_start (list_scroller, true, false, 5);
3954 ddhbox.pack_start (dvbox, true, false, 5);
3956 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3957 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3958 results.set_default_response (RESPONSE_CLOSE);
3959 results.set_position (Gtk::WIN_POS_MOUSE);
3961 results_display.show();
3962 list_scroller.show();
3969 //results.get_vbox()->show();
3970 results.set_resizable (false);
3977 ARDOUR_UI::cleanup ()
3979 if (_session == 0) {
3980 /* shouldn't happen: menu item is insensitive */
3985 MessageDialog checker (_("Are you sure you want to clean-up?"),
3987 Gtk::MESSAGE_QUESTION,
3990 checker.set_title (_("Clean-up"));
3992 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3993 ALL undo/redo information will be lost if you clean-up.\n\
3994 Clean-up will move all unused files to a \"dead\" location."));
3996 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3997 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3998 checker.set_default_response (RESPONSE_CANCEL);
4000 checker.set_name (_("CleanupDialog"));
4001 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4002 checker.set_position (Gtk::WIN_POS_MOUSE);
4004 switch (checker.run()) {
4005 case RESPONSE_ACCEPT:
4011 ARDOUR::CleanupReport rep;
4013 editor->prepare_for_cleanup ();
4015 /* do not allow flush until a session is reloaded */
4017 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4019 act->set_sensitive (false);
4022 if (_session->cleanup_sources (rep)) {
4023 editor->finish_cleanup ();
4027 editor->finish_cleanup ();
4030 display_cleanup_results (rep, _("Cleaned Files"), false);
4034 ARDOUR_UI::flush_trash ()
4036 if (_session == 0) {
4037 /* shouldn't happen: menu item is insensitive */
4041 ARDOUR::CleanupReport rep;
4043 if (_session->cleanup_trash_sources (rep)) {
4047 display_cleanup_results (rep, _("deleted file"), true);
4051 ARDOUR_UI::cleanup_peakfiles ()
4053 if (_session == 0) {
4054 /* shouldn't happen: menu item is insensitive */
4058 if (! _session->can_cleanup_peakfiles ()) {
4062 // get all region-views in this session
4064 TrackViewList empty;
4066 editor->get_regions_after(rs, (framepos_t) 0, empty);
4067 std::list<RegionView*> views = rs.by_layer();
4069 // remove displayed audio-region-views waveforms
4070 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4071 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4072 if (!arv) { continue ; }
4073 arv->delete_waves();
4076 // cleanup peak files:
4077 // - stop pending peakfile threads
4078 // - close peakfiles if any
4079 // - remove peak dir in session
4080 // - setup peakfiles (background thread)
4081 _session->cleanup_peakfiles ();
4083 // re-add waves to ARV
4084 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4085 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4086 if (!arv) { continue ; }
4087 arv->create_waves();
4091 PresentationInfo::order_t
4092 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4094 if (editor->get_selection().tracks.empty()) {
4095 return PresentationInfo::max_order;
4098 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4101 we want the new routes to have their order keys set starting from
4102 the highest order key in the selection + 1 (if available).
4105 if (place == RouteDialogs::AfterSelection) {
4106 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4108 order_hint = rtav->route()->presentation_info().order();
4111 } else if (place == RouteDialogs::BeforeSelection) {
4112 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4114 order_hint = rtav->route()->presentation_info().order();
4116 } else if (place == RouteDialogs::First) {
4119 /* leave order_hint at max_order */
4126 ARDOUR_UI::start_duplicate_routes ()
4128 if (!duplicate_routes_dialog) {
4129 duplicate_routes_dialog = new DuplicateRouteDialog;
4132 if (duplicate_routes_dialog->restart (_session)) {
4136 duplicate_routes_dialog->present ();
4140 ARDOUR_UI::add_route ()
4142 if (!add_route_dialog.get (false)) {
4143 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4150 if (add_route_dialog->is_visible()) {
4151 /* we're already doing this */
4155 add_route_dialog->set_position (WIN_POS_MOUSE);
4156 add_route_dialog->present();
4160 ARDOUR_UI::add_route_dialog_finished (int r)
4164 add_route_dialog->hide();
4167 case RESPONSE_ACCEPT:
4174 if ((count = add_route_dialog->count()) <= 0) {
4178 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4179 string template_path = add_route_dialog->track_template();
4180 DisplaySuspender ds;
4182 if (!template_path.empty()) {
4183 if (add_route_dialog->name_template_is_default()) {
4184 _session->new_route_from_template (count, order, template_path, string());
4186 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4191 ChanCount input_chan= add_route_dialog->channels ();
4192 ChanCount output_chan;
4193 string name_template = add_route_dialog->name_template ();
4194 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4195 RouteGroup* route_group = add_route_dialog->route_group ();
4196 AutoConnectOption oac = Config->get_output_auto_connect();
4197 bool strict_io = add_route_dialog->use_strict_io ();
4199 if (oac & AutoConnectMaster) {
4200 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4201 output_chan.set (DataType::MIDI, 0);
4203 output_chan = input_chan;
4206 /* XXX do something with name template */
4208 Session::ProcessorChangeBlocker pcb (_session);
4210 switch (add_route_dialog->type_wanted()) {
4211 case AddRouteDialog::AudioTrack:
4212 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4214 case AddRouteDialog::MidiTrack:
4215 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4217 case AddRouteDialog::MixedTrack:
4218 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4220 case AddRouteDialog::AudioBus:
4221 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4223 case AddRouteDialog::MidiBus:
4224 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4226 case AddRouteDialog::VCAMaster:
4227 session_add_vca (name_template, count);
4233 ARDOUR_UI::add_lua_script ()
4239 LuaScriptInfoPtr spi;
4240 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4241 switch (ss.run ()) {
4242 case Gtk::RESPONSE_ACCEPT:
4250 std::string script = "";
4253 script = Glib::file_get_contents (spi->path);
4254 } catch (Glib::FileError e) {
4255 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4256 MessageDialog am (msg);
4261 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4262 std::vector<std::string> reg = _session->registered_lua_functions ();
4264 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4265 switch (spd.run ()) {
4266 case Gtk::RESPONSE_ACCEPT:
4273 _session->register_lua_function (spd.name(), script, lsp);
4274 } catch (luabridge::LuaException const& e) {
4275 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4276 MessageDialog am (msg);
4278 } catch (SessionException e) {
4279 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4280 MessageDialog am (msg);
4286 ARDOUR_UI::remove_lua_script ()
4291 if (_session->registered_lua_function_count () == 0) {
4292 string msg = _("There are no active Lua session scripts present in this session.");
4293 MessageDialog am (msg);
4298 std::vector<std::string> reg = _session->registered_lua_functions ();
4299 SessionScriptManager sm ("Remove Lua Session Script", reg);
4300 switch (sm.run ()) {
4301 case Gtk::RESPONSE_ACCEPT:
4307 _session->unregister_lua_function (sm.name());
4308 } catch (luabridge::LuaException const& e) {
4309 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4310 MessageDialog am (msg);
4316 ARDOUR_UI::stop_video_server (bool ask_confirm)
4318 if (!video_server_process && ask_confirm) {
4319 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4321 if (video_server_process) {
4323 ArdourDialog confirm (_("Stop Video-Server"), true);
4324 Label m (_("Do you really want to stop the Video Server?"));
4325 confirm.get_vbox()->pack_start (m, true, true);
4326 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4327 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4328 confirm.show_all ();
4329 if (confirm.run() == RESPONSE_CANCEL) {
4333 delete video_server_process;
4334 video_server_process =0;
4339 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4341 ARDOUR_UI::start_video_server( float_window, true);
4345 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4351 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4352 if (video_server_process) {
4353 popup_error(_("The Video Server is already started."));
4355 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4361 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4363 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4365 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4367 video_server_dialog->set_transient_for (*float_window);
4370 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4371 video_server_dialog->hide();
4373 ResponseType r = (ResponseType) video_server_dialog->run ();
4374 video_server_dialog->hide();
4375 if (r != RESPONSE_ACCEPT) { return false; }
4376 if (video_server_dialog->show_again()) {
4377 Config->set_show_video_server_dialog(false);
4381 std::string icsd_exec = video_server_dialog->get_exec_path();
4382 std::string icsd_docroot = video_server_dialog->get_docroot();
4383 if (icsd_docroot.empty()) {
4384 #ifndef PLATFORM_WINDOWS
4385 icsd_docroot = X_("/");
4387 icsd_docroot = X_("C:\\");
4392 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4393 warning << _("Specified docroot is not an existing directory.") << endmsg;
4396 #ifndef PLATFORM_WINDOWS
4397 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4398 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4399 warning << _("Given Video Server is not an executable file.") << endmsg;
4403 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4404 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4405 warning << _("Given Video Server is not an executable file.") << endmsg;
4411 argp=(char**) calloc(9,sizeof(char*));
4412 argp[0] = strdup(icsd_exec.c_str());
4413 argp[1] = strdup("-P");
4414 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4415 argp[3] = strdup("-p");
4416 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4417 argp[5] = strdup("-C");
4418 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4419 argp[7] = strdup(icsd_docroot.c_str());
4421 stop_video_server();
4423 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4424 Config->set_video_advanced_setup(false);
4426 std::ostringstream osstream;
4427 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4428 Config->set_video_server_url(osstream.str());
4429 Config->set_video_server_docroot(icsd_docroot);
4430 Config->set_video_advanced_setup(true);
4433 if (video_server_process) {
4434 delete video_server_process;
4437 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4438 if (video_server_process->start()) {
4439 warning << _("Cannot launch the video-server") << endmsg;
4442 int timeout = 120; // 6 sec
4443 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4444 Glib::usleep (50000);
4446 if (--timeout <= 0 || !video_server_process->is_running()) break;
4449 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4451 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4452 delete video_server_process;
4453 video_server_process = 0;
4461 ARDOUR_UI::add_video (Gtk::Window* float_window)
4467 if (!start_video_server(float_window, false)) {
4468 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4473 add_video_dialog->set_transient_for (*float_window);
4476 if (add_video_dialog->is_visible()) {
4477 /* we're already doing this */
4481 ResponseType r = (ResponseType) add_video_dialog->run ();
4482 add_video_dialog->hide();
4483 if (r != RESPONSE_ACCEPT) { return; }
4485 bool local_file, orig_local_file;
4486 std::string path = add_video_dialog->file_name(local_file);
4488 std::string orig_path = path;
4489 orig_local_file = local_file;
4491 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4493 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4494 warning << string_compose(_("could not open %1"), path) << endmsg;
4497 if (!local_file && path.length() == 0) {
4498 warning << _("no video-file selected") << endmsg;
4502 std::string audio_from_video;
4503 bool detect_ltc = false;
4505 switch (add_video_dialog->import_option()) {
4506 case VTL_IMPORT_TRANSCODE:
4508 TranscodeVideoDialog *transcode_video_dialog;
4509 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4510 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4511 transcode_video_dialog->hide();
4512 if (r != RESPONSE_ACCEPT) {
4513 delete transcode_video_dialog;
4517 audio_from_video = transcode_video_dialog->get_audiofile();
4519 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4522 else if (!audio_from_video.empty()) {
4523 editor->embed_audio_from_video(
4525 video_timeline->get_offset(),
4526 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4529 switch (transcode_video_dialog->import_option()) {
4530 case VTL_IMPORT_TRANSCODED:
4531 path = transcode_video_dialog->get_filename();
4534 case VTL_IMPORT_REFERENCE:
4537 delete transcode_video_dialog;
4540 delete transcode_video_dialog;
4544 case VTL_IMPORT_NONE:
4548 /* strip _session->session_directory().video_path() from video file if possible */
4549 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4550 path=path.substr(_session->session_directory().video_path().size());
4551 if (path.at(0) == G_DIR_SEPARATOR) {
4552 path=path.substr(1);
4556 video_timeline->set_update_session_fps(auto_set_session_fps);
4558 if (video_timeline->video_file_info(path, local_file)) {
4559 XMLNode* node = new XMLNode(X_("Videotimeline"));
4560 node->add_property (X_("Filename"), path);
4561 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4562 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4563 if (orig_local_file) {
4564 node->add_property (X_("OriginalVideoFile"), orig_path);
4566 node->remove_property (X_("OriginalVideoFile"));
4568 _session->add_extra_xml (*node);
4569 _session->set_dirty ();
4571 if (!audio_from_video.empty() && detect_ltc) {
4572 std::vector<LTCFileReader::LTCMap> ltc_seq;
4575 /* TODO ask user about TV standard (LTC alignment if any) */
4576 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4577 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4579 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4581 /* TODO seek near end of file, and read LTC until end.
4582 * if it fails to find any LTC frames, scan complete file
4584 * calculate drift of LTC compared to video-duration,
4585 * ask user for reference (timecode from start/mid/end)
4588 // LTCFileReader will have written error messages
4591 ::g_unlink(audio_from_video.c_str());
4593 if (ltc_seq.size() == 0) {
4594 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4596 /* the very first TC in the file is somteimes not aligned properly */
4597 int i = ltc_seq.size() -1;
4598 ARDOUR::frameoffset_t video_start_offset =
4599 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4600 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4601 video_timeline->set_offset(video_start_offset);
4605 _session->maybe_update_session_range(
4606 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4607 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4610 if (add_video_dialog->launch_xjadeo() && local_file) {
4611 editor->set_xjadeo_sensitive(true);
4612 editor->toggle_xjadeo_proc(1);
4614 editor->toggle_xjadeo_proc(0);
4616 editor->toggle_ruler_video(true);
4621 ARDOUR_UI::remove_video ()
4623 video_timeline->close_session();
4624 editor->toggle_ruler_video(false);
4627 video_timeline->set_offset_locked(false);
4628 video_timeline->set_offset(0);
4630 /* delete session state */
4631 XMLNode* node = new XMLNode(X_("Videotimeline"));
4632 _session->add_extra_xml(*node);
4633 node = new XMLNode(X_("Videomonitor"));
4634 _session->add_extra_xml(*node);
4635 node = new XMLNode(X_("Videoexport"));
4636 _session->add_extra_xml(*node);
4637 stop_video_server();
4641 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4643 if (localcacheonly) {
4644 video_timeline->vmon_update();
4646 video_timeline->flush_cache();
4648 editor->queue_visual_videotimeline_update();
4652 ARDOUR_UI::export_video (bool range)
4654 if (ARDOUR::Config->get_show_video_export_info()) {
4655 ExportVideoInfobox infobox (_session);
4656 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4657 if (infobox.show_again()) {
4658 ARDOUR::Config->set_show_video_export_info(false);
4661 case GTK_RESPONSE_YES:
4662 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4668 export_video_dialog->set_session (_session);
4669 export_video_dialog->apply_state(editor->get_selection().time, range);
4670 export_video_dialog->run ();
4671 export_video_dialog->hide ();
4675 ARDOUR_UI::preferences_settings () const
4680 node = _session->instant_xml(X_("Preferences"));
4682 node = Config->instant_xml(X_("Preferences"));
4686 node = new XMLNode (X_("Preferences"));
4693 ARDOUR_UI::mixer_settings () const
4698 node = _session->instant_xml(X_("Mixer"));
4700 node = Config->instant_xml(X_("Mixer"));
4704 node = new XMLNode (X_("Mixer"));
4711 ARDOUR_UI::main_window_settings () const
4716 node = _session->instant_xml(X_("Main"));
4718 node = Config->instant_xml(X_("Main"));
4722 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4723 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4728 node = new XMLNode (X_("Main"));
4735 ARDOUR_UI::editor_settings () const
4740 node = _session->instant_xml(X_("Editor"));
4742 node = Config->instant_xml(X_("Editor"));
4746 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4747 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4752 node = new XMLNode (X_("Editor"));
4759 ARDOUR_UI::keyboard_settings () const
4763 node = Config->extra_xml(X_("Keyboard"));
4766 node = new XMLNode (X_("Keyboard"));
4773 ARDOUR_UI::create_xrun_marker (framepos_t where)
4776 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4777 _session->locations()->add (location);
4782 ARDOUR_UI::halt_on_xrun_message ()
4784 cerr << "HALT on xrun\n";
4785 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4790 ARDOUR_UI::xrun_handler (framepos_t where)
4796 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4798 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4799 create_xrun_marker(where);
4802 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4803 halt_on_xrun_message ();
4808 ARDOUR_UI::disk_overrun_handler ()
4810 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4812 if (!have_disk_speed_dialog_displayed) {
4813 have_disk_speed_dialog_displayed = true;
4814 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4815 The disk system on your computer\n\
4816 was not able to keep up with %1.\n\
4818 Specifically, it failed to write data to disk\n\
4819 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4820 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4826 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4827 static MessageDialog *scan_dlg = NULL;
4828 static ProgressBar *scan_pbar = NULL;
4829 static HBox *scan_tbox = NULL;
4830 static Gtk::Button *scan_timeout_button;
4833 ARDOUR_UI::cancel_plugin_scan ()
4835 PluginManager::instance().cancel_plugin_scan();
4839 ARDOUR_UI::cancel_plugin_timeout ()
4841 PluginManager::instance().cancel_plugin_timeout();
4842 scan_timeout_button->set_sensitive (false);
4846 ARDOUR_UI::plugin_scan_timeout (int timeout)
4848 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4852 scan_pbar->set_sensitive (false);
4853 scan_timeout_button->set_sensitive (true);
4854 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4857 scan_pbar->set_sensitive (false);
4858 scan_timeout_button->set_sensitive (false);
4864 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4866 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4870 const bool cancelled = PluginManager::instance().cancelled();
4871 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4872 if (cancelled && scan_dlg->is_mapped()) {
4877 if (cancelled || !can_cancel) {
4882 static Gtk::Button *cancel_button;
4884 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4885 VBox* vbox = scan_dlg->get_vbox();
4886 vbox->set_size_request(400,-1);
4887 scan_dlg->set_title (_("Scanning for plugins"));
4889 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4890 cancel_button->set_name ("EditorGTKButton");
4891 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4892 cancel_button->show();
4894 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4896 scan_tbox = manage( new HBox() );
4898 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4899 scan_timeout_button->set_name ("EditorGTKButton");
4900 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4901 scan_timeout_button->show();
4903 scan_pbar = manage(new ProgressBar());
4904 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4905 scan_pbar->set_text(_("Scan Timeout"));
4908 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4909 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4911 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4914 assert(scan_dlg && scan_tbox && cancel_button);
4916 if (type == X_("closeme")) {
4920 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4923 if (!can_cancel || !cancelled) {
4924 scan_timeout_button->set_sensitive(false);
4926 cancel_button->set_sensitive(can_cancel && !cancelled);
4932 ARDOUR_UI::gui_idle_handler ()
4935 /* due to idle calls, gtk_events_pending() may always return true */
4936 while (gtk_events_pending() && --timeout) {
4937 gtk_main_iteration ();
4942 ARDOUR_UI::disk_underrun_handler ()
4944 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4946 if (!have_disk_speed_dialog_displayed) {
4947 have_disk_speed_dialog_displayed = true;
4948 MessageDialog* msg = new MessageDialog (
4949 _main_window, string_compose (_("The disk system on your computer\n\
4950 was not able to keep up with %1.\n\
4952 Specifically, it failed to read data from disk\n\
4953 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4954 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4960 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4962 have_disk_speed_dialog_displayed = false;
4967 ARDOUR_UI::session_dialog (std::string msg)
4969 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4973 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4980 ARDOUR_UI::pending_state_dialog ()
4982 HBox* hbox = manage (new HBox());
4983 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4984 ArdourDialog dialog (_("Crash Recovery"), true);
4985 Label message (string_compose (_("\
4986 This session appears to have been in the\n\
4987 middle of recording when %1 or\n\
4988 the computer was shutdown.\n\
4990 %1 can recover any captured audio for\n\
4991 you, or it can ignore it. Please decide\n\
4992 what you would like to do.\n"), PROGRAM_NAME));
4993 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4994 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4995 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4996 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4997 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4998 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4999 dialog.set_default_response (RESPONSE_ACCEPT);
5000 dialog.set_position (WIN_POS_CENTER);
5005 switch (dialog.run ()) {
5006 case RESPONSE_ACCEPT:
5014 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5016 HBox* hbox = new HBox();
5017 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5018 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5019 Label message (string_compose (_("\
5020 This session was created with a sample rate of %1 Hz, but\n\
5021 %2 is currently running at %3 Hz. If you load this session,\n\
5022 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5024 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5025 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5026 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5027 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5028 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5029 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5030 dialog.set_default_response (RESPONSE_ACCEPT);
5031 dialog.set_position (WIN_POS_CENTER);
5036 switch (dialog.run()) {
5037 case RESPONSE_ACCEPT:
5047 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5049 MessageDialog msg (string_compose (_("\
5050 This session was created with a sample rate of %1 Hz, but\n\
5051 %2 is currently running at %3 Hz.\n\
5052 Audio will be recorded and played at the wrong sample rate.\n\
5053 Re-Configure the Audio Engine in\n\
5054 Menu > Window > Audio/Midi Setup"),
5055 desired, PROGRAM_NAME, actual),
5057 Gtk::MESSAGE_WARNING);
5062 ARDOUR_UI::use_config ()
5064 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5066 set_transport_controllable_state (*node);
5071 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5073 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5074 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5076 primary_clock->set (pos);
5079 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5080 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5082 secondary_clock->set (pos);
5085 if (big_clock_window) {
5086 big_clock->set (pos);
5088 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5092 ARDOUR_UI::step_edit_status_change (bool yn)
5094 // XXX should really store pre-step edit status of things
5095 // we make insensitive
5098 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5099 rec_button.set_sensitive (false);
5101 rec_button.unset_active_state ();;
5102 rec_button.set_sensitive (true);
5107 ARDOUR_UI::record_state_changed ()
5109 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5112 /* why bother - the clock isn't visible */
5116 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5118 if (big_clock_window) {
5119 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5120 big_clock->set_active (true);
5122 big_clock->set_active (false);
5129 ARDOUR_UI::first_idle ()
5132 _session->allow_auto_play (true);
5136 editor->first_idle();
5139 Keyboard::set_can_save_keybindings (true);
5144 ARDOUR_UI::store_clock_modes ()
5146 XMLNode* node = new XMLNode(X_("ClockModes"));
5148 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5149 XMLNode* child = new XMLNode (X_("Clock"));
5151 child->add_property (X_("name"), (*x)->name());
5152 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5153 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5155 node->add_child_nocopy (*child);
5158 _session->add_extra_xml (*node);
5159 _session->set_dirty ();
5162 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5163 : Controllable (name), ui (u), type(tp)
5169 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5172 /* do nothing: these are radio-style actions */
5176 const char *action = 0;
5180 action = X_("Roll");
5183 action = X_("Stop");
5186 action = X_("GotoStart");
5189 action = X_("GotoEnd");
5192 action = X_("Loop");
5195 action = X_("PlaySelection");
5198 action = X_("Record");
5208 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5216 ARDOUR_UI::TransportControllable::get_value (void) const
5243 ARDOUR_UI::setup_profile ()
5245 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5246 Profile->set_small_screen ();
5249 if (g_getenv ("TRX")) {
5250 Profile->set_trx ();
5253 if (g_getenv ("MIXBUS")) {
5254 Profile->set_mixbus ();
5259 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5261 MissingFileDialog dialog (s, str, type);
5266 int result = dialog.run ();
5273 return 1; // quit entire session load
5276 result = dialog.get_action ();
5282 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5284 AmbiguousFileDialog dialog (file, hits);
5291 return dialog.get_which ();
5294 /** Allocate our thread-local buffers */
5296 ARDOUR_UI::get_process_buffers ()
5298 _process_thread->get_buffers ();
5301 /** Drop our thread-local buffers */
5303 ARDOUR_UI::drop_process_buffers ()
5305 _process_thread->drop_buffers ();
5309 ARDOUR_UI::feedback_detected ()
5311 _feedback_exists = true;
5315 ARDOUR_UI::successful_graph_sort ()
5317 _feedback_exists = false;
5321 ARDOUR_UI::midi_panic ()
5324 _session->midi_panic();
5329 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5331 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5332 const char* end_big = "</span>";
5333 const char* start_mono = "<tt>";
5334 const char* end_mono = "</tt>";
5336 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5337 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5338 "From now on, use the backup copy with older versions of %3"),
5339 xml_path, backup_path, PROGRAM_NAME,
5341 start_mono, end_mono), true);
5348 ARDOUR_UI::reset_peak_display ()
5350 if (!_session || !_session->master_out() || !editor_meter) return;
5351 editor_meter->clear_meters();
5352 editor_meter_max_peak = -INFINITY;
5353 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5357 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5359 if (!_session || !_session->master_out()) return;
5360 if (group == _session->master_out()->route_group()) {
5361 reset_peak_display ();
5366 ARDOUR_UI::reset_route_peak_display (Route* route)
5368 if (!_session || !_session->master_out()) return;
5369 if (_session->master_out().get() == route) {
5370 reset_peak_display ();
5375 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5377 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5378 audio_midi_setup->set_position (WIN_POS_CENTER);
5380 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5381 audio_midi_setup->try_autostart ();
5382 if (ARDOUR::AudioEngine::instance()->running()) {
5388 int response = audio_midi_setup->run();
5389 printf("RESPONSE %d\n", response);
5391 case Gtk::RESPONSE_DELETE_EVENT:
5394 if (!AudioEngine::instance()->running()) {
5397 audio_midi_setup->hide ();
5405 ARDOUR_UI::transport_numpad_timeout ()
5407 _numpad_locate_happening = false;
5408 if (_numpad_timeout_connection.connected() )
5409 _numpad_timeout_connection.disconnect();
5414 ARDOUR_UI::transport_numpad_decimal ()
5416 _numpad_timeout_connection.disconnect();
5418 if (_numpad_locate_happening) {
5419 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5420 _numpad_locate_happening = false;
5422 _pending_locate_num = 0;
5423 _numpad_locate_happening = true;
5424 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5429 ARDOUR_UI::transport_numpad_event (int num)
5431 if ( _numpad_locate_happening ) {
5432 _pending_locate_num = _pending_locate_num*10 + num;
5435 case 0: toggle_roll(false, false); break;
5436 case 1: transport_rewind(1); break;
5437 case 2: transport_forward(1); break;
5438 case 3: transport_record(true); break;
5439 case 4: toggle_session_auto_loop(); break;
5440 case 5: transport_record(false); toggle_session_auto_loop(); break;
5441 case 6: toggle_punch(); break;
5442 case 7: toggle_click(); break;
5443 case 8: toggle_auto_return(); break;
5444 case 9: toggle_follow_edits(); break;
5450 ARDOUR_UI::set_flat_buttons ()
5452 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5456 ARDOUR_UI::audioengine_became_silent ()
5458 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5460 Gtk::MESSAGE_WARNING,
5464 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5466 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5467 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5468 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5469 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5470 Gtk::HBox pay_button_box;
5471 Gtk::HBox subscribe_button_box;
5473 pay_button_box.pack_start (pay_button, true, false);
5474 subscribe_button_box.pack_start (subscribe_button, true, false);
5476 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 */
5478 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5479 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5481 msg.get_vbox()->pack_start (pay_label);
5482 msg.get_vbox()->pack_start (pay_button_box);
5483 msg.get_vbox()->pack_start (subscribe_label);
5484 msg.get_vbox()->pack_start (subscribe_button_box);
5486 msg.get_vbox()->show_all ();
5488 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5489 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5490 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5495 case Gtk::RESPONSE_YES:
5496 AudioEngine::instance()->reset_silence_countdown ();
5499 case Gtk::RESPONSE_NO:
5501 save_state_canfail ("");
5505 case Gtk::RESPONSE_CANCEL:
5507 /* don't reset, save session and exit */
5513 ARDOUR_UI::hide_application ()
5515 Application::instance ()-> hide ();
5519 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5521 /* icons, titles, WM stuff */
5523 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5525 if (window_icons.empty()) {
5526 Glib::RefPtr<Gdk::Pixbuf> icon;
5527 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5528 window_icons.push_back (icon);
5530 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5531 window_icons.push_back (icon);
5533 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5534 window_icons.push_back (icon);
5536 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5537 window_icons.push_back (icon);
5541 if (!window_icons.empty()) {
5542 window.set_default_icon_list (window_icons);
5545 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5547 if (!name.empty()) {
5551 window.set_title (title.get_string());
5552 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5554 window.set_flags (CAN_FOCUS);
5555 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5557 /* This is a hack to ensure that GTK-accelerators continue to
5558 * work. Once we switch over to entirely native bindings, this will be
5559 * unnecessary and should be removed
5561 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5563 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5564 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5565 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5566 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5570 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5572 Gtkmm2ext::Bindings* bindings = 0;
5573 Gtk::Window* window = 0;
5575 /* until we get ardour bindings working, we are not handling key
5579 if (ev->type != GDK_KEY_PRESS) {
5583 if (event_window == &_main_window) {
5585 window = event_window;
5587 /* find current tab contents */
5589 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5591 /* see if it uses the ardour binding system */
5594 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5597 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5601 window = event_window;
5603 /* see if window uses ardour binding system */
5605 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5608 /* An empty binding set is treated as if it doesn't exist */
5610 if (bindings && bindings->empty()) {
5614 return key_press_focus_accelerator_handler (*window, ev, bindings);
5617 static Gtkmm2ext::Bindings*
5618 get_bindings_from_widget_heirarchy (GtkWidget** w)
5623 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5626 *w = gtk_widget_get_parent (*w);
5629 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5633 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5635 GtkWindow* win = window.gobj();
5636 GtkWidget* focus = gtk_window_get_focus (win);
5637 GtkWidget* binding_widget = focus;
5638 bool special_handling_of_unmodified_accelerators = false;
5639 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5643 /* some widget has keyboard focus */
5645 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5647 /* A particular kind of focusable widget currently has keyboard
5648 * focus. All unmodified key events should go to that widget
5649 * first and not be used as an accelerator by default
5652 special_handling_of_unmodified_accelerators = true;
5656 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5657 if (focus_bindings) {
5658 bindings = focus_bindings;
5659 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5664 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",
5667 Gtkmm2ext::show_gdk_event_state (ev->state),
5668 special_handling_of_unmodified_accelerators,
5669 Keyboard::some_magic_widget_has_focus(),
5671 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5672 ((ev->state & mask) ? "yes" : "no"),
5673 window.get_title()));
5675 /* This exists to allow us to override the way GTK handles
5676 key events. The normal sequence is:
5678 a) event is delivered to a GtkWindow
5679 b) accelerators/mnemonics are activated
5680 c) if (b) didn't handle the event, propagate to
5681 the focus widget and/or focus chain
5683 The problem with this is that if the accelerators include
5684 keys without modifiers, such as the space bar or the
5685 letter "e", then pressing the key while typing into
5686 a text entry widget results in the accelerator being
5687 activated, instead of the desired letter appearing
5690 There is no good way of fixing this, but this
5691 represents a compromise. The idea is that
5692 key events involving modifiers (not Shift)
5693 get routed into the activation pathway first, then
5694 get propagated to the focus widget if necessary.
5696 If the key event doesn't involve modifiers,
5697 we deliver to the focus widget first, thus allowing
5698 it to get "normal text" without interference
5701 Of course, this can also be problematic: if there
5702 is a widget with focus, then it will swallow
5703 all "normal text" accelerators.
5707 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5709 /* no special handling or there are modifiers in effect: accelerate first */
5711 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5712 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5713 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5715 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5716 KeyboardKey k (ev->state, ev->keyval);
5720 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5722 if (bindings->activate (k, Bindings::Press)) {
5723 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5727 if (binding_widget) {
5728 binding_widget = gtk_widget_get_parent (binding_widget);
5729 if (binding_widget) {
5730 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5739 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5741 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5742 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5746 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5748 if (gtk_window_propagate_key_event (win, ev)) {
5749 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5755 /* no modifiers, propagate first */
5757 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5759 if (gtk_window_propagate_key_event (win, ev)) {
5760 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5764 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5765 KeyboardKey k (ev->state, ev->keyval);
5769 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5772 if (bindings->activate (k, Bindings::Press)) {
5773 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5777 if (binding_widget) {
5778 binding_widget = gtk_widget_get_parent (binding_widget);
5779 if (binding_widget) {
5780 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5789 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5791 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5792 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5797 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5802 ARDOUR_UI::load_bindings ()
5804 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5805 error << _("Global keybindings are missing") << endmsg;
5810 ARDOUR_UI::cancel_solo ()
5813 _session->cancel_all_solo ();
5818 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5820 /* this resets focus to the first focusable parent of the given widget,
5821 * or, if there is no focusable parent, cancels focus in the toplevel
5822 * window that the given widget is packed into (if there is one).
5829 Gtk::Widget* top = w->get_toplevel();
5831 if (!top || !top->is_toplevel()) {
5835 w = w->get_parent ();
5839 if (w->is_toplevel()) {
5840 /* Setting the focus widget to a Gtk::Window causes all
5841 * subsequent calls to ::has_focus() on the nominal
5842 * focus widget in that window to return
5843 * false. Workaround: never set focus to the toplevel
5849 if (w->get_can_focus ()) {
5850 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5851 win->set_focus (*w);
5854 w = w->get_parent ();
5857 if (top == &_main_window) {
5861 /* no focusable parent found, cancel focus in top level window.
5862 C++ API cannot be used for this. Thanks, references.
5865 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);