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 "time_axis_view_item.h"
174 #include "time_info_box.h"
177 #include "utils_videotl.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))
283 , auto_input_button (ArdourButton::led_default_elements)
285 , auto_return_button (ArdourButton::led_default_elements)
286 , follow_edits_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"), _("Keyboard Shortcuts"), 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_rec_preroll ()
2458 editor->rec_with_preroll ();
2462 ARDOUR_UI::transport_rewind (int option)
2464 float current_transport_speed;
2467 current_transport_speed = _session->transport_speed();
2469 if (current_transport_speed >= 0.0f) {
2472 _session->request_transport_speed (-1.0f);
2475 _session->request_transport_speed (-4.0f);
2478 _session->request_transport_speed (-0.5f);
2483 _session->request_transport_speed (current_transport_speed * 1.5f);
2489 ARDOUR_UI::transport_forward (int option)
2495 float current_transport_speed = _session->transport_speed();
2497 if (current_transport_speed <= 0.0f) {
2500 _session->request_transport_speed (1.0f);
2503 _session->request_transport_speed (4.0f);
2506 _session->request_transport_speed (0.5f);
2511 _session->request_transport_speed (current_transport_speed * 1.5f);
2516 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2522 boost::shared_ptr<Route> r;
2524 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2526 boost::shared_ptr<Track> t;
2528 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2529 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2535 ARDOUR_UI::map_transport_state ()
2538 auto_loop_button.unset_active_state ();
2539 play_selection_button.unset_active_state ();
2540 roll_button.unset_active_state ();
2541 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2542 layered_button.set_sensitive (false);
2546 shuttle_box.map_transport_state ();
2548 float sp = _session->transport_speed();
2554 if (_session->get_play_range()) {
2556 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2557 roll_button.unset_active_state ();
2558 auto_loop_button.unset_active_state ();
2560 } else if (_session->get_play_loop ()) {
2562 auto_loop_button.set_active (true);
2563 play_selection_button.set_active (false);
2564 if (Config->get_loop_is_mode()) {
2565 roll_button.set_active (true);
2567 roll_button.set_active (false);
2572 roll_button.set_active (true);
2573 play_selection_button.set_active (false);
2574 auto_loop_button.set_active (false);
2577 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2578 /* light up both roll and play-selection if they are joined */
2579 roll_button.set_active (true);
2580 play_selection_button.set_active (true);
2582 layered_button.set_sensitive (!_session->actively_recording ());
2584 stop_button.set_active (false);
2588 layered_button.set_sensitive (true);
2589 stop_button.set_active (true);
2590 roll_button.set_active (false);
2591 play_selection_button.set_active (false);
2592 if (Config->get_loop_is_mode ()) {
2593 auto_loop_button.set_active (_session->get_play_loop());
2595 auto_loop_button.set_active (false);
2597 update_disk_space ();
2602 ARDOUR_UI::blink_handler (bool blink_on)
2604 transport_rec_enable_blink (blink_on);
2605 solo_blink (blink_on);
2606 sync_blink (blink_on);
2607 audition_blink (blink_on);
2608 feedback_blink (blink_on);
2609 error_blink (blink_on);
2613 ARDOUR_UI::update_clocks ()
2615 if (!_session) return;
2617 if (editor && !editor->dragging_playhead()) {
2618 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2623 ARDOUR_UI::start_clocking ()
2625 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2626 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2628 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2633 ARDOUR_UI::stop_clocking ()
2635 clock_signal_connection.disconnect ();
2639 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2643 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2645 label->set_text (buf);
2646 bar->set_fraction (fraction);
2648 /* process events, redraws, etc. */
2650 while (gtk_events_pending()) {
2651 gtk_main_iteration ();
2654 return true; /* continue with save-as */
2658 ARDOUR_UI::save_session_as ()
2664 if (!save_as_dialog) {
2665 save_as_dialog = new SaveAsDialog;
2668 save_as_dialog->set_name (_session->name());
2670 int response = save_as_dialog->run ();
2672 save_as_dialog->hide ();
2675 case Gtk::RESPONSE_OK:
2684 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2685 sa.new_name = save_as_dialog->new_name ();
2686 sa.switch_to = save_as_dialog->switch_to();
2687 sa.copy_media = save_as_dialog->copy_media();
2688 sa.copy_external = save_as_dialog->copy_external();
2689 sa.include_media = save_as_dialog->include_media ();
2691 /* Only bother with a progress dialog if we're going to copy
2692 media into the save-as target. Without that choice, this
2693 will be very fast because we're only talking about a few kB's to
2694 perhaps a couple of MB's of data.
2697 ArdourDialog progress_dialog (_("Save As"), true);
2699 if (sa.include_media && sa.copy_media) {
2702 Gtk::ProgressBar progress_bar;
2704 progress_dialog.get_vbox()->pack_start (label);
2705 progress_dialog.get_vbox()->pack_start (progress_bar);
2707 progress_bar.show ();
2709 /* this signal will be emitted from within this, the calling thread,
2710 * after every file is copied. It provides information on percentage
2711 * complete (in terms of total data to copy), the number of files
2712 * copied so far, and the total number to copy.
2717 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2719 progress_dialog.show_all ();
2720 progress_dialog.present ();
2723 if (_session->save_as (sa)) {
2725 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2729 if (!sa.include_media) {
2730 unload_session (false);
2731 load_session (sa.final_session_folder_name, sa.new_name);
2736 ARDOUR_UI::archive_session ()
2744 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2746 SessionArchiveDialog sad;
2747 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2748 int response = sad.run ();
2750 if (response != Gtk::RESPONSE_OK) {
2755 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2756 MessageDialog msg (_("Session Archiving failed."));
2762 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2766 struct tm local_time;
2769 localtime_r (&n, &local_time);
2770 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2772 save_state (timebuf, switch_to_it);
2777 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2781 prompter.get_result (snapname);
2783 bool do_save = (snapname.length() != 0);
2786 char illegal = Session::session_name_is_legal(snapname);
2788 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2789 "snapshot names may not contain a '%1' character"), illegal));
2795 vector<std::string> p;
2796 get_state_files_in_directory (_session->session_directory().root_path(), p);
2797 vector<string> n = get_file_names_no_extension (p);
2799 if (find (n.begin(), n.end(), snapname) != n.end()) {
2801 do_save = overwrite_file_dialog (prompter,
2802 _("Confirm Snapshot Overwrite"),
2803 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2807 save_state (snapname, switch_to_it);
2817 /** Ask the user for the name of a new snapshot and then take it.
2821 ARDOUR_UI::snapshot_session (bool switch_to_it)
2823 ArdourPrompter prompter (true);
2825 prompter.set_name ("Prompter");
2826 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2828 prompter.set_title (_("Snapshot and switch"));
2829 prompter.set_prompt (_("New session name"));
2831 prompter.set_title (_("Take Snapshot"));
2832 prompter.set_prompt (_("Name of new snapshot"));
2836 prompter.set_initial_text (_session->snap_name());
2838 Glib::DateTime tm (g_date_time_new_now_local ());
2839 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2842 bool finished = false;
2844 switch (prompter.run()) {
2845 case RESPONSE_ACCEPT:
2847 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2858 /** Ask the user for a new session name and then rename the session to it.
2862 ARDOUR_UI::rename_session ()
2868 ArdourPrompter prompter (true);
2871 prompter.set_name ("Prompter");
2872 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2873 prompter.set_title (_("Rename Session"));
2874 prompter.set_prompt (_("New session name"));
2877 switch (prompter.run()) {
2878 case RESPONSE_ACCEPT:
2880 prompter.get_result (name);
2882 bool do_rename = (name.length() != 0);
2885 char illegal = Session::session_name_is_legal (name);
2888 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2889 "session names may not contain a '%1' character"), illegal));
2894 switch (_session->rename (name)) {
2896 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2897 msg.set_position (WIN_POS_MOUSE);
2905 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2906 msg.set_position (WIN_POS_MOUSE);
2922 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2924 if (!_session || _session->deletion_in_progress()) {
2928 XMLNode* node = new XMLNode (X_("UI"));
2930 WM::Manager::instance().add_state (*node);
2932 node->add_child_nocopy (gui_object_state->get_state());
2934 _session->add_extra_xml (*node);
2936 if (export_video_dialog) {
2937 _session->add_extra_xml (export_video_dialog->get_state());
2940 save_state_canfail (name, switch_to_it);
2944 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2949 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2954 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2959 ARDOUR_UI::primary_clock_value_changed ()
2962 _session->request_locate (primary_clock->current_time ());
2967 ARDOUR_UI::big_clock_value_changed ()
2970 _session->request_locate (big_clock->current_time ());
2975 ARDOUR_UI::secondary_clock_value_changed ()
2978 _session->request_locate (secondary_clock->current_time ());
2983 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2985 if (_session == 0) {
2989 if (_session->step_editing()) {
2993 Session::RecordState const r = _session->record_status ();
2994 bool const h = _session->have_rec_enabled_track ();
2996 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2998 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3000 rec_button.set_active_state (Gtkmm2ext::Off);
3002 } else if (r == Session::Recording && h) {
3003 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3005 rec_button.unset_active_state ();
3010 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3014 prompter.get_result (name);
3016 if (name.length()) {
3017 int failed = _session->save_template (name);
3019 if (failed == -2) { /* file already exists. */
3020 bool overwrite = overwrite_file_dialog (prompter,
3021 _("Confirm Template Overwrite"),
3022 _("A template already exists with that name. Do you want to overwrite it?"));
3025 _session->save_template (name, true);
3037 ARDOUR_UI::save_template ()
3039 ArdourPrompter prompter (true);
3041 if (!check_audioengine (_main_window)) {
3045 prompter.set_name (X_("Prompter"));
3046 prompter.set_title (_("Save Template"));
3047 prompter.set_prompt (_("Name for template:"));
3048 prompter.set_initial_text(_session->name() + _("-template"));
3049 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3051 bool finished = false;
3053 switch (prompter.run()) {
3054 case RESPONSE_ACCEPT:
3055 finished = process_save_template_prompter (prompter);
3066 ARDOUR_UI::edit_metadata ()
3068 SessionMetadataEditor dialog;
3069 dialog.set_session (_session);
3070 dialog.grab_focus ();
3075 ARDOUR_UI::import_metadata ()
3077 SessionMetadataImporter dialog;
3078 dialog.set_session (_session);
3083 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3085 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3087 MessageDialog msg (str,
3089 Gtk::MESSAGE_WARNING,
3090 Gtk::BUTTONS_YES_NO,
3094 msg.set_name (X_("OpenExistingDialog"));
3095 msg.set_title (_("Open Existing Session"));
3096 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3097 msg.set_position (Gtk::WIN_POS_CENTER);
3098 pop_back_splash (msg);
3100 switch (msg.run()) {
3109 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3111 BusProfile bus_profile;
3115 bus_profile.master_out_channels = 2;
3116 bus_profile.input_ac = AutoConnectPhysical;
3117 bus_profile.output_ac = AutoConnectMaster;
3118 bus_profile.requested_physical_in = 0; // use all available
3119 bus_profile.requested_physical_out = 0; // use all available
3123 /* get settings from advanced section of NSD */
3125 if (sd.create_master_bus()) {
3126 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3128 bus_profile.master_out_channels = 0;
3131 if (sd.connect_inputs()) {
3132 bus_profile.input_ac = AutoConnectPhysical;
3134 bus_profile.input_ac = AutoConnectOption (0);
3137 bus_profile.output_ac = AutoConnectOption (0);
3139 if (sd.connect_outputs ()) {
3140 if (sd.connect_outs_to_master()) {
3141 bus_profile.output_ac = AutoConnectMaster;
3142 } else if (sd.connect_outs_to_physical()) {
3143 bus_profile.output_ac = AutoConnectPhysical;
3147 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3148 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3151 if (build_session (session_path, session_name, bus_profile)) {
3159 ARDOUR_UI::load_from_application_api (const std::string& path)
3161 /* OS X El Capitan (and probably later) now somehow passes the command
3162 line arguments to an app via the openFile delegate protocol. Ardour
3163 already does its own command line processing, and having both
3164 pathways active causes crashes. So, if the command line was already
3165 set, do nothing here.
3168 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3172 ARDOUR_COMMAND_LINE::session_name = path;
3174 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3176 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3178 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3179 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3180 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3181 * -> SessionDialog is not displayed
3184 if (_session_dialog) {
3185 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3186 std::string session_path = path;
3187 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3188 session_path = Glib::path_get_dirname (session_path);
3190 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3191 _session_dialog->set_provided_session (session_name, session_path);
3192 _session_dialog->response (RESPONSE_NONE);
3193 _session_dialog->hide();
3198 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3199 /* /path/to/foo => /path/to/foo, foo */
3200 rv = load_session (path, basename_nosuffix (path));
3202 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3203 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3206 // if load_session fails -> pop up SessionDialog.
3208 ARDOUR_COMMAND_LINE::session_name = "";
3210 if (get_session_parameters (true, false)) {
3216 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3218 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3220 string session_name;
3221 string session_path;
3222 string template_name;
3224 bool likely_new = false;
3225 bool cancel_not_quit;
3227 /* deal with any existing DIRTY session now, rather than later. don't
3228 * treat a non-dirty session this way, so that it stays visible
3229 * as we bring up the new session dialog.
3232 if (_session && ARDOUR_UI::instance()->video_timeline) {
3233 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3236 /* if there is already a session, relabel the button
3237 on the SessionDialog so that we don't Quit directly
3239 cancel_not_quit = (_session != 0);
3241 if (_session && _session->dirty()) {
3242 if (unload_session (false)) {
3243 /* unload cancelled by user */
3246 ARDOUR_COMMAND_LINE::session_name = "";
3249 if (!load_template.empty()) {
3250 should_be_new = true;
3251 template_name = load_template;
3254 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3255 session_path = ARDOUR_COMMAND_LINE::session_name;
3257 if (!session_path.empty()) {
3258 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3259 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3260 /* session/snapshot file, change path to be dir */
3261 session_path = Glib::path_get_dirname (session_path);
3266 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3268 _session_dialog = &session_dialog;
3271 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3273 /* if they named a specific statefile, use it, otherwise they are
3274 just giving a session folder, and we want to use it as is
3275 to find the session.
3278 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3280 if (suffix != string::npos) {
3281 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3282 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3283 session_name = Glib::path_get_basename (session_name);
3285 session_path = ARDOUR_COMMAND_LINE::session_name;
3286 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3291 session_dialog.clear_given ();
3294 if (should_be_new || session_name.empty()) {
3295 /* need the dialog to get info from user */
3297 cerr << "run dialog\n";
3299 switch (session_dialog.run()) {
3300 case RESPONSE_ACCEPT:
3303 /* this is used for async * app->ShouldLoad(). */
3304 continue; // while loop
3307 if (quit_on_cancel) {
3308 // JE - Currently (July 2014) this section can only get reached if the
3309 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3310 // point does NOT indicate an abnormal termination). Therefore, let's
3311 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3313 pthread_cancel_all ();
3321 session_dialog.hide ();
3324 /* if we run the startup dialog again, offer more than just "new session" */
3326 should_be_new = false;
3328 session_name = session_dialog.session_name (likely_new);
3329 session_path = session_dialog.session_folder ();
3336 int rv = ARDOUR::inflate_session (session_name,
3337 Config->get_default_session_parent_dir(), session_path, session_name);
3339 MessageDialog msg (session_dialog,
3340 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3345 session_dialog.set_provided_session (session_name, session_path);
3349 // XXX check archive, inflate
3350 string::size_type suffix = session_name.find (statefile_suffix);
3352 if (suffix != string::npos) {
3353 session_name = session_name.substr (0, suffix);
3356 /* this shouldn't happen, but we catch it just in case it does */
3358 if (session_name.empty()) {
3362 if (session_dialog.use_session_template()) {
3363 template_name = session_dialog.session_template_name();
3364 _session_is_new = true;
3367 if (session_name[0] == G_DIR_SEPARATOR ||
3368 #ifdef PLATFORM_WINDOWS
3369 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3371 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3372 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3377 /* absolute path or cwd-relative path specified for session name: infer session folder
3378 from what was given.
3381 session_path = Glib::path_get_dirname (session_name);
3382 session_name = Glib::path_get_basename (session_name);
3386 session_path = session_dialog.session_folder();
3388 char illegal = Session::session_name_is_legal (session_name);
3391 MessageDialog msg (session_dialog,
3392 string_compose (_("To ensure compatibility with various systems\n"
3393 "session names may not contain a '%1' character"),
3396 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3401 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3404 if (likely_new && !nsm) {
3406 std::string existing = Glib::build_filename (session_path, session_name);
3408 if (!ask_about_loading_existing_session (existing)) {
3409 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3414 _session_is_new = false;
3419 pop_back_splash (session_dialog);
3420 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3422 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3426 char illegal = Session::session_name_is_legal(session_name);
3429 pop_back_splash (session_dialog);
3430 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3431 "session names may not contain a '%1' character"), illegal));
3433 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3437 _session_is_new = true;
3440 if (likely_new && template_name.empty()) {
3442 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3446 ret = load_session (session_path, session_name, template_name);
3449 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3453 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3454 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3458 /* clear this to avoid endless attempts to load the
3462 ARDOUR_COMMAND_LINE::session_name = "";
3466 _session_dialog = NULL;
3472 ARDOUR_UI::close_session()
3474 if (!check_audioengine (_main_window)) {
3478 if (unload_session (true)) {
3482 ARDOUR_COMMAND_LINE::session_name = "";
3484 if (get_session_parameters (true, false)) {
3487 if (splash && splash->is_visible()) {
3488 // in 1 second, hide the splash screen
3489 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3493 /** @param snap_name Snapshot name (without .ardour suffix).
3494 * @return -2 if the load failed because we are not connected to the AudioEngine.
3497 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3499 Session *new_session;
3504 unload_status = unload_session ();
3506 if (unload_status < 0) {
3508 } else if (unload_status > 0) {
3514 session_loaded = false;
3516 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3519 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3522 /* this one is special */
3524 catch (AudioEngine::PortRegistrationFailure& err) {
3526 MessageDialog msg (err.what(),
3529 Gtk::BUTTONS_CLOSE);
3531 msg.set_title (_("Port Registration Error"));
3532 msg.set_secondary_text (_("Click the Close button to try again."));
3533 msg.set_position (Gtk::WIN_POS_CENTER);
3534 pop_back_splash (msg);
3537 int response = msg.run ();
3542 case RESPONSE_CANCEL:
3549 catch (SessionException e) {
3550 MessageDialog msg (string_compose(
3551 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3552 path, snap_name, e.what()),
3557 msg.set_title (_("Loading Error"));
3558 msg.set_position (Gtk::WIN_POS_CENTER);
3559 pop_back_splash (msg);
3571 MessageDialog msg (string_compose(
3572 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3578 msg.set_title (_("Loading Error"));
3579 msg.set_position (Gtk::WIN_POS_CENTER);
3580 pop_back_splash (msg);
3592 list<string> const u = new_session->unknown_processors ();
3594 MissingPluginDialog d (_session, u);
3599 if (!new_session->writable()) {
3600 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3605 msg.set_title (_("Read-only Session"));
3606 msg.set_position (Gtk::WIN_POS_CENTER);
3607 pop_back_splash (msg);
3614 /* Now the session been created, add the transport controls */
3615 new_session->add_controllable(roll_controllable);
3616 new_session->add_controllable(stop_controllable);
3617 new_session->add_controllable(goto_start_controllable);
3618 new_session->add_controllable(goto_end_controllable);
3619 new_session->add_controllable(auto_loop_controllable);
3620 new_session->add_controllable(play_selection_controllable);
3621 new_session->add_controllable(rec_controllable);
3623 set_session (new_session);
3625 session_loaded = true;
3628 _session->set_clean ();
3631 #ifdef WINDOWS_VST_SUPPORT
3632 fst_stop_threading();
3636 Timers::TimerSuspender t;
3640 #ifdef WINDOWS_VST_SUPPORT
3641 fst_start_threading();
3650 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3652 Session *new_session;
3655 session_loaded = false;
3656 x = unload_session ();
3664 _session_is_new = true;
3667 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3670 catch (SessionException e) {
3671 cerr << "Here are the errors associated with this failed session:\n";
3673 cerr << "---------\n";
3674 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3675 msg.set_title (_("Loading Error"));
3676 msg.set_position (Gtk::WIN_POS_CENTER);
3677 pop_back_splash (msg);
3682 cerr << "Here are the errors associated with this failed session:\n";
3684 cerr << "---------\n";
3685 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3686 msg.set_title (_("Loading Error"));
3687 msg.set_position (Gtk::WIN_POS_CENTER);
3688 pop_back_splash (msg);
3693 /* Give the new session the default GUI state, if such things exist */
3696 n = Config->instant_xml (X_("Editor"));
3698 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3699 new_session->add_instant_xml (*n, false);
3701 n = Config->instant_xml (X_("Mixer"));
3703 new_session->add_instant_xml (*n, false);
3706 n = Config->instant_xml (X_("Preferences"));
3708 new_session->add_instant_xml (*n, false);
3711 /* Put the playhead at 0 and scroll fully left */
3712 n = new_session->instant_xml (X_("Editor"));
3714 n->add_property (X_("playhead"), X_("0"));
3715 n->add_property (X_("left-frame"), X_("0"));
3718 set_session (new_session);
3720 session_loaded = true;
3722 new_session->save_state(new_session->name());
3728 ARDOUR_UI::launch_chat ()
3730 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3732 dialog.set_title (_("About the Chat"));
3733 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."));
3735 switch (dialog.run()) {
3738 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3739 #elif defined PLATFORM_WINDOWS
3740 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3742 open_uri("http://webchat.freenode.net/?channels=ardour");
3751 ARDOUR_UI::launch_manual ()
3753 PBD::open_uri (Config->get_tutorial_manual_url());
3757 ARDOUR_UI::launch_reference ()
3759 PBD::open_uri (Config->get_reference_manual_url());
3763 ARDOUR_UI::launch_tracker ()
3765 PBD::open_uri ("http://tracker.ardour.org");
3769 ARDOUR_UI::launch_subscribe ()
3771 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3775 ARDOUR_UI::launch_cheat_sheet ()
3778 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3780 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3785 ARDOUR_UI::launch_website ()
3787 PBD::open_uri ("http://ardour.org");
3791 ARDOUR_UI::launch_website_dev ()
3793 PBD::open_uri ("http://ardour.org/development.html");
3797 ARDOUR_UI::launch_forums ()
3799 PBD::open_uri ("https://community.ardour.org/forums");
3803 ARDOUR_UI::launch_howto_report ()
3805 PBD::open_uri ("http://ardour.org/reporting_bugs");
3809 ARDOUR_UI::loading_message (const std::string& msg)
3811 if (ARDOUR_COMMAND_LINE::no_splash) {
3819 splash->message (msg);
3823 ARDOUR_UI::show_splash ()
3827 splash = new Splash;
3837 ARDOUR_UI::hide_splash ()
3844 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3848 removed = rep.paths.size();
3851 MessageDialog msgd (_main_window,
3852 _("No files were ready for clean-up"),
3856 msgd.set_title (_("Clean-up"));
3857 msgd.set_secondary_text (_("If this seems suprising, \n\
3858 check for any existing snapshots.\n\
3859 These may still include regions that\n\
3860 require some unused files to continue to exist."));
3866 ArdourDialog results (_("Clean-up"), true, false);
3868 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3869 CleanupResultsModelColumns() {
3873 Gtk::TreeModelColumn<std::string> visible_name;
3874 Gtk::TreeModelColumn<std::string> fullpath;
3878 CleanupResultsModelColumns results_columns;
3879 Glib::RefPtr<Gtk::ListStore> results_model;
3880 Gtk::TreeView results_display;
3882 results_model = ListStore::create (results_columns);
3883 results_display.set_model (results_model);
3884 results_display.append_column (list_title, results_columns.visible_name);
3886 results_display.set_name ("CleanupResultsList");
3887 results_display.set_headers_visible (true);
3888 results_display.set_headers_clickable (false);
3889 results_display.set_reorderable (false);
3891 Gtk::ScrolledWindow list_scroller;
3894 Gtk::HBox dhbox; // the hbox for the image and text
3895 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3896 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3898 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3900 const string dead_directory = _session->session_directory().dead_path();
3903 %1 - number of files removed
3904 %2 - location of "dead"
3905 %3 - size of files affected
3906 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3909 const char* bprefix;
3910 double space_adjusted = 0;
3912 if (rep.space < 1000) {
3914 space_adjusted = rep.space;
3915 } else if (rep.space < 1000000) {
3916 bprefix = _("kilo");
3917 space_adjusted = floorf((float)rep.space / 1000.0);
3918 } else if (rep.space < 1000000 * 1000) {
3919 bprefix = _("mega");
3920 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3922 bprefix = _("giga");
3923 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3927 txt.set_markup (string_compose (P_("\
3928 The following file was deleted from %2,\n\
3929 releasing %3 %4bytes of disk space", "\
3930 The following %1 files were deleted from %2,\n\
3931 releasing %3 %4bytes of disk space", removed),
3932 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3934 txt.set_markup (string_compose (P_("\
3935 The following file was not in use and \n\
3936 has been moved to: %2\n\n\
3937 After a restart of %5\n\n\
3938 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3939 will release an additional %3 %4bytes of disk space.\n", "\
3940 The following %1 files were not in use and \n\
3941 have been moved to: %2\n\n\
3942 After a restart of %5\n\n\
3943 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3944 will release an additional %3 %4bytes of disk space.\n", removed),
3945 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3948 dhbox.pack_start (*dimage, true, false, 5);
3949 dhbox.pack_start (txt, true, false, 5);
3951 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3952 TreeModel::Row row = *(results_model->append());
3953 row[results_columns.visible_name] = *i;
3954 row[results_columns.fullpath] = *i;
3957 list_scroller.add (results_display);
3958 list_scroller.set_size_request (-1, 150);
3959 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3961 dvbox.pack_start (dhbox, true, false, 5);
3962 dvbox.pack_start (list_scroller, true, false, 5);
3963 ddhbox.pack_start (dvbox, true, false, 5);
3965 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3966 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3967 results.set_default_response (RESPONSE_CLOSE);
3968 results.set_position (Gtk::WIN_POS_MOUSE);
3970 results_display.show();
3971 list_scroller.show();
3978 //results.get_vbox()->show();
3979 results.set_resizable (false);
3986 ARDOUR_UI::cleanup ()
3988 if (_session == 0) {
3989 /* shouldn't happen: menu item is insensitive */
3994 MessageDialog checker (_("Are you sure you want to clean-up?"),
3996 Gtk::MESSAGE_QUESTION,
3999 checker.set_title (_("Clean-up"));
4001 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4002 ALL undo/redo information will be lost if you clean-up.\n\
4003 Clean-up will move all unused files to a \"dead\" location."));
4005 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4006 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4007 checker.set_default_response (RESPONSE_CANCEL);
4009 checker.set_name (_("CleanupDialog"));
4010 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4011 checker.set_position (Gtk::WIN_POS_MOUSE);
4013 switch (checker.run()) {
4014 case RESPONSE_ACCEPT:
4020 ARDOUR::CleanupReport rep;
4022 editor->prepare_for_cleanup ();
4024 /* do not allow flush until a session is reloaded */
4026 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4028 act->set_sensitive (false);
4031 if (_session->cleanup_sources (rep)) {
4032 editor->finish_cleanup ();
4036 editor->finish_cleanup ();
4039 display_cleanup_results (rep, _("Cleaned Files"), false);
4043 ARDOUR_UI::flush_trash ()
4045 if (_session == 0) {
4046 /* shouldn't happen: menu item is insensitive */
4050 ARDOUR::CleanupReport rep;
4052 if (_session->cleanup_trash_sources (rep)) {
4056 display_cleanup_results (rep, _("deleted file"), true);
4060 ARDOUR_UI::cleanup_peakfiles ()
4062 if (_session == 0) {
4063 /* shouldn't happen: menu item is insensitive */
4067 if (! _session->can_cleanup_peakfiles ()) {
4071 // get all region-views in this session
4073 TrackViewList empty;
4075 editor->get_regions_after(rs, (framepos_t) 0, empty);
4076 std::list<RegionView*> views = rs.by_layer();
4078 // remove displayed audio-region-views waveforms
4079 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4080 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4081 if (!arv) { continue ; }
4082 arv->delete_waves();
4085 // cleanup peak files:
4086 // - stop pending peakfile threads
4087 // - close peakfiles if any
4088 // - remove peak dir in session
4089 // - setup peakfiles (background thread)
4090 _session->cleanup_peakfiles ();
4092 // re-add waves to ARV
4093 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4094 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4095 if (!arv) { continue ; }
4096 arv->create_waves();
4100 PresentationInfo::order_t
4101 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4103 if (editor->get_selection().tracks.empty()) {
4104 return PresentationInfo::max_order;
4107 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4110 we want the new routes to have their order keys set starting from
4111 the highest order key in the selection + 1 (if available).
4114 if (place == RouteDialogs::AfterSelection) {
4115 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4117 order_hint = rtav->route()->presentation_info().order();
4120 } else if (place == RouteDialogs::BeforeSelection) {
4121 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4123 order_hint = rtav->route()->presentation_info().order();
4125 } else if (place == RouteDialogs::First) {
4128 /* leave order_hint at max_order */
4135 ARDOUR_UI::start_duplicate_routes ()
4137 if (!duplicate_routes_dialog) {
4138 duplicate_routes_dialog = new DuplicateRouteDialog;
4141 if (duplicate_routes_dialog->restart (_session)) {
4145 duplicate_routes_dialog->present ();
4149 ARDOUR_UI::add_route ()
4151 if (!add_route_dialog.get (false)) {
4152 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4159 if (add_route_dialog->is_visible()) {
4160 /* we're already doing this */
4164 add_route_dialog->set_position (WIN_POS_MOUSE);
4165 add_route_dialog->present();
4169 ARDOUR_UI::add_route_dialog_finished (int r)
4173 add_route_dialog->hide();
4176 case RESPONSE_ACCEPT:
4183 if ((count = add_route_dialog->count()) <= 0) {
4187 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4188 string template_path = add_route_dialog->track_template();
4189 DisplaySuspender ds;
4191 if (!template_path.empty()) {
4192 if (add_route_dialog->name_template_is_default()) {
4193 _session->new_route_from_template (count, order, template_path, string());
4195 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4200 ChanCount input_chan= add_route_dialog->channels ();
4201 ChanCount output_chan;
4202 string name_template = add_route_dialog->name_template ();
4203 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4204 RouteGroup* route_group = add_route_dialog->route_group ();
4205 AutoConnectOption oac = Config->get_output_auto_connect();
4206 bool strict_io = add_route_dialog->use_strict_io ();
4208 if (oac & AutoConnectMaster) {
4209 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4210 output_chan.set (DataType::MIDI, 0);
4212 output_chan = input_chan;
4215 /* XXX do something with name template */
4217 Session::ProcessorChangeBlocker pcb (_session);
4219 switch (add_route_dialog->type_wanted()) {
4220 case AddRouteDialog::AudioTrack:
4221 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4223 case AddRouteDialog::MidiTrack:
4224 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4226 case AddRouteDialog::MixedTrack:
4227 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4229 case AddRouteDialog::AudioBus:
4230 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4232 case AddRouteDialog::MidiBus:
4233 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4235 case AddRouteDialog::VCAMaster:
4236 session_add_vca (name_template, count);
4242 ARDOUR_UI::add_lua_script ()
4248 LuaScriptInfoPtr spi;
4249 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4250 switch (ss.run ()) {
4251 case Gtk::RESPONSE_ACCEPT:
4259 std::string script = "";
4262 script = Glib::file_get_contents (spi->path);
4263 } catch (Glib::FileError e) {
4264 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4265 MessageDialog am (msg);
4270 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4271 std::vector<std::string> reg = _session->registered_lua_functions ();
4273 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4274 switch (spd.run ()) {
4275 case Gtk::RESPONSE_ACCEPT:
4282 _session->register_lua_function (spd.name(), script, lsp);
4283 } catch (luabridge::LuaException const& e) {
4284 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4285 MessageDialog am (msg);
4287 } catch (SessionException e) {
4288 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4289 MessageDialog am (msg);
4295 ARDOUR_UI::remove_lua_script ()
4300 if (_session->registered_lua_function_count () == 0) {
4301 string msg = _("There are no active Lua session scripts present in this session.");
4302 MessageDialog am (msg);
4307 std::vector<std::string> reg = _session->registered_lua_functions ();
4308 SessionScriptManager sm ("Remove Lua Session Script", reg);
4309 switch (sm.run ()) {
4310 case Gtk::RESPONSE_ACCEPT:
4316 _session->unregister_lua_function (sm.name());
4317 } catch (luabridge::LuaException const& e) {
4318 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4319 MessageDialog am (msg);
4325 ARDOUR_UI::stop_video_server (bool ask_confirm)
4327 if (!video_server_process && ask_confirm) {
4328 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4330 if (video_server_process) {
4332 ArdourDialog confirm (_("Stop Video-Server"), true);
4333 Label m (_("Do you really want to stop the Video Server?"));
4334 confirm.get_vbox()->pack_start (m, true, true);
4335 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4336 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4337 confirm.show_all ();
4338 if (confirm.run() == RESPONSE_CANCEL) {
4342 delete video_server_process;
4343 video_server_process =0;
4348 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4350 ARDOUR_UI::start_video_server( float_window, true);
4354 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4360 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4361 if (video_server_process) {
4362 popup_error(_("The Video Server is already started."));
4364 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4370 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4372 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4374 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4376 video_server_dialog->set_transient_for (*float_window);
4379 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4380 video_server_dialog->hide();
4382 ResponseType r = (ResponseType) video_server_dialog->run ();
4383 video_server_dialog->hide();
4384 if (r != RESPONSE_ACCEPT) { return false; }
4385 if (video_server_dialog->show_again()) {
4386 Config->set_show_video_server_dialog(false);
4390 std::string icsd_exec = video_server_dialog->get_exec_path();
4391 std::string icsd_docroot = video_server_dialog->get_docroot();
4392 #ifndef PLATFORM_WINDOWS
4393 if (icsd_docroot.empty()) {
4394 icsd_docroot = VideoUtils::video_get_docroot (Config);
4399 #ifdef PLATFORM_WINDOWS
4400 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4401 /* OK, allow all drive letters */
4404 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4405 warning << _("Specified docroot is not an existing directory.") << endmsg;
4408 #ifndef PLATFORM_WINDOWS
4409 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4410 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4411 warning << _("Given Video Server is not an executable file.") << endmsg;
4415 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4416 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4417 warning << _("Given Video Server is not an executable file.") << endmsg;
4423 argp=(char**) calloc(9,sizeof(char*));
4424 argp[0] = strdup(icsd_exec.c_str());
4425 argp[1] = strdup("-P");
4426 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4427 argp[3] = strdup("-p");
4428 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4429 argp[5] = strdup("-C");
4430 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4431 argp[7] = strdup(icsd_docroot.c_str());
4433 stop_video_server();
4435 #ifdef PLATFORM_WINDOWS
4436 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4437 /* OK, allow all drive letters */
4440 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4441 Config->set_video_advanced_setup(false);
4443 std::ostringstream osstream;
4444 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4445 Config->set_video_server_url(osstream.str());
4446 Config->set_video_server_docroot(icsd_docroot);
4447 Config->set_video_advanced_setup(true);
4450 if (video_server_process) {
4451 delete video_server_process;
4454 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4455 if (video_server_process->start()) {
4456 warning << _("Cannot launch the video-server") << endmsg;
4459 int timeout = 120; // 6 sec
4460 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4461 Glib::usleep (50000);
4463 if (--timeout <= 0 || !video_server_process->is_running()) break;
4466 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4468 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4469 delete video_server_process;
4470 video_server_process = 0;
4478 ARDOUR_UI::add_video (Gtk::Window* float_window)
4484 if (!start_video_server(float_window, false)) {
4485 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4490 add_video_dialog->set_transient_for (*float_window);
4493 if (add_video_dialog->is_visible()) {
4494 /* we're already doing this */
4498 ResponseType r = (ResponseType) add_video_dialog->run ();
4499 add_video_dialog->hide();
4500 if (r != RESPONSE_ACCEPT) { return; }
4502 bool local_file, orig_local_file;
4503 std::string path = add_video_dialog->file_name(local_file);
4505 std::string orig_path = path;
4506 orig_local_file = local_file;
4508 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4510 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4511 warning << string_compose(_("could not open %1"), path) << endmsg;
4514 if (!local_file && path.length() == 0) {
4515 warning << _("no video-file selected") << endmsg;
4519 std::string audio_from_video;
4520 bool detect_ltc = false;
4522 switch (add_video_dialog->import_option()) {
4523 case VTL_IMPORT_TRANSCODE:
4525 TranscodeVideoDialog *transcode_video_dialog;
4526 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4527 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4528 transcode_video_dialog->hide();
4529 if (r != RESPONSE_ACCEPT) {
4530 delete transcode_video_dialog;
4534 audio_from_video = transcode_video_dialog->get_audiofile();
4536 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4539 else if (!audio_from_video.empty()) {
4540 editor->embed_audio_from_video(
4542 video_timeline->get_offset(),
4543 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4546 switch (transcode_video_dialog->import_option()) {
4547 case VTL_IMPORT_TRANSCODED:
4548 path = transcode_video_dialog->get_filename();
4551 case VTL_IMPORT_REFERENCE:
4554 delete transcode_video_dialog;
4557 delete transcode_video_dialog;
4561 case VTL_IMPORT_NONE:
4565 /* strip _session->session_directory().video_path() from video file if possible */
4566 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4567 path=path.substr(_session->session_directory().video_path().size());
4568 if (path.at(0) == G_DIR_SEPARATOR) {
4569 path=path.substr(1);
4573 video_timeline->set_update_session_fps(auto_set_session_fps);
4575 if (video_timeline->video_file_info(path, local_file)) {
4576 XMLNode* node = new XMLNode(X_("Videotimeline"));
4577 node->add_property (X_("Filename"), path);
4578 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4579 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4580 if (orig_local_file) {
4581 node->add_property (X_("OriginalVideoFile"), orig_path);
4583 node->remove_property (X_("OriginalVideoFile"));
4585 _session->add_extra_xml (*node);
4586 _session->set_dirty ();
4588 if (!audio_from_video.empty() && detect_ltc) {
4589 std::vector<LTCFileReader::LTCMap> ltc_seq;
4592 /* TODO ask user about TV standard (LTC alignment if any) */
4593 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4594 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4596 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4598 /* TODO seek near end of file, and read LTC until end.
4599 * if it fails to find any LTC frames, scan complete file
4601 * calculate drift of LTC compared to video-duration,
4602 * ask user for reference (timecode from start/mid/end)
4605 // LTCFileReader will have written error messages
4608 ::g_unlink(audio_from_video.c_str());
4610 if (ltc_seq.size() == 0) {
4611 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4613 /* the very first TC in the file is somteimes not aligned properly */
4614 int i = ltc_seq.size() -1;
4615 ARDOUR::frameoffset_t video_start_offset =
4616 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4617 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4618 video_timeline->set_offset(video_start_offset);
4622 _session->maybe_update_session_range(
4623 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4624 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4627 if (add_video_dialog->launch_xjadeo() && local_file) {
4628 editor->set_xjadeo_sensitive(true);
4629 editor->toggle_xjadeo_proc(1);
4631 editor->toggle_xjadeo_proc(0);
4633 editor->toggle_ruler_video(true);
4638 ARDOUR_UI::remove_video ()
4640 video_timeline->close_session();
4641 editor->toggle_ruler_video(false);
4644 video_timeline->set_offset_locked(false);
4645 video_timeline->set_offset(0);
4647 /* delete session state */
4648 XMLNode* node = new XMLNode(X_("Videotimeline"));
4649 _session->add_extra_xml(*node);
4650 node = new XMLNode(X_("Videomonitor"));
4651 _session->add_extra_xml(*node);
4652 node = new XMLNode(X_("Videoexport"));
4653 _session->add_extra_xml(*node);
4654 stop_video_server();
4658 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4660 if (localcacheonly) {
4661 video_timeline->vmon_update();
4663 video_timeline->flush_cache();
4665 editor->queue_visual_videotimeline_update();
4669 ARDOUR_UI::export_video (bool range)
4671 if (ARDOUR::Config->get_show_video_export_info()) {
4672 ExportVideoInfobox infobox (_session);
4673 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4674 if (infobox.show_again()) {
4675 ARDOUR::Config->set_show_video_export_info(false);
4678 case GTK_RESPONSE_YES:
4679 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4685 export_video_dialog->set_session (_session);
4686 export_video_dialog->apply_state(editor->get_selection().time, range);
4687 export_video_dialog->run ();
4688 export_video_dialog->hide ();
4692 ARDOUR_UI::preferences_settings () const
4697 node = _session->instant_xml(X_("Preferences"));
4699 node = Config->instant_xml(X_("Preferences"));
4703 node = new XMLNode (X_("Preferences"));
4710 ARDOUR_UI::mixer_settings () const
4715 node = _session->instant_xml(X_("Mixer"));
4717 node = Config->instant_xml(X_("Mixer"));
4721 node = new XMLNode (X_("Mixer"));
4728 ARDOUR_UI::main_window_settings () const
4733 node = _session->instant_xml(X_("Main"));
4735 node = Config->instant_xml(X_("Main"));
4739 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4740 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4745 node = new XMLNode (X_("Main"));
4752 ARDOUR_UI::editor_settings () const
4757 node = _session->instant_xml(X_("Editor"));
4759 node = Config->instant_xml(X_("Editor"));
4763 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4764 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4769 node = new XMLNode (X_("Editor"));
4776 ARDOUR_UI::keyboard_settings () const
4780 node = Config->extra_xml(X_("Keyboard"));
4783 node = new XMLNode (X_("Keyboard"));
4790 ARDOUR_UI::create_xrun_marker (framepos_t where)
4793 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4794 _session->locations()->add (location);
4799 ARDOUR_UI::halt_on_xrun_message ()
4801 cerr << "HALT on xrun\n";
4802 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4807 ARDOUR_UI::xrun_handler (framepos_t where)
4813 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4815 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4816 create_xrun_marker(where);
4819 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4820 halt_on_xrun_message ();
4825 ARDOUR_UI::disk_overrun_handler ()
4827 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4829 if (!have_disk_speed_dialog_displayed) {
4830 have_disk_speed_dialog_displayed = true;
4831 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4832 The disk system on your computer\n\
4833 was not able to keep up with %1.\n\
4835 Specifically, it failed to write data to disk\n\
4836 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4837 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4843 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4844 static MessageDialog *scan_dlg = NULL;
4845 static ProgressBar *scan_pbar = NULL;
4846 static HBox *scan_tbox = NULL;
4847 static Gtk::Button *scan_timeout_button;
4850 ARDOUR_UI::cancel_plugin_scan ()
4852 PluginManager::instance().cancel_plugin_scan();
4856 ARDOUR_UI::cancel_plugin_timeout ()
4858 PluginManager::instance().cancel_plugin_timeout();
4859 scan_timeout_button->set_sensitive (false);
4863 ARDOUR_UI::plugin_scan_timeout (int timeout)
4865 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4869 scan_pbar->set_sensitive (false);
4870 scan_timeout_button->set_sensitive (true);
4871 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4874 scan_pbar->set_sensitive (false);
4875 scan_timeout_button->set_sensitive (false);
4881 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4883 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4887 const bool cancelled = PluginManager::instance().cancelled();
4888 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4889 if (cancelled && scan_dlg->is_mapped()) {
4894 if (cancelled || !can_cancel) {
4899 static Gtk::Button *cancel_button;
4901 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4902 VBox* vbox = scan_dlg->get_vbox();
4903 vbox->set_size_request(400,-1);
4904 scan_dlg->set_title (_("Scanning for plugins"));
4906 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4907 cancel_button->set_name ("EditorGTKButton");
4908 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4909 cancel_button->show();
4911 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4913 scan_tbox = manage( new HBox() );
4915 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4916 scan_timeout_button->set_name ("EditorGTKButton");
4917 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4918 scan_timeout_button->show();
4920 scan_pbar = manage(new ProgressBar());
4921 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4922 scan_pbar->set_text(_("Scan Timeout"));
4925 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4926 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4928 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4931 assert(scan_dlg && scan_tbox && cancel_button);
4933 if (type == X_("closeme")) {
4937 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4940 if (!can_cancel || !cancelled) {
4941 scan_timeout_button->set_sensitive(false);
4943 cancel_button->set_sensitive(can_cancel && !cancelled);
4949 ARDOUR_UI::gui_idle_handler ()
4952 /* due to idle calls, gtk_events_pending() may always return true */
4953 while (gtk_events_pending() && --timeout) {
4954 gtk_main_iteration ();
4959 ARDOUR_UI::disk_underrun_handler ()
4961 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4963 if (!have_disk_speed_dialog_displayed) {
4964 have_disk_speed_dialog_displayed = true;
4965 MessageDialog* msg = new MessageDialog (
4966 _main_window, string_compose (_("The disk system on your computer\n\
4967 was not able to keep up with %1.\n\
4969 Specifically, it failed to read data from disk\n\
4970 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4971 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4977 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4979 have_disk_speed_dialog_displayed = false;
4984 ARDOUR_UI::session_dialog (std::string msg)
4986 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4990 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4997 ARDOUR_UI::pending_state_dialog ()
4999 HBox* hbox = manage (new HBox());
5000 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5001 ArdourDialog dialog (_("Crash Recovery"), true);
5002 Label message (string_compose (_("\
5003 This session appears to have been in the\n\
5004 middle of recording when %1 or\n\
5005 the computer was shutdown.\n\
5007 %1 can recover any captured audio for\n\
5008 you, or it can ignore it. Please decide\n\
5009 what you would like to do.\n"), PROGRAM_NAME));
5010 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5011 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5012 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5013 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5014 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5015 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5016 dialog.set_default_response (RESPONSE_ACCEPT);
5017 dialog.set_position (WIN_POS_CENTER);
5022 switch (dialog.run ()) {
5023 case RESPONSE_ACCEPT:
5031 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5033 HBox* hbox = new HBox();
5034 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5035 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5036 Label message (string_compose (_("\
5037 This session was created with a sample rate of %1 Hz, but\n\
5038 %2 is currently running at %3 Hz. If you load this session,\n\
5039 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5041 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5042 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5043 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5044 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5045 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5046 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5047 dialog.set_default_response (RESPONSE_ACCEPT);
5048 dialog.set_position (WIN_POS_CENTER);
5053 switch (dialog.run()) {
5054 case RESPONSE_ACCEPT:
5064 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5066 MessageDialog msg (string_compose (_("\
5067 This session was created with a sample rate of %1 Hz, but\n\
5068 %2 is currently running at %3 Hz.\n\
5069 Audio will be recorded and played at the wrong sample rate.\n\
5070 Re-Configure the Audio Engine in\n\
5071 Menu > Window > Audio/Midi Setup"),
5072 desired, PROGRAM_NAME, actual),
5074 Gtk::MESSAGE_WARNING);
5079 ARDOUR_UI::use_config ()
5081 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5083 set_transport_controllable_state (*node);
5088 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5090 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5091 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5093 primary_clock->set (pos);
5096 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5097 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5099 secondary_clock->set (pos);
5102 if (big_clock_window) {
5103 big_clock->set (pos);
5105 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5109 ARDOUR_UI::step_edit_status_change (bool yn)
5111 // XXX should really store pre-step edit status of things
5112 // we make insensitive
5115 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5116 rec_button.set_sensitive (false);
5118 rec_button.unset_active_state ();;
5119 rec_button.set_sensitive (true);
5124 ARDOUR_UI::record_state_changed ()
5126 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5129 /* why bother - the clock isn't visible */
5133 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5135 if (big_clock_window) {
5136 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5137 big_clock->set_active (true);
5139 big_clock->set_active (false);
5146 ARDOUR_UI::first_idle ()
5149 _session->allow_auto_play (true);
5153 editor->first_idle();
5156 Keyboard::set_can_save_keybindings (true);
5161 ARDOUR_UI::store_clock_modes ()
5163 XMLNode* node = new XMLNode(X_("ClockModes"));
5165 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5166 XMLNode* child = new XMLNode (X_("Clock"));
5168 child->add_property (X_("name"), (*x)->name());
5169 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5170 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5172 node->add_child_nocopy (*child);
5175 _session->add_extra_xml (*node);
5176 _session->set_dirty ();
5179 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5180 : Controllable (name), ui (u), type(tp)
5186 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5189 /* do nothing: these are radio-style actions */
5193 const char *action = 0;
5197 action = X_("Roll");
5200 action = X_("Stop");
5203 action = X_("GotoStart");
5206 action = X_("GotoEnd");
5209 action = X_("Loop");
5212 action = X_("PlaySelection");
5215 action = X_("Record");
5225 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5233 ARDOUR_UI::TransportControllable::get_value (void) const
5260 ARDOUR_UI::setup_profile ()
5262 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5263 Profile->set_small_screen ();
5266 if (g_getenv ("TRX")) {
5267 Profile->set_trx ();
5270 if (g_getenv ("MIXBUS")) {
5271 Profile->set_mixbus ();
5276 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5278 MissingFileDialog dialog (s, str, type);
5283 int result = dialog.run ();
5290 return 1; // quit entire session load
5293 result = dialog.get_action ();
5299 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5301 AmbiguousFileDialog dialog (file, hits);
5308 return dialog.get_which ();
5311 /** Allocate our thread-local buffers */
5313 ARDOUR_UI::get_process_buffers ()
5315 _process_thread->get_buffers ();
5318 /** Drop our thread-local buffers */
5320 ARDOUR_UI::drop_process_buffers ()
5322 _process_thread->drop_buffers ();
5326 ARDOUR_UI::feedback_detected ()
5328 _feedback_exists = true;
5332 ARDOUR_UI::successful_graph_sort ()
5334 _feedback_exists = false;
5338 ARDOUR_UI::midi_panic ()
5341 _session->midi_panic();
5346 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5348 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5349 const char* end_big = "</span>";
5350 const char* start_mono = "<tt>";
5351 const char* end_mono = "</tt>";
5353 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5354 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5355 "From now on, use the backup copy with older versions of %3"),
5356 xml_path, backup_path, PROGRAM_NAME,
5358 start_mono, end_mono), true);
5365 ARDOUR_UI::reset_peak_display ()
5367 if (!_session || !_session->master_out() || !editor_meter) return;
5368 editor_meter->clear_meters();
5369 editor_meter_max_peak = -INFINITY;
5370 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5374 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5376 if (!_session || !_session->master_out()) return;
5377 if (group == _session->master_out()->route_group()) {
5378 reset_peak_display ();
5383 ARDOUR_UI::reset_route_peak_display (Route* route)
5385 if (!_session || !_session->master_out()) return;
5386 if (_session->master_out().get() == route) {
5387 reset_peak_display ();
5392 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5394 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5395 audio_midi_setup->set_position (WIN_POS_CENTER);
5397 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5398 audio_midi_setup->try_autostart ();
5399 if (ARDOUR::AudioEngine::instance()->running()) {
5405 int response = audio_midi_setup->run();
5406 printf("RESPONSE %d\n", response);
5408 case Gtk::RESPONSE_DELETE_EVENT:
5411 if (!AudioEngine::instance()->running()) {
5414 audio_midi_setup->hide ();
5422 ARDOUR_UI::transport_numpad_timeout ()
5424 _numpad_locate_happening = false;
5425 if (_numpad_timeout_connection.connected() )
5426 _numpad_timeout_connection.disconnect();
5431 ARDOUR_UI::transport_numpad_decimal ()
5433 _numpad_timeout_connection.disconnect();
5435 if (_numpad_locate_happening) {
5436 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5437 _numpad_locate_happening = false;
5439 _pending_locate_num = 0;
5440 _numpad_locate_happening = true;
5441 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5446 ARDOUR_UI::transport_numpad_event (int num)
5448 if ( _numpad_locate_happening ) {
5449 _pending_locate_num = _pending_locate_num*10 + num;
5452 case 0: toggle_roll(false, false); break;
5453 case 1: transport_rewind(1); break;
5454 case 2: transport_forward(1); break;
5455 case 3: transport_record(true); break;
5456 case 4: toggle_session_auto_loop(); break;
5457 case 5: transport_record(false); toggle_session_auto_loop(); break;
5458 case 6: toggle_punch(); break;
5459 case 7: toggle_click(); break;
5460 case 8: toggle_auto_return(); break;
5461 case 9: toggle_follow_edits(); break;
5467 ARDOUR_UI::set_flat_buttons ()
5469 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5473 ARDOUR_UI::audioengine_became_silent ()
5475 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5477 Gtk::MESSAGE_WARNING,
5481 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5483 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5484 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5485 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5486 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5487 Gtk::HBox pay_button_box;
5488 Gtk::HBox subscribe_button_box;
5490 pay_button_box.pack_start (pay_button, true, false);
5491 subscribe_button_box.pack_start (subscribe_button, true, false);
5493 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 */
5495 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5496 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5498 msg.get_vbox()->pack_start (pay_label);
5499 msg.get_vbox()->pack_start (pay_button_box);
5500 msg.get_vbox()->pack_start (subscribe_label);
5501 msg.get_vbox()->pack_start (subscribe_button_box);
5503 msg.get_vbox()->show_all ();
5505 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5506 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5507 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5512 case Gtk::RESPONSE_YES:
5513 AudioEngine::instance()->reset_silence_countdown ();
5516 case Gtk::RESPONSE_NO:
5518 save_state_canfail ("");
5522 case Gtk::RESPONSE_CANCEL:
5524 /* don't reset, save session and exit */
5530 ARDOUR_UI::hide_application ()
5532 Application::instance ()-> hide ();
5536 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5538 /* icons, titles, WM stuff */
5540 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5542 if (window_icons.empty()) {
5543 Glib::RefPtr<Gdk::Pixbuf> icon;
5544 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5545 window_icons.push_back (icon);
5547 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5548 window_icons.push_back (icon);
5550 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5551 window_icons.push_back (icon);
5553 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5554 window_icons.push_back (icon);
5558 if (!window_icons.empty()) {
5559 window.set_default_icon_list (window_icons);
5562 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5564 if (!name.empty()) {
5568 window.set_title (title.get_string());
5569 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5571 window.set_flags (CAN_FOCUS);
5572 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5574 /* This is a hack to ensure that GTK-accelerators continue to
5575 * work. Once we switch over to entirely native bindings, this will be
5576 * unnecessary and should be removed
5578 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5580 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5581 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5582 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5583 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5587 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5589 Gtkmm2ext::Bindings* bindings = 0;
5590 Gtk::Window* window = 0;
5592 /* until we get ardour bindings working, we are not handling key
5596 if (ev->type != GDK_KEY_PRESS) {
5600 if (event_window == &_main_window) {
5602 window = event_window;
5604 /* find current tab contents */
5606 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5608 /* see if it uses the ardour binding system */
5611 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5614 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5618 window = event_window;
5620 /* see if window uses ardour binding system */
5622 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5625 /* An empty binding set is treated as if it doesn't exist */
5627 if (bindings && bindings->empty()) {
5631 return key_press_focus_accelerator_handler (*window, ev, bindings);
5634 static Gtkmm2ext::Bindings*
5635 get_bindings_from_widget_heirarchy (GtkWidget** w)
5640 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5643 *w = gtk_widget_get_parent (*w);
5646 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5650 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5652 GtkWindow* win = window.gobj();
5653 GtkWidget* focus = gtk_window_get_focus (win);
5654 GtkWidget* binding_widget = focus;
5655 bool special_handling_of_unmodified_accelerators = false;
5656 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5660 /* some widget has keyboard focus */
5662 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5664 /* A particular kind of focusable widget currently has keyboard
5665 * focus. All unmodified key events should go to that widget
5666 * first and not be used as an accelerator by default
5669 special_handling_of_unmodified_accelerators = true;
5673 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5674 if (focus_bindings) {
5675 bindings = focus_bindings;
5676 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5681 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",
5684 Gtkmm2ext::show_gdk_event_state (ev->state),
5685 special_handling_of_unmodified_accelerators,
5686 Keyboard::some_magic_widget_has_focus(),
5688 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5689 ((ev->state & mask) ? "yes" : "no"),
5690 window.get_title()));
5692 /* This exists to allow us to override the way GTK handles
5693 key events. The normal sequence is:
5695 a) event is delivered to a GtkWindow
5696 b) accelerators/mnemonics are activated
5697 c) if (b) didn't handle the event, propagate to
5698 the focus widget and/or focus chain
5700 The problem with this is that if the accelerators include
5701 keys without modifiers, such as the space bar or the
5702 letter "e", then pressing the key while typing into
5703 a text entry widget results in the accelerator being
5704 activated, instead of the desired letter appearing
5707 There is no good way of fixing this, but this
5708 represents a compromise. The idea is that
5709 key events involving modifiers (not Shift)
5710 get routed into the activation pathway first, then
5711 get propagated to the focus widget if necessary.
5713 If the key event doesn't involve modifiers,
5714 we deliver to the focus widget first, thus allowing
5715 it to get "normal text" without interference
5718 Of course, this can also be problematic: if there
5719 is a widget with focus, then it will swallow
5720 all "normal text" accelerators.
5724 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5726 /* no special handling or there are modifiers in effect: accelerate first */
5728 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5729 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5730 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5732 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5733 KeyboardKey k (ev->state, ev->keyval);
5737 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5739 if (bindings->activate (k, Bindings::Press)) {
5740 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5744 if (binding_widget) {
5745 binding_widget = gtk_widget_get_parent (binding_widget);
5746 if (binding_widget) {
5747 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5756 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5758 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5759 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5763 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5765 if (gtk_window_propagate_key_event (win, ev)) {
5766 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5772 /* no modifiers, propagate first */
5774 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5776 if (gtk_window_propagate_key_event (win, ev)) {
5777 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5781 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5782 KeyboardKey k (ev->state, ev->keyval);
5786 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5789 if (bindings->activate (k, Bindings::Press)) {
5790 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5794 if (binding_widget) {
5795 binding_widget = gtk_widget_get_parent (binding_widget);
5796 if (binding_widget) {
5797 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5806 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5808 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5809 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5814 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5819 ARDOUR_UI::load_bindings ()
5821 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5822 error << _("Global keybindings are missing") << endmsg;
5827 ARDOUR_UI::cancel_solo ()
5830 _session->cancel_all_solo ();
5835 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5837 /* this resets focus to the first focusable parent of the given widget,
5838 * or, if there is no focusable parent, cancels focus in the toplevel
5839 * window that the given widget is packed into (if there is one).
5846 Gtk::Widget* top = w->get_toplevel();
5848 if (!top || !top->is_toplevel()) {
5852 w = w->get_parent ();
5856 if (w->is_toplevel()) {
5857 /* Setting the focus widget to a Gtk::Window causes all
5858 * subsequent calls to ::has_focus() on the nominal
5859 * focus widget in that window to return
5860 * false. Workaround: never set focus to the toplevel
5866 if (w->get_can_focus ()) {
5867 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5868 win->set_focus (*w);
5871 w = w->get_parent ();
5874 if (top == &_main_window) {
5878 /* no focusable parent found, cancel focus in top level window.
5879 C++ API cannot be used for this. Thanks, references.
5882 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);