2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/xml++.h"
70 #include "gtkmm2ext/application.h"
71 #include "gtkmm2ext/bindings.h"
72 #include "gtkmm2ext/gtk_ui.h"
73 #include "gtkmm2ext/utils.h"
74 #include "gtkmm2ext/click_box.h"
75 #include "gtkmm2ext/fastmeter.h"
76 #include "gtkmm2ext/popup.h"
77 #include "gtkmm2ext/window_title.h"
79 #include "ardour/ardour.h"
80 #include "ardour/audio_backend.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/automation_watch.h"
85 #include "ardour/diskstream.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/filesystem_paths.h"
88 #include "ardour/ltc_file_reader.h"
89 #include "ardour/midi_track.h"
90 #include "ardour/port.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/process_thread.h"
93 #include "ardour/profile.h"
94 #include "ardour/recent_sessions.h"
95 #include "ardour/record_enable_control.h"
96 #include "ardour/session_directory.h"
97 #include "ardour/session_route.h"
98 #include "ardour/session_state_utils.h"
99 #include "ardour/session_utils.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/slave.h"
102 #include "ardour/system_exec.h"
103 #include "ardour/track.h"
104 #include "ardour/vca_manager.h"
105 #include "ardour/utils.h"
107 #include "LuaBridge/LuaBridge.h"
109 #ifdef WINDOWS_VST_SUPPORT
112 #ifdef AUDIOUNIT_SUPPORT
113 #include "ardour/audio_unit.h"
116 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
121 #include "timecode/time.h"
123 typedef uint64_t microseconds_t;
128 #include "add_route_dialog.h"
129 #include "ambiguous_file_dialog.h"
130 #include "ardour_ui.h"
131 #include "audio_clock.h"
132 #include "audio_region_view.h"
133 #include "big_clock_window.h"
134 #include "bundle_manager.h"
135 #include "duplicate_routes_dialog.h"
137 #include "engine_dialog.h"
138 #include "export_video_dialog.h"
139 #include "export_video_infobox.h"
140 #include "gain_meter.h"
141 #include "global_port_matrix.h"
142 #include "gui_object.h"
143 #include "gui_thread.h"
144 #include "keyboard.h"
145 #include "keyeditor.h"
146 #include "location_ui.h"
147 #include "lua_script_manager.h"
148 #include "luawindow.h"
149 #include "main_clock.h"
150 #include "missing_file_dialog.h"
151 #include "missing_plugin_dialog.h"
152 #include "mixer_ui.h"
153 #include "meterbridge.h"
154 #include "mouse_cursors.h"
157 #include "pingback.h"
158 #include "processor_box.h"
159 #include "prompter.h"
160 #include "public_editor.h"
161 #include "rc_option_editor.h"
162 #include "route_time_axis.h"
163 #include "route_params_ui.h"
164 #include "save_as_dialog.h"
165 #include "script_selector.h"
166 #include "session_archive_dialog.h"
167 #include "session_dialog.h"
168 #include "session_metadata_dialog.h"
169 #include "session_option_editor.h"
170 #include "speaker_dialog.h"
173 #include "theme_manager.h"
174 #include "time_axis_view_item.h"
175 #include "time_info_box.h"
178 #include "video_server_dialog.h"
179 #include "add_video_dialog.h"
180 #include "transcode_video_dialog.h"
182 #include "pbd/i18n.h"
184 using namespace ARDOUR;
185 using namespace ARDOUR_UI_UTILS;
187 using namespace Gtkmm2ext;
190 using namespace Editing;
192 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
194 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
195 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
198 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
200 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
201 "Would you like these files to be copied and used for %1 %2.x?\n\n"
202 "(This will require you to restart %1.)"),
203 PROGRAM_NAME, PROGRAM_VERSION, version),
204 false, /* no markup */
207 true /* modal, though it hardly matters since it is the only window */
210 msg.set_default_response (Gtk::RESPONSE_YES);
213 return (msg.run() == Gtk::RESPONSE_YES);
217 libxml_generic_error_func (void* /* parsing_context*/,
225 vsnprintf (buf, sizeof (buf), msg, ap);
226 error << buf << endmsg;
231 libxml_structured_error_func (void* /* parsing_context*/,
239 replace_all (msg, "\n", "");
242 if (err->file && err->line) {
243 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
246 error << ':' << err->int2;
251 error << X_("XML error: ") << msg << endmsg;
257 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
258 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
259 , session_loaded (false)
260 , gui_object_state (new GUIObjectState)
261 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
262 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
263 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
265 , global_actions (X_("global"))
266 , ignore_dual_punch (false)
267 , main_window_visibility (0)
272 , _mixer_on_top (false)
273 , _initial_verbose_plugin_scan (false)
274 , first_time_engine_run (true)
275 , secondary_clock_spacer (0)
276 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
277 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
278 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
279 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
280 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
281 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
282 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
284 , auto_return_button (ArdourButton::led_default_elements)
285 , follow_edits_button (ArdourButton::led_default_elements)
286 , auto_input_button (ArdourButton::led_default_elements)
287 , auditioning_alert_button (_("Audition"))
288 , solo_alert_button (_("Solo"))
289 , feedback_alert_button (_("Feedback"))
290 , error_alert_button ( ArdourButton::just_led_default_elements )
292 , editor_meter_peak_display()
293 , _numpad_locate_happening (false)
294 , _session_is_new (false)
295 , last_key_press_time (0)
299 , rc_option_editor (0)
300 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
301 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
302 , about (X_("about"), _("About"))
303 , location_ui (X_("locations"), S_("Ranges|Locations"))
304 , route_params (X_("inspector"), _("Tracks and Busses"))
305 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
306 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
307 , lua_script_window (X_("script-manager"), _("Script Manager"))
308 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
309 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
310 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
311 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
312 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
313 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
314 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
315 , video_server_process (0)
317 , have_configure_timeout (false)
318 , last_configure_time (0)
320 , have_disk_speed_dialog_displayed (false)
321 , _status_bar_visibility (X_("status-bar"))
322 , _feedback_exists (false)
323 , _log_not_acknowledged (LogLevelNone)
324 , duplicate_routes_dialog (0)
325 , editor_visibility_button (S_("Window|Editor"))
326 , mixer_visibility_button (S_("Window|Mixer"))
327 , prefs_visibility_button (S_("Window|Preferences"))
329 Gtkmm2ext::init (localedir);
331 UIConfiguration::instance().post_gui_init ();
333 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
334 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
336 /* configuration was modified, exit immediately */
341 if (string (VERSIONSTRING).find (".pre") != string::npos) {
342 /* check this is not being run from ./ardev etc. */
343 if (!running_from_source_tree ()) {
344 pre_release_dialog ();
348 if (theArdourUI == 0) {
352 /* track main window visibility */
354 main_window_visibility = new VisibilityTracker (_main_window);
356 /* stop libxml from spewing to stdout/stderr */
358 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
359 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
361 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
362 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
363 UIConfiguration::instance().map_parameters (pc);
365 roll_button.set_controllable (roll_controllable);
366 stop_button.set_controllable (stop_controllable);
367 goto_start_button.set_controllable (goto_start_controllable);
368 goto_end_button.set_controllable (goto_end_controllable);
369 auto_loop_button.set_controllable (auto_loop_controllable);
370 play_selection_button.set_controllable (play_selection_controllable);
371 rec_button.set_controllable (rec_controllable);
373 roll_button.set_name ("transport button");
374 stop_button.set_name ("transport button");
375 goto_start_button.set_name ("transport button");
376 goto_end_button.set_name ("transport button");
377 auto_loop_button.set_name ("transport button");
378 play_selection_button.set_name ("transport button");
379 rec_button.set_name ("transport recenable button");
380 midi_panic_button.set_name ("transport button");
382 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
383 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
385 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
387 /* handle dialog requests */
389 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
391 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
393 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
395 /* handle Audio/MIDI setup when session requires it */
397 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
399 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
401 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
403 /* handle sr mismatch with a dialog - cross-thread from engine */
404 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
406 /* handle requests to quit (coming from JACK session) */
408 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
410 /* tell the user about feedback */
412 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
413 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
415 /* handle requests to deal with missing files */
417 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
419 /* and ambiguous files */
421 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
423 /* also plugin scan messages */
424 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
425 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
427 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
429 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
432 /* lets get this party started */
434 setup_gtk_ardour_enums ();
437 SessionEvent::create_per_thread_pool ("GUI", 4096);
439 /* we like keyboards */
441 keyboard = new ArdourKeyboard(*this);
443 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
445 keyboard->set_state (*node, Stateful::loading_state_version);
448 UIConfiguration::instance().reset_dpi ();
450 TimeAxisViewItem::set_constant_heights ();
452 /* Set this up so that our window proxies can register actions */
454 ActionManager::init ();
456 /* The following must happen after ARDOUR::init() so that Config is set up */
458 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
461 key_editor.set_state (*ui_xml, 0);
462 session_option_editor.set_state (*ui_xml, 0);
463 speaker_config_window.set_state (*ui_xml, 0);
464 about.set_state (*ui_xml, 0);
465 add_route_dialog.set_state (*ui_xml, 0);
466 add_video_dialog.set_state (*ui_xml, 0);
467 route_params.set_state (*ui_xml, 0);
468 bundle_manager.set_state (*ui_xml, 0);
469 location_ui.set_state (*ui_xml, 0);
470 big_clock_window.set_state (*ui_xml, 0);
471 audio_port_matrix.set_state (*ui_xml, 0);
472 midi_port_matrix.set_state (*ui_xml, 0);
473 export_video_dialog.set_state (*ui_xml, 0);
474 lua_script_window.set_state (*ui_xml, 0);
477 /* Separate windows */
479 WM::Manager::instance().register_window (&key_editor);
480 WM::Manager::instance().register_window (&session_option_editor);
481 WM::Manager::instance().register_window (&speaker_config_window);
482 WM::Manager::instance().register_window (&about);
483 WM::Manager::instance().register_window (&add_route_dialog);
484 WM::Manager::instance().register_window (&add_video_dialog);
485 WM::Manager::instance().register_window (&route_params);
486 WM::Manager::instance().register_window (&audio_midi_setup);
487 WM::Manager::instance().register_window (&export_video_dialog);
488 WM::Manager::instance().register_window (&lua_script_window);
489 WM::Manager::instance().register_window (&bundle_manager);
490 WM::Manager::instance().register_window (&location_ui);
491 WM::Manager::instance().register_window (&big_clock_window);
492 WM::Manager::instance().register_window (&audio_port_matrix);
493 WM::Manager::instance().register_window (&midi_port_matrix);
495 /* do not retain position for add route dialog */
496 add_route_dialog.set_state_mask (WindowProxy::Size);
498 /* Trigger setting up the color scheme and loading the GTK RC file */
500 UIConfiguration::instance().load_rc_file (false);
502 _process_thread = new ProcessThread ();
503 _process_thread->init ();
505 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
511 ARDOUR_UI::pre_release_dialog ()
513 ArdourDialog d (_("Pre-Release Warning"), true, false);
514 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
516 Label* label = manage (new Label);
517 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
518 There are still several issues and bugs to be worked on,\n\
519 as well as general workflow improvements, before this can be considered\n\
520 release software. So, a few guidelines:\n\
522 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
523 though it may be so, depending on your workflow.\n\
524 2) Please wait for a helpful writeup of new features.\n\
525 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
526 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
527 making sure to note the product version number as 5.0-pre.\n\
528 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
529 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
530 can get there directly from within the program via the Help->Chat menu option.\n\
532 Full information on all the above can be found on the support page at\n\
534 http://ardour.org/support\n\
535 "), PROGRAM_NAME, VERSIONSTRING));
537 d.get_vbox()->set_border_width (12);
538 d.get_vbox()->pack_start (*label, false, false, 12);
539 d.get_vbox()->show_all ();
544 GlobalPortMatrixWindow*
545 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
550 return new GlobalPortMatrixWindow (_session, type);
554 ARDOUR_UI::attach_to_engine ()
556 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
557 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
561 ARDOUR_UI::engine_stopped ()
563 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
564 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
565 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
566 update_sample_rate (0);
571 ARDOUR_UI::engine_running ()
573 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
574 if (first_time_engine_run) {
576 first_time_engine_run = false;
580 _session->reset_xrun_count ();
582 update_disk_space ();
584 update_xrun_count ();
585 update_sample_rate (AudioEngine::instance()->sample_rate());
586 update_timecode_format ();
587 update_peak_thread_work ();
588 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
589 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
593 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
595 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
596 /* we can't rely on the original string continuing to exist when we are called
597 again in the GUI thread, so make a copy and note that we need to
600 char *copy = strdup (reason);
601 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
605 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
606 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
608 update_sample_rate (0);
612 /* if the reason is a non-empty string, it means that the backend was shutdown
613 rather than just Ardour.
616 if (strlen (reason)) {
617 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
619 msgstr = string_compose (_("\
620 The audio backend has either been shutdown or it\n\
621 disconnected %1 because %1\n\
622 was not fast enough. Try to restart\n\
623 the audio backend and save the session."), PROGRAM_NAME);
626 MessageDialog msg (_main_window, msgstr);
627 pop_back_splash (msg);
631 free (const_cast<char*> (reason));
636 ARDOUR_UI::post_engine ()
638 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
640 #ifdef AUDIOUNIT_SUPPORT
642 if (AUPluginInfo::au_get_crashlog(au_msg)) {
643 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
644 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
645 info << au_msg << endmsg;
649 ARDOUR::init_post_engine ();
651 /* connect to important signals */
653 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
654 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
655 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
656 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
657 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
659 if (setup_windows ()) {
660 throw failed_constructor ();
663 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
664 XMLNode* n = Config->extra_xml (X_("UI"));
666 _status_bar_visibility.set_state (*n);
669 check_memory_locking();
671 /* this is the first point at which all the possible actions are
672 * available, because some of the available actions are dependent on
673 * aspects of the engine/backend.
676 if (ARDOUR_COMMAND_LINE::show_key_actions) {
679 vector<string> paths;
680 vector<string> labels;
681 vector<string> tooltips;
683 vector<Glib::RefPtr<Gtk::Action> > actions;
685 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
687 vector<string>::iterator k;
688 vector<string>::iterator p;
690 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
695 cout << *p << " => " << *k << endl;
699 halt_connection.disconnect ();
700 AudioEngine::instance()->stop ();
704 /* this being a GUI and all, we want peakfiles */
706 AudioFileSource::set_build_peakfiles (true);
707 AudioFileSource::set_build_missing_peakfiles (true);
709 /* set default clock modes */
711 primary_clock->set_mode (AudioClock::Timecode);
712 secondary_clock->set_mode (AudioClock::BBT);
714 /* start the time-of-day-clock */
717 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
718 update_wall_clock ();
719 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
724 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
725 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
726 Config->map_parameters (pc);
728 UIConfiguration::instance().map_parameters (pc);
732 ARDOUR_UI::~ARDOUR_UI ()
734 UIConfiguration::instance().save_state();
738 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
739 // don't bother at 'real' exit. the OS cleans up for us.
740 delete big_clock; big_clock = 0;
741 delete primary_clock; primary_clock = 0;
742 delete secondary_clock; secondary_clock = 0;
743 delete _process_thread; _process_thread = 0;
744 delete time_info_box; time_info_box = 0;
745 delete meterbridge; meterbridge = 0;
746 delete luawindow; luawindow = 0;
747 delete editor; editor = 0;
748 delete mixer; mixer = 0;
750 delete gui_object_state; gui_object_state = 0;
751 delete main_window_visibility;
752 FastMeter::flush_pattern_cache ();
753 PixFader::flush_pattern_cache ();
757 /* Small trick to flush main-thread event pool.
758 * Other thread-pools are destroyed at pthread_exit(),
759 * but tmain thread termination is too late to trigger Pool::~Pool()
761 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
762 delete ev->event_pool();
767 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
769 if (Splash::instance()) {
770 Splash::instance()->pop_back_for (win);
775 ARDOUR_UI::configure_timeout ()
777 if (last_configure_time == 0) {
778 /* no configure events yet */
782 /* force a gap of 0.5 seconds since the last configure event
785 if (get_microseconds() - last_configure_time < 500000) {
788 have_configure_timeout = false;
789 save_ardour_state ();
795 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
797 if (have_configure_timeout) {
798 last_configure_time = get_microseconds();
800 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
801 have_configure_timeout = true;
808 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
810 XMLProperty const * prop;
812 if ((prop = node.property ("roll")) != 0) {
813 roll_controllable->set_id (prop->value());
815 if ((prop = node.property ("stop")) != 0) {
816 stop_controllable->set_id (prop->value());
818 if ((prop = node.property ("goto-start")) != 0) {
819 goto_start_controllable->set_id (prop->value());
821 if ((prop = node.property ("goto-end")) != 0) {
822 goto_end_controllable->set_id (prop->value());
824 if ((prop = node.property ("auto-loop")) != 0) {
825 auto_loop_controllable->set_id (prop->value());
827 if ((prop = node.property ("play-selection")) != 0) {
828 play_selection_controllable->set_id (prop->value());
830 if ((prop = node.property ("rec")) != 0) {
831 rec_controllable->set_id (prop->value());
833 if ((prop = node.property ("shuttle")) != 0) {
834 shuttle_box.controllable()->set_id (prop->value());
839 ARDOUR_UI::get_transport_controllable_state ()
841 XMLNode* node = new XMLNode(X_("TransportControllables"));
844 roll_controllable->id().print (buf, sizeof (buf));
845 node->add_property (X_("roll"), buf);
846 stop_controllable->id().print (buf, sizeof (buf));
847 node->add_property (X_("stop"), buf);
848 goto_start_controllable->id().print (buf, sizeof (buf));
849 node->add_property (X_("goto_start"), buf);
850 goto_end_controllable->id().print (buf, sizeof (buf));
851 node->add_property (X_("goto_end"), buf);
852 auto_loop_controllable->id().print (buf, sizeof (buf));
853 node->add_property (X_("auto_loop"), buf);
854 play_selection_controllable->id().print (buf, sizeof (buf));
855 node->add_property (X_("play_selection"), buf);
856 rec_controllable->id().print (buf, sizeof (buf));
857 node->add_property (X_("rec"), buf);
858 shuttle_box.controllable()->id().print (buf, sizeof (buf));
859 node->add_property (X_("shuttle"), buf);
865 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
868 _session->save_state (snapshot_name);
873 ARDOUR_UI::autosave_session ()
875 if (g_main_depth() > 1) {
876 /* inside a recursive main loop,
877 give up because we may not be able to
883 if (!Config->get_periodic_safety_backups()) {
888 _session->maybe_write_autosave();
895 ARDOUR_UI::session_dirty_changed ()
902 ARDOUR_UI::update_autosave ()
904 if (_session && _session->dirty()) {
905 if (_autosave_connection.connected()) {
906 _autosave_connection.disconnect();
909 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
910 Config->get_periodic_safety_backup_interval() * 1000);
913 if (_autosave_connection.connected()) {
914 _autosave_connection.disconnect();
920 ARDOUR_UI::check_announcements ()
923 string _annc_filename;
926 _annc_filename = PROGRAM_NAME "_announcements_osx_";
927 #elif defined PLATFORM_WINDOWS
928 _annc_filename = PROGRAM_NAME "_announcements_windows_";
930 _annc_filename = PROGRAM_NAME "_announcements_linux_";
932 _annc_filename.append (VERSIONSTRING);
934 _announce_string = "";
936 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
937 FILE* fin = g_fopen (path.c_str(), "rb");
939 while (!feof (fin)) {
942 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
945 _announce_string.append (tmp, len);
950 pingback (VERSIONSTRING, path);
955 _hide_splash (gpointer arg)
957 ((ARDOUR_UI*)arg)->hide_splash();
962 ARDOUR_UI::starting ()
964 Application* app = Application::instance ();
966 bool brand_new_user = ArdourStartup::required ();
968 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
969 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
971 if (ARDOUR_COMMAND_LINE::check_announcements) {
972 check_announcements ();
977 /* we need to create this early because it may need to set the
978 * audio backend end up.
982 audio_midi_setup.get (true);
984 std::cerr << "audio-midi engine setup failed."<< std::endl;
988 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
989 nsm = new NSM_Client;
990 if (!nsm->init (nsm_url)) {
991 /* the ardour executable may have different names:
993 * waf's obj.target for distro versions: eg ardour4, ardourvst4
994 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
995 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
997 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
999 const char *process_name = g_getenv ("ARDOUR_SELF");
1000 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1003 // wait for announce reply from nsm server
1004 for ( i = 0; i < 5000; ++i) {
1008 if (nsm->is_active()) {
1013 error << _("NSM server did not announce itself") << endmsg;
1016 // wait for open command from nsm server
1017 for ( i = 0; i < 5000; ++i) {
1019 Glib::usleep (1000);
1020 if (nsm->client_id ()) {
1026 error << _("NSM: no client ID provided") << endmsg;
1030 if (_session && nsm) {
1031 _session->set_nsm_state( nsm->is_active() );
1033 error << _("NSM: no session created") << endmsg;
1037 // nsm requires these actions disabled
1038 vector<string> action_names;
1039 action_names.push_back("SaveAs");
1040 action_names.push_back("Rename");
1041 action_names.push_back("New");
1042 action_names.push_back("Open");
1043 action_names.push_back("Recent");
1044 action_names.push_back("Close");
1046 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1047 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1049 act->set_sensitive (false);
1056 error << _("NSM: initialization failed") << endmsg;
1062 if (brand_new_user) {
1063 _initial_verbose_plugin_scan = true;
1068 _initial_verbose_plugin_scan = false;
1069 switch (s.response ()) {
1070 case Gtk::RESPONSE_OK:
1077 // TODO: maybe IFF brand_new_user
1078 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1079 std::string dspd (Config->get_default_session_parent_dir());
1080 Searchpath ds (ARDOUR::ardour_data_search_path());
1081 ds.add_subdirectory_to_paths ("sessions");
1082 vector<string> demos;
1083 find_files_matching_pattern (demos, ds, "*.tar.xz");
1085 ARDOUR::RecentSessions rs;
1086 ARDOUR::read_recent_sessions (rs);
1088 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1089 /* "demo-session" must be inside "demo-session.tar.xz"
1092 std::string name = basename_nosuffix (basename_nosuffix (*i));
1093 std::string path = Glib::build_filename (dspd, name);
1094 /* skip if session-dir already exists */
1095 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1098 /* skip sessions that are already in 'recent'.
1099 * eg. a new user changed <session-default-dir> shorly after installation
1101 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1102 if ((*r).first == name) {
1107 PBD::FileArchive ar (*i);
1108 if (0 == ar.inflate (dspd)) {
1109 store_recent_sessions (name, path);
1110 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1116 #ifdef NO_PLUGIN_STATE
1118 ARDOUR::RecentSessions rs;
1119 ARDOUR::read_recent_sessions (rs);
1121 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1123 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1125 /* already used Ardour, have sessions ... warn about plugin state */
1127 ArdourDialog d (_("Free/Demo Version Warning"), true);
1129 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1130 CheckButton c (_("Don't warn me about this again"));
1132 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1133 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1134 _("It will not restore OR save any plugin settings"),
1135 _("If you load an existing session with plugin settings\n"
1136 "they will not be used and will be lost."),
1137 _("To get full access to updates without this limitation\n"
1138 "consider becoming a subscriber for a low cost every month.")));
1139 l.set_justify (JUSTIFY_CENTER);
1141 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1143 d.get_vbox()->pack_start (l, true, true);
1144 d.get_vbox()->pack_start (b, false, false, 12);
1145 d.get_vbox()->pack_start (c, false, false, 12);
1147 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1148 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1152 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1154 if (d.run () != RESPONSE_OK) {
1160 /* go get a session */
1162 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1164 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1165 std::cerr << "Cannot get session parameters."<< std::endl;
1172 WM::Manager::instance().show_visible ();
1174 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1175 * editor window, and we may want stuff to be hidden.
1177 _status_bar_visibility.update ();
1179 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1181 if (splash && splash->is_visible()) {
1182 // in 1 second, hide the splash screen
1183 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1186 /* all other dialogs are created conditionally */
1192 ARDOUR_UI::check_memory_locking ()
1194 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1195 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1199 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1201 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1203 struct rlimit limits;
1205 long pages, page_size;
1207 size_t pages_len=sizeof(pages);
1208 if ((page_size = getpagesize()) < 0 ||
1209 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1211 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1216 ram = (int64_t) pages * (int64_t) page_size;
1219 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1223 if (limits.rlim_cur != RLIM_INFINITY) {
1225 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1229 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1230 "This might cause %1 to run out of memory before your system "
1231 "runs out of memory. \n\n"
1232 "You can view the memory limit with 'ulimit -l', "
1233 "and it is normally controlled by %2"),
1236 X_("/etc/login.conf")
1238 X_(" /etc/security/limits.conf")
1242 msg.set_default_response (RESPONSE_OK);
1244 VBox* vbox = msg.get_vbox();
1246 CheckButton cb (_("Do not show this window again"));
1247 hbox.pack_start (cb, true, false);
1248 vbox->pack_start (hbox);
1253 pop_back_splash (msg);
1257 if (cb.get_active()) {
1258 XMLNode node (X_("no-memory-warning"));
1259 Config->add_instant_xml (node);
1264 #endif // !__APPLE__
1269 ARDOUR_UI::queue_finish ()
1271 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1275 ARDOUR_UI::idle_finish ()
1278 return false; /* do not call again */
1285 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1287 if (_session->dirty()) {
1288 vector<string> actions;
1289 actions.push_back (_("Don't quit"));
1290 actions.push_back (_("Just quit"));
1291 actions.push_back (_("Save and quit"));
1292 switch (ask_about_saving_session(actions)) {
1297 /* use the default name */
1298 if (save_state_canfail ("")) {
1299 /* failed - don't quit */
1300 MessageDialog msg (_main_window,
1301 string_compose (_("\
1302 %1 was unable to save your session.\n\n\
1303 If you still wish to quit, please use the\n\n\
1304 \"Just quit\" option."), PROGRAM_NAME));
1305 pop_back_splash(msg);
1315 second_connection.disconnect ();
1316 point_one_second_connection.disconnect ();
1317 point_zero_something_second_connection.disconnect();
1318 fps_connection.disconnect();
1321 delete ARDOUR_UI::instance()->video_timeline;
1322 ARDOUR_UI::instance()->video_timeline = NULL;
1323 stop_video_server();
1325 /* Save state before deleting the session, as that causes some
1326 windows to be destroyed before their visible state can be
1329 save_ardour_state ();
1331 if (key_editor.get (false)) {
1332 key_editor->disconnect ();
1335 close_all_dialogs ();
1338 _session->set_clean ();
1339 _session->remove_pending_capture_state ();
1344 halt_connection.disconnect ();
1345 AudioEngine::instance()->stop ();
1346 #ifdef WINDOWS_VST_SUPPORT
1347 fst_stop_threading();
1353 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1355 ArdourDialog window (_("Unsaved Session"));
1356 Gtk::HBox dhbox; // the hbox for the image and text
1357 Gtk::Label prompt_label;
1358 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1362 assert (actions.size() >= 3);
1364 window.add_button (actions[0], RESPONSE_REJECT);
1365 window.add_button (actions[1], RESPONSE_APPLY);
1366 window.add_button (actions[2], RESPONSE_ACCEPT);
1368 window.set_default_response (RESPONSE_ACCEPT);
1370 Gtk::Button noquit_button (msg);
1371 noquit_button.set_name ("EditorGTKButton");
1375 if (_session->snap_name() == _session->name()) {
1376 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1377 _session->snap_name());
1379 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1380 _session->snap_name());
1383 prompt_label.set_text (prompt);
1384 prompt_label.set_name (X_("PrompterLabel"));
1385 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1387 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1388 dhbox.set_homogeneous (false);
1389 dhbox.pack_start (*dimage, false, false, 5);
1390 dhbox.pack_start (prompt_label, true, false, 5);
1391 window.get_vbox()->pack_start (dhbox);
1393 window.set_name (_("Prompter"));
1394 window.set_modal (true);
1395 window.set_resizable (false);
1398 prompt_label.show();
1403 ResponseType r = (ResponseType) window.run();
1408 case RESPONSE_ACCEPT: // save and get out of here
1410 case RESPONSE_APPLY: // get out of here
1421 ARDOUR_UI::every_second ()
1424 update_xrun_count ();
1425 update_buffer_load ();
1426 update_disk_space ();
1427 update_timecode_format ();
1428 update_peak_thread_work ();
1430 if (nsm && nsm->is_active ()) {
1433 if (!_was_dirty && _session->dirty ()) {
1437 else if (_was_dirty && !_session->dirty ()){
1445 ARDOUR_UI::every_point_one_seconds ()
1447 // TODO get rid of this..
1448 // ShuttleControl is updated directly via TransportStateChange signal
1452 ARDOUR_UI::every_point_zero_something_seconds ()
1454 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1456 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1457 float mpeak = editor_meter->update_meters();
1458 if (mpeak > editor_meter_max_peak) {
1459 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1460 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1467 ARDOUR_UI::set_fps_timeout_connection ()
1469 unsigned int interval = 40;
1470 if (!_session) return;
1471 if (_session->timecode_frames_per_second() != 0) {
1472 /* ideally we'll use a select() to sleep and not accumulate
1473 * idle time to provide a regular periodic signal.
1474 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1475 * However, that'll require a dedicated thread and cross-thread
1476 * signals to the GUI Thread..
1478 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1479 * _session->frame_rate() / _session->nominal_frame_rate()
1480 / _session->timecode_frames_per_second()
1482 #ifdef PLATFORM_WINDOWS
1483 // the smallest windows scheduler time-slice is ~15ms.
1484 // periodic GUI timeouts shorter than that will cause
1485 // WaitForSingleObject to spinlock (100% of one CPU Core)
1486 // and gtk never enters idle mode.
1487 // also changing timeBeginPeriod(1) does not affect that in
1488 // any beneficial way, so we just limit the max rate for now.
1489 interval = std::max(30u, interval); // at most ~33Hz.
1491 interval = std::max(8u, interval); // at most 120Hz.
1494 fps_connection.disconnect();
1495 Timers::set_fps_interval (interval);
1499 ARDOUR_UI::update_sample_rate (framecnt_t)
1503 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1505 if (!AudioEngine::instance()->connected()) {
1507 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1511 framecnt_t rate = AudioEngine::instance()->sample_rate();
1514 /* no sample rate available */
1515 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1518 if (fmod (rate, 1000.0) != 0.0) {
1519 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1520 (float) rate / 1000.0f,
1521 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1523 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1525 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1529 sample_rate_label.set_markup (buf);
1533 ARDOUR_UI::update_format ()
1536 format_label.set_text ("");
1541 s << _("File:") << X_(" <span foreground=\"green\">");
1543 switch (_session->config.get_native_file_header_format ()) {
1575 switch (_session->config.get_native_file_data_format ()) {
1589 format_label.set_markup (s.str ());
1593 ARDOUR_UI::update_xrun_count ()
1597 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1598 should also be changed.
1602 const unsigned int x = _session->get_xrun_count ();
1604 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1606 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1609 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1611 xrun_label.set_markup (buf);
1612 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1616 ARDOUR_UI::update_cpu_load ()
1620 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1621 should also be changed.
1624 double const c = AudioEngine::instance()->get_dsp_load ();
1625 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1626 cpu_load_label.set_markup (buf);
1630 ARDOUR_UI::update_peak_thread_work ()
1633 const int c = SourceFactory::peak_work_queue_length ();
1635 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1636 peak_thread_work_label.set_markup (buf);
1638 peak_thread_work_label.set_markup (X_(""));
1643 ARDOUR_UI::update_buffer_load ()
1647 uint32_t const playback = _session ? _session->playback_load () : 100;
1648 uint32_t const capture = _session ? _session->capture_load () : 100;
1650 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1651 should also be changed.
1657 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1658 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1659 playback <= 5 ? X_("red") : X_("green"),
1661 capture <= 5 ? X_("red") : X_("green"),
1665 buffer_load_label.set_markup (buf);
1667 buffer_load_label.set_text ("");
1672 ARDOUR_UI::count_recenabled_streams (Route& route)
1674 Track* track = dynamic_cast<Track*>(&route);
1675 if (track && track->rec_enable_control()->get_value()) {
1676 rec_enabled_streams += track->n_inputs().n_total();
1681 ARDOUR_UI::update_disk_space()
1683 if (_session == 0) {
1687 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1689 framecnt_t fr = _session->frame_rate();
1692 /* skip update - no SR available */
1697 /* Available space is unknown */
1698 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1699 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1700 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1702 rec_enabled_streams = 0;
1703 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1705 framecnt_t frames = opt_frames.get_value_or (0);
1707 if (rec_enabled_streams) {
1708 frames /= rec_enabled_streams;
1715 hrs = frames / (fr * 3600);
1718 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1720 frames -= hrs * fr * 3600;
1721 mins = frames / (fr * 60);
1722 frames -= mins * fr * 60;
1725 bool const low = (hrs == 0 && mins <= 30);
1729 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1730 low ? X_("red") : X_("green"),
1736 disk_space_label.set_markup (buf);
1740 ARDOUR_UI::update_timecode_format ()
1746 TimecodeSlave* tcslave;
1747 SyncSource sync_src = Config->get_sync_source();
1749 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1750 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1755 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1756 matching ? X_("green") : X_("red"),
1757 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1759 snprintf (buf, sizeof (buf), "TC: n/a");
1762 timecode_format_label.set_markup (buf);
1766 ARDOUR_UI::update_wall_clock ()
1770 static int last_min = -1;
1773 tm_now = localtime (&now);
1774 if (last_min != tm_now->tm_min) {
1776 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1777 wall_clock_label.set_text (buf);
1778 last_min = tm_now->tm_min;
1785 ARDOUR_UI::open_recent_session ()
1787 bool can_return = (_session != 0);
1789 SessionDialog recent_session_dialog;
1793 ResponseType r = (ResponseType) recent_session_dialog.run ();
1796 case RESPONSE_ACCEPT:
1800 recent_session_dialog.hide();
1807 recent_session_dialog.hide();
1811 std::string path = recent_session_dialog.session_folder();
1812 std::string state = recent_session_dialog.session_name (should_be_new);
1814 if (should_be_new == true) {
1818 _session_is_new = false;
1820 if (load_session (path, state) == 0) {
1826 if (splash && splash->is_visible()) {
1827 // in 1 second, hide the splash screen
1828 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1833 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1835 if (!AudioEngine::instance()->connected()) {
1836 MessageDialog msg (parent, string_compose (
1837 _("%1 is not connected to any audio backend.\n"
1838 "You cannot open or close sessions in this condition"),
1840 pop_back_splash (msg);
1848 ARDOUR_UI::open_session ()
1850 if (!check_audioengine (_main_window)) {
1854 /* ardour sessions are folders */
1855 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1856 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1857 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1858 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1861 string session_parent_dir = Glib::path_get_dirname(_session->path());
1862 open_session_selector.set_current_folder(session_parent_dir);
1864 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1867 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1869 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1870 string default_session_folder = Config->get_default_session_parent_dir();
1871 open_session_selector.add_shortcut_folder (default_session_folder);
1873 catch (Glib::Error & e) {
1874 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1877 FileFilter session_filter;
1878 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1879 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1880 open_session_selector.add_filter (session_filter);
1881 open_session_selector.set_filter (session_filter);
1883 int response = open_session_selector.run();
1884 open_session_selector.hide ();
1886 if (response == Gtk::RESPONSE_CANCEL) {
1890 string session_path = open_session_selector.get_filename();
1894 if (session_path.length() > 0) {
1895 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1896 _session_is_new = isnew;
1897 load_session (path, name);
1903 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1909 _session->vca_manager().create_vca (n, name_template);
1913 ARDOUR_UI::session_add_mixed_track (
1914 const ChanCount& input,
1915 const ChanCount& output,
1916 RouteGroup* route_group,
1918 const string& name_template,
1920 PluginInfoPtr instrument,
1921 Plugin::PresetRecord* pset,
1922 ARDOUR::PresentationInfo::order_t order)
1924 list<boost::shared_ptr<MidiTrack> > tracks;
1926 if (_session == 0) {
1927 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1932 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1934 if (tracks.size() != how_many) {
1935 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1940 display_insufficient_ports_message ();
1945 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1946 (*i)->set_strict_io (true);
1952 ARDOUR_UI::session_add_midi_bus (
1953 RouteGroup* route_group,
1955 const string& name_template,
1957 PluginInfoPtr instrument,
1958 Plugin::PresetRecord* pset,
1959 ARDOUR::PresentationInfo::order_t order)
1963 if (_session == 0) {
1964 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1970 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1971 if (routes.size() != how_many) {
1972 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1977 display_insufficient_ports_message ();
1982 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1983 (*i)->set_strict_io (true);
1989 ARDOUR_UI::session_add_midi_route (
1991 RouteGroup* route_group,
1993 const string& name_template,
1995 PluginInfoPtr instrument,
1996 Plugin::PresetRecord* pset,
1997 ARDOUR::PresentationInfo::order_t order)
1999 ChanCount one_midi_channel;
2000 one_midi_channel.set (DataType::MIDI, 1);
2003 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2005 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2010 ARDOUR_UI::session_add_audio_route (
2012 int32_t input_channels,
2013 int32_t output_channels,
2014 ARDOUR::TrackMode mode,
2015 RouteGroup* route_group,
2017 string const & name_template,
2019 ARDOUR::PresentationInfo::order_t order)
2021 list<boost::shared_ptr<AudioTrack> > tracks;
2024 if (_session == 0) {
2025 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2031 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2033 if (tracks.size() != how_many) {
2034 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2040 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2042 if (routes.size() != how_many) {
2043 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2050 display_insufficient_ports_message ();
2055 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2056 (*i)->set_strict_io (true);
2058 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2059 (*i)->set_strict_io (true);
2065 ARDOUR_UI::display_insufficient_ports_message ()
2067 MessageDialog msg (_main_window,
2068 string_compose (_("There are insufficient ports available\n\
2069 to create a new track or bus.\n\
2070 You should save %1, exit and\n\
2071 restart with more ports."), PROGRAM_NAME));
2072 pop_back_splash (msg);
2077 ARDOUR_UI::transport_goto_start ()
2080 _session->goto_start();
2082 /* force displayed area in editor to start no matter
2083 what "follow playhead" setting is.
2087 editor->center_screen (_session->current_start_frame ());
2093 ARDOUR_UI::transport_goto_zero ()
2096 _session->request_locate (0);
2098 /* force displayed area in editor to start no matter
2099 what "follow playhead" setting is.
2103 editor->reset_x_origin (0);
2109 ARDOUR_UI::transport_goto_wallclock ()
2111 if (_session && editor) {
2118 localtime_r (&now, &tmnow);
2120 framecnt_t frame_rate = _session->frame_rate();
2122 if (frame_rate == 0) {
2123 /* no frame rate available */
2127 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2128 frames += tmnow.tm_min * (60 * frame_rate);
2129 frames += tmnow.tm_sec * frame_rate;
2131 _session->request_locate (frames, _session->transport_rolling ());
2133 /* force displayed area in editor to start no matter
2134 what "follow playhead" setting is.
2138 editor->center_screen (frames);
2144 ARDOUR_UI::transport_goto_end ()
2147 framepos_t const frame = _session->current_end_frame();
2148 _session->request_locate (frame);
2150 /* force displayed area in editor to start no matter
2151 what "follow playhead" setting is.
2155 editor->center_screen (frame);
2161 ARDOUR_UI::transport_stop ()
2167 if (_session->is_auditioning()) {
2168 _session->cancel_audition ();
2172 _session->request_stop (false, true);
2175 /** Check if any tracks are record enabled. If none are, record enable all of them.
2176 * @return true if track record-enabled status was changed, false otherwise.
2179 ARDOUR_UI::trx_record_enable_all_tracks ()
2185 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2186 bool none_record_enabled = true;
2188 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2189 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2192 if (t->rec_enable_control()->get_value()) {
2193 none_record_enabled = false;
2198 if (none_record_enabled) {
2199 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2202 return none_record_enabled;
2206 ARDOUR_UI::transport_record (bool roll)
2209 switch (_session->record_status()) {
2210 case Session::Disabled:
2211 if (_session->ntracks() == 0) {
2212 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."));
2216 if (Profile->get_trx()) {
2217 roll = trx_record_enable_all_tracks ();
2219 _session->maybe_enable_record ();
2224 case Session::Recording:
2226 _session->request_stop();
2228 _session->disable_record (false, true);
2232 case Session::Enabled:
2233 _session->disable_record (false, true);
2239 ARDOUR_UI::transport_roll ()
2245 if (_session->is_auditioning()) {
2250 if (_session->config.get_external_sync()) {
2251 switch (Config->get_sync_source()) {
2255 /* transport controlled by the master */
2261 bool rolling = _session->transport_rolling();
2263 if (_session->get_play_loop()) {
2265 /* If loop playback is not a mode, then we should cancel
2266 it when this action is requested. If it is a mode
2267 we just leave it in place.
2270 if (!Config->get_loop_is_mode()) {
2271 /* XXX it is not possible to just leave seamless loop and keep
2272 playing at present (nov 4th 2009)
2274 if (!Config->get_seamless_loop()) {
2275 /* stop loop playback and stop rolling */
2276 _session->request_play_loop (false, true);
2277 } else if (rolling) {
2278 /* stop loop playback but keep rolling */
2279 _session->request_play_loop (false, false);
2283 } else if (_session->get_play_range () ) {
2284 /* stop playing a range if we currently are */
2285 _session->request_play_range (0, true);
2289 _session->request_transport_speed (1.0f);
2294 ARDOUR_UI::get_smart_mode() const
2296 return ( editor->get_smart_mode() );
2301 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2307 if (_session->is_auditioning()) {
2308 _session->cancel_audition ();
2312 if (_session->config.get_external_sync()) {
2313 switch (Config->get_sync_source()) {
2317 /* transport controlled by the master */
2322 bool rolling = _session->transport_rolling();
2323 bool affect_transport = true;
2325 if (rolling && roll_out_of_bounded_mode) {
2326 /* drop out of loop/range playback but leave transport rolling */
2327 if (_session->get_play_loop()) {
2328 if (_session->actively_recording()) {
2330 /* just stop using the loop, then actually stop
2333 _session->request_play_loop (false, affect_transport);
2336 if (Config->get_seamless_loop()) {
2337 /* the disk buffers contain copies of the loop - we can't
2338 just keep playing, so stop the transport. the user
2339 can restart as they wish.
2341 affect_transport = true;
2343 /* disk buffers are normal, so we can keep playing */
2344 affect_transport = false;
2346 _session->request_play_loop (false, affect_transport);
2348 } else if (_session->get_play_range ()) {
2349 affect_transport = false;
2350 _session->request_play_range (0, true);
2354 if (affect_transport) {
2356 _session->request_stop (with_abort, true);
2358 } else if (!with_abort) { /* with_abort == true means the
2359 * command was intended to stop
2360 * transport, not start.
2363 /* the only external sync condition we can be in here
2364 * would be Engine (JACK) sync, in which case we still
2368 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
2369 _session->request_play_range (&editor->get_selection().time, true);
2370 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2372 _session->request_transport_speed (1.0f);
2378 ARDOUR_UI::toggle_session_auto_loop ()
2384 Location * looploc = _session->locations()->auto_loop_location();
2390 if (_session->get_play_loop()) {
2392 /* looping enabled, our job is to disable it */
2394 _session->request_play_loop (false);
2398 /* looping not enabled, our job is to enable it.
2400 loop-is-NOT-mode: this action always starts the transport rolling.
2401 loop-IS-mode: this action simply sets the loop play mechanism, but
2402 does not start transport.
2404 if (Config->get_loop_is_mode()) {
2405 _session->request_play_loop (true, false);
2407 _session->request_play_loop (true, true);
2411 //show the loop markers
2412 looploc->set_hidden (false, this);
2416 ARDOUR_UI::transport_play_selection ()
2422 editor->play_selection ();
2426 ARDOUR_UI::transport_play_preroll ()
2431 editor->play_with_preroll ();
2435 ARDOUR_UI::transport_rewind (int option)
2437 float current_transport_speed;
2440 current_transport_speed = _session->transport_speed();
2442 if (current_transport_speed >= 0.0f) {
2445 _session->request_transport_speed (-1.0f);
2448 _session->request_transport_speed (-4.0f);
2451 _session->request_transport_speed (-0.5f);
2456 _session->request_transport_speed (current_transport_speed * 1.5f);
2462 ARDOUR_UI::transport_forward (int option)
2468 float current_transport_speed = _session->transport_speed();
2470 if (current_transport_speed <= 0.0f) {
2473 _session->request_transport_speed (1.0f);
2476 _session->request_transport_speed (4.0f);
2479 _session->request_transport_speed (0.5f);
2484 _session->request_transport_speed (current_transport_speed * 1.5f);
2489 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2495 boost::shared_ptr<Route> r;
2497 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2499 boost::shared_ptr<Track> t;
2501 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2502 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2508 ARDOUR_UI::map_transport_state ()
2511 auto_loop_button.unset_active_state ();
2512 play_selection_button.unset_active_state ();
2513 roll_button.unset_active_state ();
2514 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2515 layered_button.set_sensitive (false);
2519 shuttle_box.map_transport_state ();
2521 float sp = _session->transport_speed();
2527 if (_session->get_play_range()) {
2529 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2530 roll_button.unset_active_state ();
2531 auto_loop_button.unset_active_state ();
2533 } else if (_session->get_play_loop ()) {
2535 auto_loop_button.set_active (true);
2536 play_selection_button.set_active (false);
2537 if (Config->get_loop_is_mode()) {
2538 roll_button.set_active (true);
2540 roll_button.set_active (false);
2545 roll_button.set_active (true);
2546 play_selection_button.set_active (false);
2547 auto_loop_button.set_active (false);
2550 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2551 /* light up both roll and play-selection if they are joined */
2552 roll_button.set_active (true);
2553 play_selection_button.set_active (true);
2555 layered_button.set_sensitive (!_session->actively_recording ());
2557 stop_button.set_active (false);
2561 layered_button.set_sensitive (true);
2562 stop_button.set_active (true);
2563 roll_button.set_active (false);
2564 play_selection_button.set_active (false);
2565 if (Config->get_loop_is_mode ()) {
2566 auto_loop_button.set_active (_session->get_play_loop());
2568 auto_loop_button.set_active (false);
2570 update_disk_space ();
2575 ARDOUR_UI::blink_handler (bool blink_on)
2577 transport_rec_enable_blink (blink_on);
2578 solo_blink (blink_on);
2579 sync_blink (blink_on);
2580 audition_blink (blink_on);
2581 feedback_blink (blink_on);
2582 error_blink (blink_on);
2586 ARDOUR_UI::update_clocks ()
2588 if (!_session) return;
2590 if (editor && !editor->dragging_playhead()) {
2591 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2596 ARDOUR_UI::start_clocking ()
2598 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2599 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2601 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2606 ARDOUR_UI::stop_clocking ()
2608 clock_signal_connection.disconnect ();
2612 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2616 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2618 label->set_text (buf);
2619 bar->set_fraction (fraction);
2621 /* process events, redraws, etc. */
2623 while (gtk_events_pending()) {
2624 gtk_main_iteration ();
2627 return true; /* continue with save-as */
2631 ARDOUR_UI::save_session_as ()
2637 if (!save_as_dialog) {
2638 save_as_dialog = new SaveAsDialog;
2641 save_as_dialog->set_name (_session->name());
2643 int response = save_as_dialog->run ();
2645 save_as_dialog->hide ();
2648 case Gtk::RESPONSE_OK:
2657 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2658 sa.new_name = save_as_dialog->new_name ();
2659 sa.switch_to = save_as_dialog->switch_to();
2660 sa.copy_media = save_as_dialog->copy_media();
2661 sa.copy_external = save_as_dialog->copy_external();
2662 sa.include_media = save_as_dialog->include_media ();
2664 /* Only bother with a progress dialog if we're going to copy
2665 media into the save-as target. Without that choice, this
2666 will be very fast because we're only talking about a few kB's to
2667 perhaps a couple of MB's of data.
2670 ArdourDialog progress_dialog (_("Save As"), true);
2672 if (sa.include_media && sa.copy_media) {
2675 Gtk::ProgressBar progress_bar;
2677 progress_dialog.get_vbox()->pack_start (label);
2678 progress_dialog.get_vbox()->pack_start (progress_bar);
2680 progress_bar.show ();
2682 /* this signal will be emitted from within this, the calling thread,
2683 * after every file is copied. It provides information on percentage
2684 * complete (in terms of total data to copy), the number of files
2685 * copied so far, and the total number to copy.
2690 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2692 progress_dialog.show_all ();
2693 progress_dialog.present ();
2696 if (_session->save_as (sa)) {
2698 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2702 if (!sa.include_media) {
2703 unload_session (false);
2704 load_session (sa.final_session_folder_name, sa.new_name);
2709 ARDOUR_UI::archive_session ()
2717 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2719 SessionArchiveDialog sad;
2720 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2721 int response = sad.run ();
2723 if (response != Gtk::RESPONSE_OK) {
2728 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2729 MessageDialog msg (_("Session Archiving failed."));
2735 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2739 struct tm local_time;
2742 localtime_r (&n, &local_time);
2743 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2745 save_state (timebuf, switch_to_it);
2750 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2754 prompter.get_result (snapname);
2756 bool do_save = (snapname.length() != 0);
2759 char illegal = Session::session_name_is_legal(snapname);
2761 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2762 "snapshot names may not contain a '%1' character"), illegal));
2768 vector<std::string> p;
2769 get_state_files_in_directory (_session->session_directory().root_path(), p);
2770 vector<string> n = get_file_names_no_extension (p);
2772 if (find (n.begin(), n.end(), snapname) != n.end()) {
2774 do_save = overwrite_file_dialog (prompter,
2775 _("Confirm Snapshot Overwrite"),
2776 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2780 save_state (snapname, switch_to_it);
2790 /** Ask the user for the name of a new snapshot and then take it.
2794 ARDOUR_UI::snapshot_session (bool switch_to_it)
2796 ArdourPrompter prompter (true);
2798 prompter.set_name ("Prompter");
2799 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2801 prompter.set_title (_("Snapshot and switch"));
2802 prompter.set_prompt (_("New session name"));
2804 prompter.set_title (_("Take Snapshot"));
2805 prompter.set_prompt (_("Name of new snapshot"));
2809 prompter.set_initial_text (_session->snap_name());
2811 Glib::DateTime tm (g_date_time_new_now_local ());
2812 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2815 bool finished = false;
2817 switch (prompter.run()) {
2818 case RESPONSE_ACCEPT:
2820 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2831 /** Ask the user for a new session name and then rename the session to it.
2835 ARDOUR_UI::rename_session ()
2841 ArdourPrompter prompter (true);
2844 prompter.set_name ("Prompter");
2845 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2846 prompter.set_title (_("Rename Session"));
2847 prompter.set_prompt (_("New session name"));
2850 switch (prompter.run()) {
2851 case RESPONSE_ACCEPT:
2853 prompter.get_result (name);
2855 bool do_rename = (name.length() != 0);
2858 char illegal = Session::session_name_is_legal (name);
2861 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2862 "session names may not contain a '%1' character"), illegal));
2867 switch (_session->rename (name)) {
2869 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2870 msg.set_position (WIN_POS_MOUSE);
2878 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2879 msg.set_position (WIN_POS_MOUSE);
2895 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2897 if (!_session || _session->deletion_in_progress()) {
2901 XMLNode* node = new XMLNode (X_("UI"));
2903 WM::Manager::instance().add_state (*node);
2905 node->add_child_nocopy (gui_object_state->get_state());
2907 _session->add_extra_xml (*node);
2909 if (export_video_dialog) {
2910 _session->add_extra_xml (export_video_dialog->get_state());
2913 save_state_canfail (name, switch_to_it);
2917 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2922 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2927 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2932 ARDOUR_UI::primary_clock_value_changed ()
2935 _session->request_locate (primary_clock->current_time ());
2940 ARDOUR_UI::big_clock_value_changed ()
2943 _session->request_locate (big_clock->current_time ());
2948 ARDOUR_UI::secondary_clock_value_changed ()
2951 _session->request_locate (secondary_clock->current_time ());
2956 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2958 if (_session == 0) {
2962 if (_session->step_editing()) {
2966 Session::RecordState const r = _session->record_status ();
2967 bool const h = _session->have_rec_enabled_track ();
2969 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2971 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2973 rec_button.set_active_state (Gtkmm2ext::Off);
2975 } else if (r == Session::Recording && h) {
2976 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2978 rec_button.unset_active_state ();
2983 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2987 prompter.get_result (name);
2989 if (name.length()) {
2990 int failed = _session->save_template (name);
2992 if (failed == -2) { /* file already exists. */
2993 bool overwrite = overwrite_file_dialog (prompter,
2994 _("Confirm Template Overwrite"),
2995 _("A template already exists with that name. Do you want to overwrite it?"));
2998 _session->save_template (name, true);
3010 ARDOUR_UI::save_template ()
3012 ArdourPrompter prompter (true);
3014 if (!check_audioengine (_main_window)) {
3018 prompter.set_name (X_("Prompter"));
3019 prompter.set_title (_("Save Template"));
3020 prompter.set_prompt (_("Name for template:"));
3021 prompter.set_initial_text(_session->name() + _("-template"));
3022 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3024 bool finished = false;
3026 switch (prompter.run()) {
3027 case RESPONSE_ACCEPT:
3028 finished = process_save_template_prompter (prompter);
3039 ARDOUR_UI::edit_metadata ()
3041 SessionMetadataEditor dialog;
3042 dialog.set_session (_session);
3043 dialog.grab_focus ();
3048 ARDOUR_UI::import_metadata ()
3050 SessionMetadataImporter dialog;
3051 dialog.set_session (_session);
3056 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3058 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3060 MessageDialog msg (str,
3062 Gtk::MESSAGE_WARNING,
3063 Gtk::BUTTONS_YES_NO,
3067 msg.set_name (X_("OpenExistingDialog"));
3068 msg.set_title (_("Open Existing Session"));
3069 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3070 msg.set_position (Gtk::WIN_POS_CENTER);
3071 pop_back_splash (msg);
3073 switch (msg.run()) {
3082 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3084 BusProfile bus_profile;
3088 bus_profile.master_out_channels = 2;
3089 bus_profile.input_ac = AutoConnectPhysical;
3090 bus_profile.output_ac = AutoConnectMaster;
3091 bus_profile.requested_physical_in = 0; // use all available
3092 bus_profile.requested_physical_out = 0; // use all available
3096 /* get settings from advanced section of NSD */
3098 if (sd.create_master_bus()) {
3099 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3101 bus_profile.master_out_channels = 0;
3104 if (sd.connect_inputs()) {
3105 bus_profile.input_ac = AutoConnectPhysical;
3107 bus_profile.input_ac = AutoConnectOption (0);
3110 bus_profile.output_ac = AutoConnectOption (0);
3112 if (sd.connect_outputs ()) {
3113 if (sd.connect_outs_to_master()) {
3114 bus_profile.output_ac = AutoConnectMaster;
3115 } else if (sd.connect_outs_to_physical()) {
3116 bus_profile.output_ac = AutoConnectPhysical;
3120 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3121 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3124 if (build_session (session_path, session_name, bus_profile)) {
3132 ARDOUR_UI::load_from_application_api (const std::string& path)
3134 /* OS X El Capitan (and probably later) now somehow passes the command
3135 line arguments to an app via the openFile delegate protocol. Ardour
3136 already does its own command line processing, and having both
3137 pathways active causes crashes. So, if the command line was already
3138 set, do nothing here.
3141 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3145 ARDOUR_COMMAND_LINE::session_name = path;
3147 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3149 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3151 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3152 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3153 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3154 * -> SessionDialog is not displayed
3157 if (_session_dialog) {
3158 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3159 std::string session_path = path;
3160 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3161 session_path = Glib::path_get_dirname (session_path);
3163 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3164 _session_dialog->set_provided_session (session_name, session_path);
3165 _session_dialog->response (RESPONSE_NONE);
3166 _session_dialog->hide();
3171 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3172 /* /path/to/foo => /path/to/foo, foo */
3173 rv = load_session (path, basename_nosuffix (path));
3175 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3176 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3179 // if load_session fails -> pop up SessionDialog.
3181 ARDOUR_COMMAND_LINE::session_name = "";
3183 if (get_session_parameters (true, false)) {
3189 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3191 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3193 string session_name;
3194 string session_path;
3195 string template_name;
3197 bool likely_new = false;
3198 bool cancel_not_quit;
3200 /* deal with any existing DIRTY session now, rather than later. don't
3201 * treat a non-dirty session this way, so that it stays visible
3202 * as we bring up the new session dialog.
3205 if (_session && ARDOUR_UI::instance()->video_timeline) {
3206 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3209 /* if there is already a session, relabel the button
3210 on the SessionDialog so that we don't Quit directly
3212 cancel_not_quit = (_session != 0);
3214 if (_session && _session->dirty()) {
3215 if (unload_session (false)) {
3216 /* unload cancelled by user */
3219 ARDOUR_COMMAND_LINE::session_name = "";
3222 if (!load_template.empty()) {
3223 should_be_new = true;
3224 template_name = load_template;
3227 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3228 session_path = ARDOUR_COMMAND_LINE::session_name;
3230 if (!session_path.empty()) {
3231 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3232 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3233 /* session/snapshot file, change path to be dir */
3234 session_path = Glib::path_get_dirname (session_path);
3239 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3241 _session_dialog = &session_dialog;
3244 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3246 /* if they named a specific statefile, use it, otherwise they are
3247 just giving a session folder, and we want to use it as is
3248 to find the session.
3251 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3253 if (suffix != string::npos) {
3254 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3255 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3256 session_name = Glib::path_get_basename (session_name);
3258 session_path = ARDOUR_COMMAND_LINE::session_name;
3259 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3264 session_dialog.clear_given ();
3267 if (should_be_new || session_name.empty()) {
3268 /* need the dialog to get info from user */
3270 cerr << "run dialog\n";
3272 switch (session_dialog.run()) {
3273 case RESPONSE_ACCEPT:
3276 /* this is used for async * app->ShouldLoad(). */
3277 continue; // while loop
3280 if (quit_on_cancel) {
3281 // JE - Currently (July 2014) this section can only get reached if the
3282 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3283 // point does NOT indicate an abnormal termination). Therefore, let's
3284 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3286 pthread_cancel_all ();
3294 session_dialog.hide ();
3297 /* if we run the startup dialog again, offer more than just "new session" */
3299 should_be_new = false;
3301 session_name = session_dialog.session_name (likely_new);
3302 session_path = session_dialog.session_folder ();
3308 string::size_type suffix = session_name.find (statefile_suffix);
3310 if (suffix != string::npos) {
3311 session_name = session_name.substr (0, suffix);
3314 /* this shouldn't happen, but we catch it just in case it does */
3316 if (session_name.empty()) {
3320 if (session_dialog.use_session_template()) {
3321 template_name = session_dialog.session_template_name();
3322 _session_is_new = true;
3325 if (session_name[0] == G_DIR_SEPARATOR ||
3326 #ifdef PLATFORM_WINDOWS
3327 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3329 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3330 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3335 /* absolute path or cwd-relative path specified for session name: infer session folder
3336 from what was given.
3339 session_path = Glib::path_get_dirname (session_name);
3340 session_name = Glib::path_get_basename (session_name);
3344 session_path = session_dialog.session_folder();
3346 char illegal = Session::session_name_is_legal (session_name);
3349 MessageDialog msg (session_dialog,
3350 string_compose (_("To ensure compatibility with various systems\n"
3351 "session names may not contain a '%1' character"),
3354 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3359 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3362 if (likely_new && !nsm) {
3364 std::string existing = Glib::build_filename (session_path, session_name);
3366 if (!ask_about_loading_existing_session (existing)) {
3367 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3372 _session_is_new = false;
3377 pop_back_splash (session_dialog);
3378 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3380 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3384 char illegal = Session::session_name_is_legal(session_name);
3387 pop_back_splash (session_dialog);
3388 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3389 "session names may not contain a '%1' character"), illegal));
3391 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3395 _session_is_new = true;
3398 if (likely_new && template_name.empty()) {
3400 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3404 ret = load_session (session_path, session_name, template_name);
3407 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3411 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3412 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3416 /* clear this to avoid endless attempts to load the
3420 ARDOUR_COMMAND_LINE::session_name = "";
3424 _session_dialog = NULL;
3430 ARDOUR_UI::close_session()
3432 if (!check_audioengine (_main_window)) {
3436 if (unload_session (true)) {
3440 ARDOUR_COMMAND_LINE::session_name = "";
3442 if (get_session_parameters (true, false)) {
3445 if (splash && splash->is_visible()) {
3446 // in 1 second, hide the splash screen
3447 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3451 /** @param snap_name Snapshot name (without .ardour suffix).
3452 * @return -2 if the load failed because we are not connected to the AudioEngine.
3455 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3457 Session *new_session;
3462 unload_status = unload_session ();
3464 if (unload_status < 0) {
3466 } else if (unload_status > 0) {
3472 session_loaded = false;
3474 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3477 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3480 /* this one is special */
3482 catch (AudioEngine::PortRegistrationFailure& err) {
3484 MessageDialog msg (err.what(),
3487 Gtk::BUTTONS_CLOSE);
3489 msg.set_title (_("Port Registration Error"));
3490 msg.set_secondary_text (_("Click the Close button to try again."));
3491 msg.set_position (Gtk::WIN_POS_CENTER);
3492 pop_back_splash (msg);
3495 int response = msg.run ();
3500 case RESPONSE_CANCEL:
3507 catch (SessionException e) {
3508 MessageDialog msg (string_compose(
3509 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3510 path, snap_name, e.what()),
3515 msg.set_title (_("Loading Error"));
3516 msg.set_position (Gtk::WIN_POS_CENTER);
3517 pop_back_splash (msg);
3529 MessageDialog msg (string_compose(
3530 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3536 msg.set_title (_("Loading Error"));
3537 msg.set_position (Gtk::WIN_POS_CENTER);
3538 pop_back_splash (msg);
3550 list<string> const u = new_session->unknown_processors ();
3552 MissingPluginDialog d (_session, u);
3557 if (!new_session->writable()) {
3558 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3563 msg.set_title (_("Read-only Session"));
3564 msg.set_position (Gtk::WIN_POS_CENTER);
3565 pop_back_splash (msg);
3572 /* Now the session been created, add the transport controls */
3573 new_session->add_controllable(roll_controllable);
3574 new_session->add_controllable(stop_controllable);
3575 new_session->add_controllable(goto_start_controllable);
3576 new_session->add_controllable(goto_end_controllable);
3577 new_session->add_controllable(auto_loop_controllable);
3578 new_session->add_controllable(play_selection_controllable);
3579 new_session->add_controllable(rec_controllable);
3581 set_session (new_session);
3583 session_loaded = true;
3586 _session->set_clean ();
3589 #ifdef WINDOWS_VST_SUPPORT
3590 fst_stop_threading();
3594 Timers::TimerSuspender t;
3598 #ifdef WINDOWS_VST_SUPPORT
3599 fst_start_threading();
3608 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3610 Session *new_session;
3613 session_loaded = false;
3614 x = unload_session ();
3622 _session_is_new = true;
3625 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3628 catch (SessionException e) {
3629 cerr << "Here are the errors associated with this failed session:\n";
3631 cerr << "---------\n";
3632 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3633 msg.set_title (_("Loading Error"));
3634 msg.set_position (Gtk::WIN_POS_CENTER);
3635 pop_back_splash (msg);
3640 cerr << "Here are the errors associated with this failed session:\n";
3642 cerr << "---------\n";
3643 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3644 msg.set_title (_("Loading Error"));
3645 msg.set_position (Gtk::WIN_POS_CENTER);
3646 pop_back_splash (msg);
3651 /* Give the new session the default GUI state, if such things exist */
3654 n = Config->instant_xml (X_("Editor"));
3656 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3657 new_session->add_instant_xml (*n, false);
3659 n = Config->instant_xml (X_("Mixer"));
3661 new_session->add_instant_xml (*n, false);
3664 n = Config->instant_xml (X_("Preferences"));
3666 new_session->add_instant_xml (*n, false);
3669 /* Put the playhead at 0 and scroll fully left */
3670 n = new_session->instant_xml (X_("Editor"));
3672 n->add_property (X_("playhead"), X_("0"));
3673 n->add_property (X_("left-frame"), X_("0"));
3676 set_session (new_session);
3678 session_loaded = true;
3680 new_session->save_state(new_session->name());
3686 ARDOUR_UI::launch_chat ()
3688 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3690 dialog.set_title (_("About the Chat"));
3691 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."));
3693 switch (dialog.run()) {
3696 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3697 #elif defined PLATFORM_WINDOWS
3698 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3700 open_uri("http://webchat.freenode.net/?channels=ardour");
3709 ARDOUR_UI::launch_manual ()
3711 PBD::open_uri (Config->get_tutorial_manual_url());
3715 ARDOUR_UI::launch_reference ()
3717 PBD::open_uri (Config->get_reference_manual_url());
3721 ARDOUR_UI::launch_tracker ()
3723 PBD::open_uri ("http://tracker.ardour.org");
3727 ARDOUR_UI::launch_subscribe ()
3729 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3733 ARDOUR_UI::launch_cheat_sheet ()
3736 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3738 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3743 ARDOUR_UI::launch_website ()
3745 PBD::open_uri ("http://ardour.org");
3749 ARDOUR_UI::launch_website_dev ()
3751 PBD::open_uri ("http://ardour.org/development.html");
3755 ARDOUR_UI::launch_forums ()
3757 PBD::open_uri ("https://community.ardour.org/forums");
3761 ARDOUR_UI::launch_howto_report ()
3763 PBD::open_uri ("http://ardour.org/reporting_bugs");
3767 ARDOUR_UI::loading_message (const std::string& msg)
3769 if (ARDOUR_COMMAND_LINE::no_splash) {
3777 splash->message (msg);
3781 ARDOUR_UI::show_splash ()
3785 splash = new Splash;
3795 ARDOUR_UI::hide_splash ()
3802 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3806 removed = rep.paths.size();
3809 MessageDialog msgd (_main_window,
3810 _("No files were ready for clean-up"),
3814 msgd.set_title (_("Clean-up"));
3815 msgd.set_secondary_text (_("If this seems suprising, \n\
3816 check for any existing snapshots.\n\
3817 These may still include regions that\n\
3818 require some unused files to continue to exist."));
3824 ArdourDialog results (_("Clean-up"), true, false);
3826 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3827 CleanupResultsModelColumns() {
3831 Gtk::TreeModelColumn<std::string> visible_name;
3832 Gtk::TreeModelColumn<std::string> fullpath;
3836 CleanupResultsModelColumns results_columns;
3837 Glib::RefPtr<Gtk::ListStore> results_model;
3838 Gtk::TreeView results_display;
3840 results_model = ListStore::create (results_columns);
3841 results_display.set_model (results_model);
3842 results_display.append_column (list_title, results_columns.visible_name);
3844 results_display.set_name ("CleanupResultsList");
3845 results_display.set_headers_visible (true);
3846 results_display.set_headers_clickable (false);
3847 results_display.set_reorderable (false);
3849 Gtk::ScrolledWindow list_scroller;
3852 Gtk::HBox dhbox; // the hbox for the image and text
3853 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3854 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3856 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3858 const string dead_directory = _session->session_directory().dead_path();
3861 %1 - number of files removed
3862 %2 - location of "dead"
3863 %3 - size of files affected
3864 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3867 const char* bprefix;
3868 double space_adjusted = 0;
3870 if (rep.space < 1000) {
3872 space_adjusted = rep.space;
3873 } else if (rep.space < 1000000) {
3874 bprefix = _("kilo");
3875 space_adjusted = floorf((float)rep.space / 1000.0);
3876 } else if (rep.space < 1000000 * 1000) {
3877 bprefix = _("mega");
3878 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3880 bprefix = _("giga");
3881 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3885 txt.set_markup (string_compose (P_("\
3886 The following file was deleted from %2,\n\
3887 releasing %3 %4bytes of disk space", "\
3888 The following %1 files were deleted from %2,\n\
3889 releasing %3 %4bytes of disk space", removed),
3890 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3892 txt.set_markup (string_compose (P_("\
3893 The following file was not in use and \n\
3894 has been moved to: %2\n\n\
3895 After a restart of %5\n\n\
3896 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3897 will release an additional %3 %4bytes of disk space.\n", "\
3898 The following %1 files were not in use and \n\
3899 have been moved to: %2\n\n\
3900 After a restart of %5\n\n\
3901 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3902 will release an additional %3 %4bytes of disk space.\n", removed),
3903 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3906 dhbox.pack_start (*dimage, true, false, 5);
3907 dhbox.pack_start (txt, true, false, 5);
3909 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3910 TreeModel::Row row = *(results_model->append());
3911 row[results_columns.visible_name] = *i;
3912 row[results_columns.fullpath] = *i;
3915 list_scroller.add (results_display);
3916 list_scroller.set_size_request (-1, 150);
3917 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3919 dvbox.pack_start (dhbox, true, false, 5);
3920 dvbox.pack_start (list_scroller, true, false, 5);
3921 ddhbox.pack_start (dvbox, true, false, 5);
3923 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3924 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3925 results.set_default_response (RESPONSE_CLOSE);
3926 results.set_position (Gtk::WIN_POS_MOUSE);
3928 results_display.show();
3929 list_scroller.show();
3936 //results.get_vbox()->show();
3937 results.set_resizable (false);
3944 ARDOUR_UI::cleanup ()
3946 if (_session == 0) {
3947 /* shouldn't happen: menu item is insensitive */
3952 MessageDialog checker (_("Are you sure you want to clean-up?"),
3954 Gtk::MESSAGE_QUESTION,
3957 checker.set_title (_("Clean-up"));
3959 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3960 ALL undo/redo information will be lost if you clean-up.\n\
3961 Clean-up will move all unused files to a \"dead\" location."));
3963 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3964 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3965 checker.set_default_response (RESPONSE_CANCEL);
3967 checker.set_name (_("CleanupDialog"));
3968 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3969 checker.set_position (Gtk::WIN_POS_MOUSE);
3971 switch (checker.run()) {
3972 case RESPONSE_ACCEPT:
3978 ARDOUR::CleanupReport rep;
3980 editor->prepare_for_cleanup ();
3982 /* do not allow flush until a session is reloaded */
3984 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3986 act->set_sensitive (false);
3989 if (_session->cleanup_sources (rep)) {
3990 editor->finish_cleanup ();
3994 editor->finish_cleanup ();
3997 display_cleanup_results (rep, _("Cleaned Files"), false);
4001 ARDOUR_UI::flush_trash ()
4003 if (_session == 0) {
4004 /* shouldn't happen: menu item is insensitive */
4008 ARDOUR::CleanupReport rep;
4010 if (_session->cleanup_trash_sources (rep)) {
4014 display_cleanup_results (rep, _("deleted file"), true);
4018 ARDOUR_UI::cleanup_peakfiles ()
4020 if (_session == 0) {
4021 /* shouldn't happen: menu item is insensitive */
4025 if (! _session->can_cleanup_peakfiles ()) {
4029 // get all region-views in this session
4031 TrackViewList empty;
4033 editor->get_regions_after(rs, (framepos_t) 0, empty);
4034 std::list<RegionView*> views = rs.by_layer();
4036 // remove displayed audio-region-views waveforms
4037 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4038 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4039 if (!arv) { continue ; }
4040 arv->delete_waves();
4043 // cleanup peak files:
4044 // - stop pending peakfile threads
4045 // - close peakfiles if any
4046 // - remove peak dir in session
4047 // - setup peakfiles (background thread)
4048 _session->cleanup_peakfiles ();
4050 // re-add waves to ARV
4051 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4052 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4053 if (!arv) { continue ; }
4054 arv->create_waves();
4058 PresentationInfo::order_t
4059 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4061 if (editor->get_selection().tracks.empty()) {
4062 return PresentationInfo::max_order;
4065 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4068 we want the new routes to have their order keys set starting from
4069 the highest order key in the selection + 1 (if available).
4072 if (place == RouteDialogs::AfterSelection) {
4073 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4075 order_hint = rtav->route()->presentation_info().order();
4078 } else if (place == RouteDialogs::BeforeSelection) {
4079 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4081 order_hint = rtav->route()->presentation_info().order();
4083 } else if (place == RouteDialogs::First) {
4086 /* leave order_hint at max_order */
4093 ARDOUR_UI::start_duplicate_routes ()
4095 if (!duplicate_routes_dialog) {
4096 duplicate_routes_dialog = new DuplicateRouteDialog;
4099 if (duplicate_routes_dialog->restart (_session)) {
4103 duplicate_routes_dialog->present ();
4107 ARDOUR_UI::add_route ()
4109 if (!add_route_dialog.get (false)) {
4110 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4117 if (add_route_dialog->is_visible()) {
4118 /* we're already doing this */
4122 add_route_dialog->set_position (WIN_POS_MOUSE);
4123 add_route_dialog->present();
4127 ARDOUR_UI::add_route_dialog_finished (int r)
4131 add_route_dialog->hide();
4134 case RESPONSE_ACCEPT:
4141 if ((count = add_route_dialog->count()) <= 0) {
4145 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4146 string template_path = add_route_dialog->track_template();
4147 DisplaySuspender ds;
4149 if (!template_path.empty()) {
4150 if (add_route_dialog->name_template_is_default()) {
4151 _session->new_route_from_template (count, order, template_path, string());
4153 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4158 ChanCount input_chan= add_route_dialog->channels ();
4159 ChanCount output_chan;
4160 string name_template = add_route_dialog->name_template ();
4161 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4162 RouteGroup* route_group = add_route_dialog->route_group ();
4163 AutoConnectOption oac = Config->get_output_auto_connect();
4164 bool strict_io = add_route_dialog->use_strict_io ();
4166 if (oac & AutoConnectMaster) {
4167 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4168 output_chan.set (DataType::MIDI, 0);
4170 output_chan = input_chan;
4173 /* XXX do something with name template */
4175 Session::ProcessorChangeBlocker pcb (_session);
4177 switch (add_route_dialog->type_wanted()) {
4178 case AddRouteDialog::AudioTrack:
4179 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4181 case AddRouteDialog::MidiTrack:
4182 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4184 case AddRouteDialog::MixedTrack:
4185 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4187 case AddRouteDialog::AudioBus:
4188 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4190 case AddRouteDialog::MidiBus:
4191 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4193 case AddRouteDialog::VCAMaster:
4194 session_add_vca (name_template, count);
4200 ARDOUR_UI::add_lua_script ()
4206 LuaScriptInfoPtr spi;
4207 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4208 switch (ss.run ()) {
4209 case Gtk::RESPONSE_ACCEPT:
4217 std::string script = "";
4220 script = Glib::file_get_contents (spi->path);
4221 } catch (Glib::FileError e) {
4222 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4223 MessageDialog am (msg);
4228 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4229 std::vector<std::string> reg = _session->registered_lua_functions ();
4231 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4232 switch (spd.run ()) {
4233 case Gtk::RESPONSE_ACCEPT:
4240 _session->register_lua_function (spd.name(), script, lsp);
4241 } catch (luabridge::LuaException const& e) {
4242 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4243 MessageDialog am (msg);
4245 } catch (SessionException e) {
4246 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4247 MessageDialog am (msg);
4253 ARDOUR_UI::remove_lua_script ()
4258 if (_session->registered_lua_function_count () == 0) {
4259 string msg = _("There are no active Lua session scripts present in this session.");
4260 MessageDialog am (msg);
4265 std::vector<std::string> reg = _session->registered_lua_functions ();
4266 SessionScriptManager sm ("Remove Lua Session Script", reg);
4267 switch (sm.run ()) {
4268 case Gtk::RESPONSE_ACCEPT:
4274 _session->unregister_lua_function (sm.name());
4275 } catch (luabridge::LuaException const& e) {
4276 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4277 MessageDialog am (msg);
4283 ARDOUR_UI::stop_video_server (bool ask_confirm)
4285 if (!video_server_process && ask_confirm) {
4286 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4288 if (video_server_process) {
4290 ArdourDialog confirm (_("Stop Video-Server"), true);
4291 Label m (_("Do you really want to stop the Video Server?"));
4292 confirm.get_vbox()->pack_start (m, true, true);
4293 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4294 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4295 confirm.show_all ();
4296 if (confirm.run() == RESPONSE_CANCEL) {
4300 delete video_server_process;
4301 video_server_process =0;
4306 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4308 ARDOUR_UI::start_video_server( float_window, true);
4312 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4318 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4319 if (video_server_process) {
4320 popup_error(_("The Video Server is already started."));
4322 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4328 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4330 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4332 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4334 video_server_dialog->set_transient_for (*float_window);
4337 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4338 video_server_dialog->hide();
4340 ResponseType r = (ResponseType) video_server_dialog->run ();
4341 video_server_dialog->hide();
4342 if (r != RESPONSE_ACCEPT) { return false; }
4343 if (video_server_dialog->show_again()) {
4344 Config->set_show_video_server_dialog(false);
4348 std::string icsd_exec = video_server_dialog->get_exec_path();
4349 std::string icsd_docroot = video_server_dialog->get_docroot();
4350 if (icsd_docroot.empty()) {
4351 #ifndef PLATFORM_WINDOWS
4352 icsd_docroot = X_("/");
4354 icsd_docroot = X_("C:\\");
4359 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4360 warning << _("Specified docroot is not an existing directory.") << endmsg;
4363 #ifndef PLATFORM_WINDOWS
4364 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4365 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4366 warning << _("Given Video Server is not an executable file.") << endmsg;
4370 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4371 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4372 warning << _("Given Video Server is not an executable file.") << endmsg;
4378 argp=(char**) calloc(9,sizeof(char*));
4379 argp[0] = strdup(icsd_exec.c_str());
4380 argp[1] = strdup("-P");
4381 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4382 argp[3] = strdup("-p");
4383 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4384 argp[5] = strdup("-C");
4385 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4386 argp[7] = strdup(icsd_docroot.c_str());
4388 stop_video_server();
4390 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4391 Config->set_video_advanced_setup(false);
4393 std::ostringstream osstream;
4394 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4395 Config->set_video_server_url(osstream.str());
4396 Config->set_video_server_docroot(icsd_docroot);
4397 Config->set_video_advanced_setup(true);
4400 if (video_server_process) {
4401 delete video_server_process;
4404 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4405 if (video_server_process->start()) {
4406 warning << _("Cannot launch the video-server") << endmsg;
4409 int timeout = 120; // 6 sec
4410 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4411 Glib::usleep (50000);
4413 if (--timeout <= 0 || !video_server_process->is_running()) break;
4416 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4418 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4419 delete video_server_process;
4420 video_server_process = 0;
4428 ARDOUR_UI::add_video (Gtk::Window* float_window)
4434 if (!start_video_server(float_window, false)) {
4435 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4440 add_video_dialog->set_transient_for (*float_window);
4443 if (add_video_dialog->is_visible()) {
4444 /* we're already doing this */
4448 ResponseType r = (ResponseType) add_video_dialog->run ();
4449 add_video_dialog->hide();
4450 if (r != RESPONSE_ACCEPT) { return; }
4452 bool local_file, orig_local_file;
4453 std::string path = add_video_dialog->file_name(local_file);
4455 std::string orig_path = path;
4456 orig_local_file = local_file;
4458 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4460 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4461 warning << string_compose(_("could not open %1"), path) << endmsg;
4464 if (!local_file && path.length() == 0) {
4465 warning << _("no video-file selected") << endmsg;
4469 std::string audio_from_video;
4470 bool detect_ltc = false;
4472 switch (add_video_dialog->import_option()) {
4473 case VTL_IMPORT_TRANSCODE:
4475 TranscodeVideoDialog *transcode_video_dialog;
4476 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4477 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4478 transcode_video_dialog->hide();
4479 if (r != RESPONSE_ACCEPT) {
4480 delete transcode_video_dialog;
4484 audio_from_video = transcode_video_dialog->get_audiofile();
4486 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4489 else if (!audio_from_video.empty()) {
4490 editor->embed_audio_from_video(
4492 video_timeline->get_offset(),
4493 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4496 switch (transcode_video_dialog->import_option()) {
4497 case VTL_IMPORT_TRANSCODED:
4498 path = transcode_video_dialog->get_filename();
4501 case VTL_IMPORT_REFERENCE:
4504 delete transcode_video_dialog;
4507 delete transcode_video_dialog;
4511 case VTL_IMPORT_NONE:
4515 /* strip _session->session_directory().video_path() from video file if possible */
4516 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4517 path=path.substr(_session->session_directory().video_path().size());
4518 if (path.at(0) == G_DIR_SEPARATOR) {
4519 path=path.substr(1);
4523 video_timeline->set_update_session_fps(auto_set_session_fps);
4525 if (video_timeline->video_file_info(path, local_file)) {
4526 XMLNode* node = new XMLNode(X_("Videotimeline"));
4527 node->add_property (X_("Filename"), path);
4528 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4529 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4530 if (orig_local_file) {
4531 node->add_property (X_("OriginalVideoFile"), orig_path);
4533 node->remove_property (X_("OriginalVideoFile"));
4535 _session->add_extra_xml (*node);
4536 _session->set_dirty ();
4538 if (!audio_from_video.empty() && detect_ltc) {
4539 std::vector<LTCFileReader::LTCMap> ltc_seq;
4542 /* TODO ask user about TV standard (LTC alignment if any) */
4543 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4544 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4546 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4548 /* TODO seek near end of file, and read LTC until end.
4549 * if it fails to find any LTC frames, scan complete file
4551 * calculate drift of LTC compared to video-duration,
4552 * ask user for reference (timecode from start/mid/end)
4555 // LTCFileReader will have written error messages
4558 ::g_unlink(audio_from_video.c_str());
4560 if (ltc_seq.size() == 0) {
4561 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4563 /* the very first TC in the file is somteimes not aligned properly */
4564 int i = ltc_seq.size() -1;
4565 ARDOUR::frameoffset_t video_start_offset =
4566 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4567 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4568 video_timeline->set_offset(video_start_offset);
4572 _session->maybe_update_session_range(
4573 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4574 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4577 if (add_video_dialog->launch_xjadeo() && local_file) {
4578 editor->set_xjadeo_sensitive(true);
4579 editor->toggle_xjadeo_proc(1);
4581 editor->toggle_xjadeo_proc(0);
4583 editor->toggle_ruler_video(true);
4588 ARDOUR_UI::remove_video ()
4590 video_timeline->close_session();
4591 editor->toggle_ruler_video(false);
4594 video_timeline->set_offset_locked(false);
4595 video_timeline->set_offset(0);
4597 /* delete session state */
4598 XMLNode* node = new XMLNode(X_("Videotimeline"));
4599 _session->add_extra_xml(*node);
4600 node = new XMLNode(X_("Videomonitor"));
4601 _session->add_extra_xml(*node);
4602 node = new XMLNode(X_("Videoexport"));
4603 _session->add_extra_xml(*node);
4604 stop_video_server();
4608 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4610 if (localcacheonly) {
4611 video_timeline->vmon_update();
4613 video_timeline->flush_cache();
4615 editor->queue_visual_videotimeline_update();
4619 ARDOUR_UI::export_video (bool range)
4621 if (ARDOUR::Config->get_show_video_export_info()) {
4622 ExportVideoInfobox infobox (_session);
4623 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4624 if (infobox.show_again()) {
4625 ARDOUR::Config->set_show_video_export_info(false);
4628 case GTK_RESPONSE_YES:
4629 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4635 export_video_dialog->set_session (_session);
4636 export_video_dialog->apply_state(editor->get_selection().time, range);
4637 export_video_dialog->run ();
4638 export_video_dialog->hide ();
4642 ARDOUR_UI::preferences_settings () const
4647 node = _session->instant_xml(X_("Preferences"));
4649 node = Config->instant_xml(X_("Preferences"));
4653 node = new XMLNode (X_("Preferences"));
4660 ARDOUR_UI::mixer_settings () const
4665 node = _session->instant_xml(X_("Mixer"));
4667 node = Config->instant_xml(X_("Mixer"));
4671 node = new XMLNode (X_("Mixer"));
4678 ARDOUR_UI::main_window_settings () const
4683 node = _session->instant_xml(X_("Main"));
4685 node = Config->instant_xml(X_("Main"));
4689 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4690 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4695 node = new XMLNode (X_("Main"));
4702 ARDOUR_UI::editor_settings () const
4707 node = _session->instant_xml(X_("Editor"));
4709 node = Config->instant_xml(X_("Editor"));
4713 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4714 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4719 node = new XMLNode (X_("Editor"));
4726 ARDOUR_UI::keyboard_settings () const
4730 node = Config->extra_xml(X_("Keyboard"));
4733 node = new XMLNode (X_("Keyboard"));
4740 ARDOUR_UI::create_xrun_marker (framepos_t where)
4743 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4744 _session->locations()->add (location);
4749 ARDOUR_UI::halt_on_xrun_message ()
4751 cerr << "HALT on xrun\n";
4752 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4757 ARDOUR_UI::xrun_handler (framepos_t where)
4763 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4765 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4766 create_xrun_marker(where);
4769 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4770 halt_on_xrun_message ();
4775 ARDOUR_UI::disk_overrun_handler ()
4777 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4779 if (!have_disk_speed_dialog_displayed) {
4780 have_disk_speed_dialog_displayed = true;
4781 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4782 The disk system on your computer\n\
4783 was not able to keep up with %1.\n\
4785 Specifically, it failed to write data to disk\n\
4786 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4787 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4793 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4794 static MessageDialog *scan_dlg = NULL;
4795 static ProgressBar *scan_pbar = NULL;
4796 static HBox *scan_tbox = NULL;
4797 static Gtk::Button *scan_timeout_button;
4800 ARDOUR_UI::cancel_plugin_scan ()
4802 PluginManager::instance().cancel_plugin_scan();
4806 ARDOUR_UI::cancel_plugin_timeout ()
4808 PluginManager::instance().cancel_plugin_timeout();
4809 scan_timeout_button->set_sensitive (false);
4813 ARDOUR_UI::plugin_scan_timeout (int timeout)
4815 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4819 scan_pbar->set_sensitive (false);
4820 scan_timeout_button->set_sensitive (true);
4821 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4824 scan_pbar->set_sensitive (false);
4825 scan_timeout_button->set_sensitive (false);
4831 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4833 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4837 const bool cancelled = PluginManager::instance().cancelled();
4838 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4839 if (cancelled && scan_dlg->is_mapped()) {
4844 if (cancelled || !can_cancel) {
4849 static Gtk::Button *cancel_button;
4851 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4852 VBox* vbox = scan_dlg->get_vbox();
4853 vbox->set_size_request(400,-1);
4854 scan_dlg->set_title (_("Scanning for plugins"));
4856 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4857 cancel_button->set_name ("EditorGTKButton");
4858 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4859 cancel_button->show();
4861 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4863 scan_tbox = manage( new HBox() );
4865 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4866 scan_timeout_button->set_name ("EditorGTKButton");
4867 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4868 scan_timeout_button->show();
4870 scan_pbar = manage(new ProgressBar());
4871 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4872 scan_pbar->set_text(_("Scan Timeout"));
4875 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4876 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4878 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4881 assert(scan_dlg && scan_tbox && cancel_button);
4883 if (type == X_("closeme")) {
4887 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4890 if (!can_cancel || !cancelled) {
4891 scan_timeout_button->set_sensitive(false);
4893 cancel_button->set_sensitive(can_cancel && !cancelled);
4899 ARDOUR_UI::gui_idle_handler ()
4902 /* due to idle calls, gtk_events_pending() may always return true */
4903 while (gtk_events_pending() && --timeout) {
4904 gtk_main_iteration ();
4909 ARDOUR_UI::disk_underrun_handler ()
4911 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4913 if (!have_disk_speed_dialog_displayed) {
4914 have_disk_speed_dialog_displayed = true;
4915 MessageDialog* msg = new MessageDialog (
4916 _main_window, string_compose (_("The disk system on your computer\n\
4917 was not able to keep up with %1.\n\
4919 Specifically, it failed to read data from disk\n\
4920 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4921 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4927 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4929 have_disk_speed_dialog_displayed = false;
4934 ARDOUR_UI::session_dialog (std::string msg)
4936 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4940 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4947 ARDOUR_UI::pending_state_dialog ()
4949 HBox* hbox = manage (new HBox());
4950 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4951 ArdourDialog dialog (_("Crash Recovery"), true);
4952 Label message (string_compose (_("\
4953 This session appears to have been in the\n\
4954 middle of recording when %1 or\n\
4955 the computer was shutdown.\n\
4957 %1 can recover any captured audio for\n\
4958 you, or it can ignore it. Please decide\n\
4959 what you would like to do.\n"), PROGRAM_NAME));
4960 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4961 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4962 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4963 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4964 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4965 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4966 dialog.set_default_response (RESPONSE_ACCEPT);
4967 dialog.set_position (WIN_POS_CENTER);
4972 switch (dialog.run ()) {
4973 case RESPONSE_ACCEPT:
4981 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4983 HBox* hbox = new HBox();
4984 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4985 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4986 Label message (string_compose (_("\
4987 This session was created with a sample rate of %1 Hz, but\n\
4988 %2 is currently running at %3 Hz. If you load this session,\n\
4989 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4991 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4992 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4993 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4994 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4995 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4996 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4997 dialog.set_default_response (RESPONSE_ACCEPT);
4998 dialog.set_position (WIN_POS_CENTER);
5003 switch (dialog.run()) {
5004 case RESPONSE_ACCEPT:
5014 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5016 MessageDialog msg (string_compose (_("\
5017 This session was created with a sample rate of %1 Hz, but\n\
5018 %2 is currently running at %3 Hz.\n\
5019 Audio will be recorded and played at the wrong sample rate.\n\
5020 Re-Configure the Audio Engine in\n\
5021 Menu > Window > Audio/Midi Setup"),
5022 desired, PROGRAM_NAME, actual),
5024 Gtk::MESSAGE_WARNING);
5029 ARDOUR_UI::use_config ()
5031 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5033 set_transport_controllable_state (*node);
5038 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5040 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5041 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5043 primary_clock->set (pos);
5046 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5047 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5049 secondary_clock->set (pos);
5052 if (big_clock_window) {
5053 big_clock->set (pos);
5055 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5059 ARDOUR_UI::step_edit_status_change (bool yn)
5061 // XXX should really store pre-step edit status of things
5062 // we make insensitive
5065 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5066 rec_button.set_sensitive (false);
5068 rec_button.unset_active_state ();;
5069 rec_button.set_sensitive (true);
5074 ARDOUR_UI::record_state_changed ()
5076 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5079 /* why bother - the clock isn't visible */
5083 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5085 if (big_clock_window) {
5086 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5087 big_clock->set_active (true);
5089 big_clock->set_active (false);
5096 ARDOUR_UI::first_idle ()
5099 _session->allow_auto_play (true);
5103 editor->first_idle();
5106 Keyboard::set_can_save_keybindings (true);
5111 ARDOUR_UI::store_clock_modes ()
5113 XMLNode* node = new XMLNode(X_("ClockModes"));
5115 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5116 XMLNode* child = new XMLNode (X_("Clock"));
5118 child->add_property (X_("name"), (*x)->name());
5119 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5120 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5122 node->add_child_nocopy (*child);
5125 _session->add_extra_xml (*node);
5126 _session->set_dirty ();
5129 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5130 : Controllable (name), ui (u), type(tp)
5136 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5139 /* do nothing: these are radio-style actions */
5143 const char *action = 0;
5147 action = X_("Roll");
5150 action = X_("Stop");
5153 action = X_("GotoStart");
5156 action = X_("GotoEnd");
5159 action = X_("Loop");
5162 action = X_("PlaySelection");
5165 action = X_("Record");
5175 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5183 ARDOUR_UI::TransportControllable::get_value (void) const
5210 ARDOUR_UI::setup_profile ()
5212 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5213 Profile->set_small_screen ();
5216 if (g_getenv ("TRX")) {
5217 Profile->set_trx ();
5220 if (g_getenv ("MIXBUS")) {
5221 Profile->set_mixbus ();
5226 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5228 MissingFileDialog dialog (s, str, type);
5233 int result = dialog.run ();
5240 return 1; // quit entire session load
5243 result = dialog.get_action ();
5249 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5251 AmbiguousFileDialog dialog (file, hits);
5258 return dialog.get_which ();
5261 /** Allocate our thread-local buffers */
5263 ARDOUR_UI::get_process_buffers ()
5265 _process_thread->get_buffers ();
5268 /** Drop our thread-local buffers */
5270 ARDOUR_UI::drop_process_buffers ()
5272 _process_thread->drop_buffers ();
5276 ARDOUR_UI::feedback_detected ()
5278 _feedback_exists = true;
5282 ARDOUR_UI::successful_graph_sort ()
5284 _feedback_exists = false;
5288 ARDOUR_UI::midi_panic ()
5291 _session->midi_panic();
5296 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5298 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5299 const char* end_big = "</span>";
5300 const char* start_mono = "<tt>";
5301 const char* end_mono = "</tt>";
5303 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5304 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5305 "From now on, use the backup copy with older versions of %3"),
5306 xml_path, backup_path, PROGRAM_NAME,
5308 start_mono, end_mono), true);
5315 ARDOUR_UI::reset_peak_display ()
5317 if (!_session || !_session->master_out() || !editor_meter) return;
5318 editor_meter->clear_meters();
5319 editor_meter_max_peak = -INFINITY;
5320 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5324 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5326 if (!_session || !_session->master_out()) return;
5327 if (group == _session->master_out()->route_group()) {
5328 reset_peak_display ();
5333 ARDOUR_UI::reset_route_peak_display (Route* route)
5335 if (!_session || !_session->master_out()) return;
5336 if (_session->master_out().get() == route) {
5337 reset_peak_display ();
5342 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5344 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5345 audio_midi_setup->set_position (WIN_POS_CENTER);
5347 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5348 audio_midi_setup->try_autostart ();
5349 if (ARDOUR::AudioEngine::instance()->running()) {
5355 int response = audio_midi_setup->run();
5356 printf("RESPONSE %d\n", response);
5358 case Gtk::RESPONSE_DELETE_EVENT:
5361 if (!AudioEngine::instance()->running()) {
5364 audio_midi_setup->hide ();
5372 ARDOUR_UI::transport_numpad_timeout ()
5374 _numpad_locate_happening = false;
5375 if (_numpad_timeout_connection.connected() )
5376 _numpad_timeout_connection.disconnect();
5381 ARDOUR_UI::transport_numpad_decimal ()
5383 _numpad_timeout_connection.disconnect();
5385 if (_numpad_locate_happening) {
5386 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5387 _numpad_locate_happening = false;
5389 _pending_locate_num = 0;
5390 _numpad_locate_happening = true;
5391 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5396 ARDOUR_UI::transport_numpad_event (int num)
5398 if ( _numpad_locate_happening ) {
5399 _pending_locate_num = _pending_locate_num*10 + num;
5402 case 0: toggle_roll(false, false); break;
5403 case 1: transport_rewind(1); break;
5404 case 2: transport_forward(1); break;
5405 case 3: transport_record(true); break;
5406 case 4: toggle_session_auto_loop(); break;
5407 case 5: transport_record(false); toggle_session_auto_loop(); break;
5408 case 6: toggle_punch(); break;
5409 case 7: toggle_click(); break;
5410 case 8: toggle_auto_return(); break;
5411 case 9: toggle_follow_edits(); break;
5417 ARDOUR_UI::set_flat_buttons ()
5419 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5423 ARDOUR_UI::audioengine_became_silent ()
5425 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5427 Gtk::MESSAGE_WARNING,
5431 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5433 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5434 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5435 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5436 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5437 Gtk::HBox pay_button_box;
5438 Gtk::HBox subscribe_button_box;
5440 pay_button_box.pack_start (pay_button, true, false);
5441 subscribe_button_box.pack_start (subscribe_button, true, false);
5443 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 */
5445 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5446 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5448 msg.get_vbox()->pack_start (pay_label);
5449 msg.get_vbox()->pack_start (pay_button_box);
5450 msg.get_vbox()->pack_start (subscribe_label);
5451 msg.get_vbox()->pack_start (subscribe_button_box);
5453 msg.get_vbox()->show_all ();
5455 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5456 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5457 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5462 case Gtk::RESPONSE_YES:
5463 AudioEngine::instance()->reset_silence_countdown ();
5466 case Gtk::RESPONSE_NO:
5468 save_state_canfail ("");
5472 case Gtk::RESPONSE_CANCEL:
5474 /* don't reset, save session and exit */
5480 ARDOUR_UI::hide_application ()
5482 Application::instance ()-> hide ();
5486 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5488 /* icons, titles, WM stuff */
5490 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5492 if (window_icons.empty()) {
5493 Glib::RefPtr<Gdk::Pixbuf> icon;
5494 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5495 window_icons.push_back (icon);
5497 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5498 window_icons.push_back (icon);
5500 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5501 window_icons.push_back (icon);
5503 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5504 window_icons.push_back (icon);
5508 if (!window_icons.empty()) {
5509 window.set_default_icon_list (window_icons);
5512 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5514 if (!name.empty()) {
5518 window.set_title (title.get_string());
5519 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5521 window.set_flags (CAN_FOCUS);
5522 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5524 /* This is a hack to ensure that GTK-accelerators continue to
5525 * work. Once we switch over to entirely native bindings, this will be
5526 * unnecessary and should be removed
5528 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5530 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5531 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5532 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5533 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5537 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5539 Gtkmm2ext::Bindings* bindings = 0;
5540 Gtk::Window* window = 0;
5542 /* until we get ardour bindings working, we are not handling key
5546 if (ev->type != GDK_KEY_PRESS) {
5550 if (event_window == &_main_window) {
5552 window = event_window;
5554 /* find current tab contents */
5556 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5558 /* see if it uses the ardour binding system */
5561 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5564 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5568 window = event_window;
5570 /* see if window uses ardour binding system */
5572 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5575 /* An empty binding set is treated as if it doesn't exist */
5577 if (bindings && bindings->empty()) {
5581 return key_press_focus_accelerator_handler (*window, ev, bindings);
5584 static Gtkmm2ext::Bindings*
5585 get_bindings_from_widget_heirarchy (GtkWidget** w)
5590 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5593 *w = gtk_widget_get_parent (*w);
5596 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5600 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5602 GtkWindow* win = window.gobj();
5603 GtkWidget* focus = gtk_window_get_focus (win);
5604 GtkWidget* binding_widget = focus;
5605 bool special_handling_of_unmodified_accelerators = false;
5606 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5610 /* some widget has keyboard focus */
5612 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5614 /* A particular kind of focusable widget currently has keyboard
5615 * focus. All unmodified key events should go to that widget
5616 * first and not be used as an accelerator by default
5619 special_handling_of_unmodified_accelerators = true;
5623 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5624 if (focus_bindings) {
5625 bindings = focus_bindings;
5626 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5631 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",
5634 Gtkmm2ext::show_gdk_event_state (ev->state),
5635 special_handling_of_unmodified_accelerators,
5636 Keyboard::some_magic_widget_has_focus(),
5638 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5639 ((ev->state & mask) ? "yes" : "no"),
5640 window.get_title()));
5642 /* This exists to allow us to override the way GTK handles
5643 key events. The normal sequence is:
5645 a) event is delivered to a GtkWindow
5646 b) accelerators/mnemonics are activated
5647 c) if (b) didn't handle the event, propagate to
5648 the focus widget and/or focus chain
5650 The problem with this is that if the accelerators include
5651 keys without modifiers, such as the space bar or the
5652 letter "e", then pressing the key while typing into
5653 a text entry widget results in the accelerator being
5654 activated, instead of the desired letter appearing
5657 There is no good way of fixing this, but this
5658 represents a compromise. The idea is that
5659 key events involving modifiers (not Shift)
5660 get routed into the activation pathway first, then
5661 get propagated to the focus widget if necessary.
5663 If the key event doesn't involve modifiers,
5664 we deliver to the focus widget first, thus allowing
5665 it to get "normal text" without interference
5668 Of course, this can also be problematic: if there
5669 is a widget with focus, then it will swallow
5670 all "normal text" accelerators.
5674 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5676 /* no special handling or there are modifiers in effect: accelerate first */
5678 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5679 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5680 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5682 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5683 KeyboardKey k (ev->state, ev->keyval);
5687 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5689 if (bindings->activate (k, Bindings::Press)) {
5690 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5694 if (binding_widget) {
5695 binding_widget = gtk_widget_get_parent (binding_widget);
5696 if (binding_widget) {
5697 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5706 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5708 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5709 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5713 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5715 if (gtk_window_propagate_key_event (win, ev)) {
5716 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5722 /* no modifiers, propagate first */
5724 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5726 if (gtk_window_propagate_key_event (win, ev)) {
5727 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5731 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5732 KeyboardKey k (ev->state, ev->keyval);
5736 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
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");
5764 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5769 ARDOUR_UI::load_bindings ()
5771 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5772 error << _("Global keybindings are missing") << endmsg;
5777 ARDOUR_UI::cancel_solo ()
5780 _session->cancel_all_solo ();
5785 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5787 /* this resets focus to the first focusable parent of the given widget,
5788 * or, if there is no focusable parent, cancels focus in the toplevel
5789 * window that the given widget is packed into (if there is one).
5796 Gtk::Widget* top = w->get_toplevel();
5798 if (!top || !top->is_toplevel()) {
5802 w = w->get_parent ();
5806 if (w->is_toplevel()) {
5807 /* Setting the focus widget to a Gtk::Window causes all
5808 * subsequent calls to ::has_focus() on the nominal
5809 * focus widget in that window to return
5810 * false. Workaround: never set focus to the toplevel
5816 if (w->get_can_focus ()) {
5817 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5818 win->set_focus (*w);
5821 w = w->get_parent ();
5824 if (top == &_main_window) {
5828 /* no focusable parent found, cancel focus in top level window.
5829 C++ API cannot be used for this. Thanks, references.
5832 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);