2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/accelmap.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/uimanager.h>
55 #include "pbd/error.h"
56 #include "pbd/basename.h"
57 #include "pbd/compose.h"
58 #include "pbd/convert.h"
59 #include "pbd/failed_constructor.h"
60 #include "pbd/file_archive.h"
61 #include "pbd/enumwriter.h"
62 #include "pbd/memento_command.h"
63 #include "pbd/openuri.h"
64 #include "pbd/stl_delete.h"
65 #include "pbd/types_convert.h"
66 #include "pbd/unwind.h"
67 #include "pbd/file_utils.h"
68 #include "pbd/localtime_r.h"
69 #include "pbd/pthread_utils.h"
70 #include "pbd/replace_all.h"
71 #include "pbd/scoped_file_descriptor.h"
72 #include "pbd/xml++.h"
74 #include "gtkmm2ext/application.h"
75 #include "gtkmm2ext/bindings.h"
76 #include "gtkmm2ext/gtk_ui.h"
77 #include "gtkmm2ext/utils.h"
78 #include "gtkmm2ext/window_title.h"
80 #include "widgets/fastmeter.h"
81 #include "widgets/prompter.h"
83 #include "ardour/ardour.h"
84 #include "ardour/audio_backend.h"
85 #include "ardour/audio_track.h"
86 #include "ardour/audioengine.h"
87 #include "ardour/audiofilesource.h"
88 #include "ardour/automation_watch.h"
89 #include "ardour/diskstream.h"
90 #include "ardour/filename_extensions.h"
91 #include "ardour/filesystem_paths.h"
92 #include "ardour/ltc_file_reader.h"
93 #include "ardour/midi_track.h"
94 #include "ardour/port.h"
95 #include "ardour/plugin_manager.h"
96 #include "ardour/process_thread.h"
97 #include "ardour/profile.h"
98 #include "ardour/recent_sessions.h"
99 #include "ardour/record_enable_control.h"
100 #include "ardour/revision.h"
101 #include "ardour/session_directory.h"
102 #include "ardour/session_route.h"
103 #include "ardour/session_state_utils.h"
104 #include "ardour/session_utils.h"
105 #include "ardour/source_factory.h"
106 #include "ardour/slave.h"
107 #include "ardour/system_exec.h"
108 #include "ardour/track.h"
109 #include "ardour/vca_manager.h"
110 #include "ardour/utils.h"
112 #include "LuaBridge/LuaBridge.h"
114 #ifdef WINDOWS_VST_SUPPORT
117 #ifdef AUDIOUNIT_SUPPORT
118 #include "ardour/audio_unit.h"
121 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
126 #include "timecode/time.h"
128 typedef uint64_t microseconds_t;
132 #include "enums_convert.h"
134 #include "add_route_dialog.h"
135 #include "ambiguous_file_dialog.h"
136 #include "ardour_ui.h"
137 #include "audio_clock.h"
138 #include "audio_region_view.h"
139 #include "big_clock_window.h"
140 #include "bundle_manager.h"
141 #include "duplicate_routes_dialog.h"
143 #include "engine_dialog.h"
144 #include "export_video_dialog.h"
145 #include "export_video_infobox.h"
146 #include "gain_meter.h"
147 #include "global_port_matrix.h"
148 #include "gui_object.h"
149 #include "gui_thread.h"
150 #include "idleometer.h"
151 #include "keyboard.h"
152 #include "keyeditor.h"
153 #include "location_ui.h"
154 #include "lua_script_manager.h"
155 #include "luawindow.h"
156 #include "main_clock.h"
157 #include "missing_file_dialog.h"
158 #include "missing_plugin_dialog.h"
159 #include "mixer_ui.h"
160 #include "meterbridge.h"
161 #include "meter_patterns.h"
162 #include "mouse_cursors.h"
165 #include "pingback.h"
166 #include "processor_box.h"
167 #include "public_editor.h"
168 #include "rc_option_editor.h"
169 #include "route_time_axis.h"
170 #include "route_params_ui.h"
171 #include "save_as_dialog.h"
172 #include "script_selector.h"
173 #include "session_archive_dialog.h"
174 #include "session_dialog.h"
175 #include "session_metadata_dialog.h"
176 #include "session_option_editor.h"
177 #include "speaker_dialog.h"
180 #include "template_dialog.h"
181 #include "time_axis_view_item.h"
182 #include "time_info_box.h"
185 #include "utils_videotl.h"
186 #include "video_server_dialog.h"
187 #include "add_video_dialog.h"
188 #include "transcode_video_dialog.h"
190 #include "pbd/i18n.h"
192 using namespace ARDOUR;
193 using namespace ARDOUR_UI_UTILS;
195 using namespace Gtkmm2ext;
196 using namespace ArdourWidgets;
199 using namespace Editing;
201 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
203 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
204 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
207 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
209 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
210 "Would you like these files to be copied and used for %1 %2.x?\n\n"
211 "(This will require you to restart %1.)"),
212 PROGRAM_NAME, PROGRAM_VERSION, version),
213 false, /* no markup */
216 true /* modal, though it hardly matters since it is the only window */
219 msg.set_default_response (Gtk::RESPONSE_YES);
222 return (msg.run() == Gtk::RESPONSE_YES);
226 libxml_generic_error_func (void* /* parsing_context*/,
234 vsnprintf (buf, sizeof (buf), msg, ap);
235 error << buf << endmsg;
240 libxml_structured_error_func (void* /* parsing_context*/,
248 replace_all (msg, "\n", "");
251 if (err->file && err->line) {
252 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
255 error << ':' << err->int2;
260 error << X_("XML error: ") << msg << endmsg;
266 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
267 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
268 , session_loaded (false)
269 , session_load_in_progress (false)
270 , gui_object_state (new GUIObjectState)
271 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
272 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
273 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
275 , global_actions (X_("global"))
276 , ignore_dual_punch (false)
277 , main_window_visibility (0)
282 , _mixer_on_top (false)
283 , _initial_verbose_plugin_scan (false)
284 , first_time_engine_run (true)
285 , secondary_clock_spacer (0)
286 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
287 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
288 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
289 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
290 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
291 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
292 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
293 , auto_input_button (ArdourButton::led_default_elements)
295 , auto_return_button (ArdourButton::led_default_elements)
296 , follow_edits_button (ArdourButton::led_default_elements)
297 , auditioning_alert_button (_("Audition"))
298 , solo_alert_button (_("Solo"))
299 , feedback_alert_button (_("Feedback"))
300 , error_alert_button ( ArdourButton::just_led_default_elements )
301 , editor_meter_peak_display()
303 , _suspend_editor_meter_callbacks (false)
304 , _numpad_locate_happening (false)
305 , _session_is_new (false)
306 , last_key_press_time (0)
310 , rc_option_editor (0)
311 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
312 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
313 , about (X_("about"), _("About"))
314 , location_ui (X_("locations"), S_("Ranges|Locations"))
315 , route_params (X_("inspector"), _("Tracks and Busses"))
316 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
317 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
318 , lua_script_window (X_("script-manager"), _("Script Manager"))
319 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
320 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
321 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
322 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
323 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
324 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
325 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
326 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
327 , video_server_process (0)
329 , have_configure_timeout (false)
330 , last_configure_time (0)
332 , have_disk_speed_dialog_displayed (false)
333 , _status_bar_visibility (X_("status-bar"))
334 , _feedback_exists (false)
335 , _log_not_acknowledged (LogLevelNone)
336 , duplicate_routes_dialog (0)
337 , editor_visibility_button (S_("Window|Editor"))
338 , mixer_visibility_button (S_("Window|Mixer"))
339 , prefs_visibility_button (S_("Window|Preferences"))
341 Gtkmm2ext::init (localedir);
343 UIConfiguration::instance().post_gui_init ();
345 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
347 /* "touch" the been-here-before path now that config has been migrated */
348 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
350 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
352 /* configuration was modified, exit immediately */
357 if (string (VERSIONSTRING).find (".pre") != string::npos) {
358 /* check this is not being run from ./ardev etc. */
359 if (!running_from_source_tree ()) {
360 pre_release_dialog ();
364 if (theArdourUI == 0) {
368 /* track main window visibility */
370 main_window_visibility = new VisibilityTracker (_main_window);
372 /* stop libxml from spewing to stdout/stderr */
374 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
375 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
377 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
378 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
379 UIConfiguration::instance().map_parameters (pc);
381 roll_button.set_controllable (roll_controllable);
382 stop_button.set_controllable (stop_controllable);
383 goto_start_button.set_controllable (goto_start_controllable);
384 goto_end_button.set_controllable (goto_end_controllable);
385 auto_loop_button.set_controllable (auto_loop_controllable);
386 play_selection_button.set_controllable (play_selection_controllable);
387 rec_button.set_controllable (rec_controllable);
389 roll_button.set_name ("transport button");
390 stop_button.set_name ("transport button");
391 goto_start_button.set_name ("transport button");
392 goto_end_button.set_name ("transport button");
393 auto_loop_button.set_name ("transport button");
394 play_selection_button.set_name ("transport button");
395 rec_button.set_name ("transport recenable button");
396 midi_panic_button.set_name ("transport button");
398 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
399 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
401 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
403 /* handle dialog requests */
405 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
407 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
409 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
411 /* handle Audio/MIDI setup when session requires it */
413 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
415 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
417 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
419 /* handle sr mismatch with a dialog - cross-thread from engine */
420 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
422 /* handle requests to quit (coming from JACK session) */
424 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
426 /* tell the user about feedback */
428 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
429 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
431 /* handle requests to deal with missing files */
433 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
435 /* and ambiguous files */
437 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
439 /* also plugin scan messages */
440 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
441 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
443 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
445 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
448 /* lets get this party started */
450 setup_gtk_ardour_enums ();
453 SessionEvent::create_per_thread_pool ("GUI", 4096);
455 /* we like keyboards */
457 keyboard = new ArdourKeyboard(*this);
459 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
461 keyboard->set_state (*node, Stateful::loading_state_version);
464 UIConfiguration::instance().reset_dpi ();
466 TimeAxisViewItem::set_constant_heights ();
468 /* Set this up so that our window proxies can register actions */
470 ActionManager::init ();
472 /* The following must happen after ARDOUR::init() so that Config is set up */
474 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
477 key_editor.set_state (*ui_xml, 0);
478 session_option_editor.set_state (*ui_xml, 0);
479 speaker_config_window.set_state (*ui_xml, 0);
480 about.set_state (*ui_xml, 0);
481 add_route_dialog.set_state (*ui_xml, 0);
482 add_video_dialog.set_state (*ui_xml, 0);
483 route_params.set_state (*ui_xml, 0);
484 bundle_manager.set_state (*ui_xml, 0);
485 location_ui.set_state (*ui_xml, 0);
486 big_clock_window.set_state (*ui_xml, 0);
487 audio_port_matrix.set_state (*ui_xml, 0);
488 midi_port_matrix.set_state (*ui_xml, 0);
489 export_video_dialog.set_state (*ui_xml, 0);
490 lua_script_window.set_state (*ui_xml, 0);
491 idleometer.set_state (*ui_xml, 0);
494 /* Separate windows */
496 WM::Manager::instance().register_window (&key_editor);
497 WM::Manager::instance().register_window (&session_option_editor);
498 WM::Manager::instance().register_window (&speaker_config_window);
499 WM::Manager::instance().register_window (&about);
500 WM::Manager::instance().register_window (&add_route_dialog);
501 WM::Manager::instance().register_window (&add_video_dialog);
502 WM::Manager::instance().register_window (&route_params);
503 WM::Manager::instance().register_window (&audio_midi_setup);
504 WM::Manager::instance().register_window (&export_video_dialog);
505 WM::Manager::instance().register_window (&lua_script_window);
506 WM::Manager::instance().register_window (&bundle_manager);
507 WM::Manager::instance().register_window (&location_ui);
508 WM::Manager::instance().register_window (&big_clock_window);
509 WM::Manager::instance().register_window (&audio_port_matrix);
510 WM::Manager::instance().register_window (&midi_port_matrix);
511 WM::Manager::instance().register_window (&idleometer);
513 /* do not retain position for add route dialog */
514 add_route_dialog.set_state_mask (WindowProxy::Size);
516 /* Trigger setting up the color scheme and loading the GTK RC file */
518 UIConfiguration::instance().load_rc_file (false);
520 _process_thread = new ProcessThread ();
521 _process_thread->init ();
523 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
529 ARDOUR_UI::pre_release_dialog ()
531 ArdourDialog d (_("Pre-Release Warning"), true, false);
532 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
534 Label* label = manage (new Label);
535 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
536 There are still several issues and bugs to be worked on,\n\
537 as well as general workflow improvements, before this can be considered\n\
538 release software. So, a few guidelines:\n\
540 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
541 though it may be so, depending on your workflow.\n\
542 2) Please wait for a helpful writeup of new features.\n\
543 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
544 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
545 making sure to note the product version number as 5.0-pre.\n\
546 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
547 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
548 can get there directly from within the program via the Help->Chat menu option.\n\
550 Full information on all the above can be found on the support page at\n\
552 http://ardour.org/support\n\
553 "), PROGRAM_NAME, VERSIONSTRING));
555 d.get_vbox()->set_border_width (12);
556 d.get_vbox()->pack_start (*label, false, false, 12);
557 d.get_vbox()->show_all ();
562 GlobalPortMatrixWindow*
563 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
568 return new GlobalPortMatrixWindow (_session, type);
572 ARDOUR_UI::attach_to_engine ()
574 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
575 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
579 ARDOUR_UI::engine_stopped ()
581 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
582 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
583 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
584 update_sample_rate (0);
589 ARDOUR_UI::engine_running ()
591 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
592 if (first_time_engine_run) {
594 first_time_engine_run = false;
598 _session->reset_xrun_count ();
600 update_disk_space ();
602 update_xrun_count ();
603 update_sample_rate (AudioEngine::instance()->sample_rate());
604 update_timecode_format ();
605 update_peak_thread_work ();
606 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
607 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
611 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
613 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
614 /* we can't rely on the original string continuing to exist when we are called
615 again in the GUI thread, so make a copy and note that we need to
618 char *copy = strdup (reason);
619 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
623 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
624 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
626 update_sample_rate (0);
630 /* if the reason is a non-empty string, it means that the backend was shutdown
631 rather than just Ardour.
634 if (strlen (reason)) {
635 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
637 msgstr = string_compose (_("\
638 The audio backend has either been shutdown or it\n\
639 disconnected %1 because %1\n\
640 was not fast enough. Try to restart\n\
641 the audio backend and save the session."), PROGRAM_NAME);
644 MessageDialog msg (_main_window, msgstr);
645 pop_back_splash (msg);
649 free (const_cast<char*> (reason));
654 ARDOUR_UI::post_engine ()
656 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
658 #ifdef AUDIOUNIT_SUPPORT
660 if (AUPluginInfo::au_get_crashlog(au_msg)) {
661 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
662 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
663 info << au_msg << endmsg;
667 ARDOUR::init_post_engine ();
669 /* connect to important signals */
671 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
672 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
673 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
674 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
675 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
677 if (setup_windows ()) {
678 throw failed_constructor ();
681 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
682 XMLNode* n = Config->extra_xml (X_("UI"));
684 _status_bar_visibility.set_state (*n);
687 check_memory_locking();
689 /* this is the first point at which all the possible actions are
690 * available, because some of the available actions are dependent on
691 * aspects of the engine/backend.
694 if (ARDOUR_COMMAND_LINE::show_key_actions) {
696 Bindings::save_all_bindings_as_html (sstr);
698 if (sstr.str().empty()) {
705 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
707 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
713 #ifdef PLATFORM_WINDOWS
719 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
720 #ifndef PLATFORM_WINDOWS
723 g_unlink (file_name);
725 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
731 #ifndef PLATFORM_WINDOWS
735 PBD::open_uri (string_compose ("file:///%1", file_name));
737 halt_connection.disconnect ();
738 AudioEngine::instance()->stop ();
743 if (ARDOUR_COMMAND_LINE::show_actions) {
746 vector<string> paths;
747 vector<string> labels;
748 vector<string> tooltips;
750 vector<Glib::RefPtr<Gtk::Action> > actions;
751 string ver_in = revision;
752 string ver = ver_in.substr(0, ver_in.find("-"));
755 output << "\n<h2>Menu actions</h2>" << endl;
756 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
757 output << " surfaces or scripts.\n</p>\n" << endl;
758 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
759 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
760 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
761 output << "<table class=\"dl\">\n <thead>" << endl;
762 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
763 output << " </thead>\n <tbody>" << endl;
765 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
767 vector<string>::iterator p;
768 vector<string>::iterator l;
770 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
771 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
772 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
774 output << " </tbody>\n </table>" << endl;
776 // output this mess to a browser for easiest X-platform use
777 // it is not pretty HTML, but it works and it's main purpose
778 // is to create raw html to fit in Ardour's manual with no editing
783 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
785 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
791 #ifdef PLATFORM_WINDOWS
797 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
798 #ifndef PLATFORM_WINDOWS
801 g_unlink (file_name);
803 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
809 #ifndef PLATFORM_WINDOWS
813 PBD::open_uri (string_compose ("file:///%1", file_name));
815 halt_connection.disconnect ();
816 AudioEngine::instance()->stop ();
820 /* this being a GUI and all, we want peakfiles */
822 AudioFileSource::set_build_peakfiles (true);
823 AudioFileSource::set_build_missing_peakfiles (true);
825 /* set default clock modes */
827 primary_clock->set_mode (AudioClock::Timecode);
828 secondary_clock->set_mode (AudioClock::BBT);
830 /* start the time-of-day-clock */
833 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
834 update_wall_clock ();
835 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
840 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
841 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
842 Config->map_parameters (pc);
844 UIConfiguration::instance().map_parameters (pc);
848 ARDOUR_UI::~ARDOUR_UI ()
850 UIConfiguration::instance().save_state();
854 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
855 // don't bother at 'real' exit. the OS cleans up for us.
856 delete big_clock; big_clock = 0;
857 delete primary_clock; primary_clock = 0;
858 delete secondary_clock; secondary_clock = 0;
859 delete _process_thread; _process_thread = 0;
860 delete time_info_box; time_info_box = 0;
861 delete meterbridge; meterbridge = 0;
862 delete luawindow; luawindow = 0;
863 delete editor; editor = 0;
864 delete mixer; mixer = 0;
865 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
867 delete gui_object_state; gui_object_state = 0;
868 delete main_window_visibility;
869 FastMeter::flush_pattern_cache ();
870 ArdourFader::flush_pattern_cache ();
874 /* Small trick to flush main-thread event pool.
875 * Other thread-pools are destroyed at pthread_exit(),
876 * but tmain thread termination is too late to trigger Pool::~Pool()
878 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.
879 delete ev->event_pool();
884 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
886 if (Splash::instance()) {
887 Splash::instance()->pop_back_for (win);
892 ARDOUR_UI::configure_timeout ()
894 if (last_configure_time == 0) {
895 /* no configure events yet */
899 /* force a gap of 0.5 seconds since the last configure event
902 if (get_microseconds() - last_configure_time < 500000) {
905 have_configure_timeout = false;
906 save_ardour_state ();
912 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
914 if (have_configure_timeout) {
915 last_configure_time = get_microseconds();
917 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
918 have_configure_timeout = true;
925 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
929 if (node.get_property ("roll", str)){
930 roll_controllable->set_id (str);
932 if (node.get_property ("stop", str)) {
933 stop_controllable->set_id (str);
935 if (node.get_property ("goto-start", str)) {
936 goto_start_controllable->set_id (str);
938 if (node.get_property ("goto-end", str)) {
939 goto_end_controllable->set_id (str);
941 if (node.get_property ("auto-loop", str)) {
942 auto_loop_controllable->set_id (str);
944 if (node.get_property ("play-selection", str)) {
945 play_selection_controllable->set_id (str);
947 if (node.get_property ("rec", str)) {
948 rec_controllable->set_id (str);
950 if (node.get_property ("shuttle", str)) {
951 shuttle_box.controllable()->set_id (str);
956 ARDOUR_UI::get_transport_controllable_state ()
958 XMLNode* node = new XMLNode(X_("TransportControllables"));
960 node->set_property (X_("roll"), roll_controllable->id());
961 node->set_property (X_("stop"), stop_controllable->id());
962 node->set_property (X_("goto-start"), goto_start_controllable->id());
963 node->set_property (X_("goto-end"), goto_end_controllable->id());
964 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
965 node->set_property (X_("play-selection"), play_selection_controllable->id());
966 node->set_property (X_("rec"), rec_controllable->id());
967 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
973 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
976 _session->save_state (snapshot_name);
981 ARDOUR_UI::autosave_session ()
983 if (g_main_depth() > 1) {
984 /* inside a recursive main loop,
985 give up because we may not be able to
991 if (!Config->get_periodic_safety_backups()) {
996 _session->maybe_write_autosave();
1003 ARDOUR_UI::session_dirty_changed ()
1010 ARDOUR_UI::update_autosave ()
1012 if (_session && _session->dirty()) {
1013 if (_autosave_connection.connected()) {
1014 _autosave_connection.disconnect();
1017 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1018 Config->get_periodic_safety_backup_interval() * 1000);
1021 if (_autosave_connection.connected()) {
1022 _autosave_connection.disconnect();
1028 ARDOUR_UI::check_announcements ()
1031 string _annc_filename;
1034 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1035 #elif defined PLATFORM_WINDOWS
1036 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1038 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1040 _annc_filename.append (VERSIONSTRING);
1042 _announce_string = "";
1044 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1045 FILE* fin = g_fopen (path.c_str(), "rb");
1047 while (!feof (fin)) {
1050 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1053 _announce_string.append (tmp, len);
1058 pingback (VERSIONSTRING, path);
1063 _hide_splash (gpointer arg)
1065 ((ARDOUR_UI*)arg)->hide_splash();
1070 ARDOUR_UI::starting ()
1072 Application* app = Application::instance ();
1073 const char *nsm_url;
1074 bool brand_new_user = ArdourStartup::required ();
1076 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1077 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1079 if (ARDOUR_COMMAND_LINE::check_announcements) {
1080 check_announcements ();
1085 /* we need to create this early because it may need to set the
1086 * audio backend end up.
1090 audio_midi_setup.get (true);
1092 std::cerr << "audio-midi engine setup failed."<< std::endl;
1096 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1097 nsm = new NSM_Client;
1098 if (!nsm->init (nsm_url)) {
1099 /* the ardour executable may have different names:
1101 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1102 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1103 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1105 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1107 const char *process_name = g_getenv ("ARDOUR_SELF");
1108 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1111 // wait for announce reply from nsm server
1112 for ( i = 0; i < 5000; ++i) {
1116 if (nsm->is_active()) {
1121 error << _("NSM server did not announce itself") << endmsg;
1124 // wait for open command from nsm server
1125 for ( i = 0; i < 5000; ++i) {
1127 Glib::usleep (1000);
1128 if (nsm->client_id ()) {
1134 error << _("NSM: no client ID provided") << endmsg;
1138 if (_session && nsm) {
1139 _session->set_nsm_state( nsm->is_active() );
1141 error << _("NSM: no session created") << endmsg;
1145 // nsm requires these actions disabled
1146 vector<string> action_names;
1147 action_names.push_back("SaveAs");
1148 action_names.push_back("Rename");
1149 action_names.push_back("New");
1150 action_names.push_back("Open");
1151 action_names.push_back("Recent");
1152 action_names.push_back("Close");
1154 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1155 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1157 act->set_sensitive (false);
1164 error << _("NSM: initialization failed") << endmsg;
1170 if (brand_new_user) {
1171 _initial_verbose_plugin_scan = true;
1176 _initial_verbose_plugin_scan = false;
1177 switch (s.response ()) {
1178 case Gtk::RESPONSE_OK:
1185 // TODO: maybe IFF brand_new_user
1186 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1187 std::string dspd (Config->get_default_session_parent_dir());
1188 Searchpath ds (ARDOUR::ardour_data_search_path());
1189 ds.add_subdirectory_to_paths ("sessions");
1190 vector<string> demos;
1191 find_files_matching_pattern (demos, ds, "*.tar.xz");
1193 ARDOUR::RecentSessions rs;
1194 ARDOUR::read_recent_sessions (rs);
1196 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1197 /* "demo-session" must be inside "demo-session.tar.xz"
1200 std::string name = basename_nosuffix (basename_nosuffix (*i));
1201 std::string path = Glib::build_filename (dspd, name);
1202 /* skip if session-dir already exists */
1203 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1206 /* skip sessions that are already in 'recent'.
1207 * eg. a new user changed <session-default-dir> shorly after installation
1209 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1210 if ((*r).first == name) {
1215 PBD::FileArchive ar (*i);
1216 if (0 == ar.inflate (dspd)) {
1217 store_recent_sessions (name, path);
1218 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1224 #ifdef NO_PLUGIN_STATE
1226 ARDOUR::RecentSessions rs;
1227 ARDOUR::read_recent_sessions (rs);
1229 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1231 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1233 /* already used Ardour, have sessions ... warn about plugin state */
1235 ArdourDialog d (_("Free/Demo Version Warning"), true);
1237 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1238 CheckButton c (_("Don't warn me about this again"));
1240 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"),
1241 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1242 _("It will not restore OR save any plugin settings"),
1243 _("If you load an existing session with plugin settings\n"
1244 "they will not be used and will be lost."),
1245 _("To get full access to updates without this limitation\n"
1246 "consider becoming a subscriber for a low cost every month.")));
1247 l.set_justify (JUSTIFY_CENTER);
1249 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1251 d.get_vbox()->pack_start (l, true, true);
1252 d.get_vbox()->pack_start (b, false, false, 12);
1253 d.get_vbox()->pack_start (c, false, false, 12);
1255 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1256 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1260 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1262 if (d.run () != RESPONSE_OK) {
1268 /* go get a session */
1270 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1272 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1273 std::cerr << "Cannot get session parameters."<< std::endl;
1280 WM::Manager::instance().show_visible ();
1282 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1283 * editor window, and we may want stuff to be hidden.
1285 _status_bar_visibility.update ();
1287 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1289 /* all other dialogs are created conditionally */
1295 ARDOUR_UI::check_memory_locking ()
1297 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1298 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1302 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1304 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1306 struct rlimit limits;
1308 long pages, page_size;
1310 size_t pages_len=sizeof(pages);
1311 if ((page_size = getpagesize()) < 0 ||
1312 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1314 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1319 ram = (int64_t) pages * (int64_t) page_size;
1322 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1326 if (limits.rlim_cur != RLIM_INFINITY) {
1328 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1332 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1333 "This might cause %1 to run out of memory before your system "
1334 "runs out of memory. \n\n"
1335 "You can view the memory limit with 'ulimit -l', "
1336 "and it is normally controlled by %2"),
1339 X_("/etc/login.conf")
1341 X_(" /etc/security/limits.conf")
1345 msg.set_default_response (RESPONSE_OK);
1347 VBox* vbox = msg.get_vbox();
1349 CheckButton cb (_("Do not show this window again"));
1350 hbox.pack_start (cb, true, false);
1351 vbox->pack_start (hbox);
1356 pop_back_splash (msg);
1360 if (cb.get_active()) {
1361 XMLNode node (X_("no-memory-warning"));
1362 Config->add_instant_xml (node);
1367 #endif // !__APPLE__
1372 ARDOUR_UI::queue_finish ()
1374 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1378 ARDOUR_UI::idle_finish ()
1381 return false; /* do not call again */
1388 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1390 if (_session->dirty()) {
1391 vector<string> actions;
1392 actions.push_back (_("Don't quit"));
1393 actions.push_back (_("Just quit"));
1394 actions.push_back (_("Save and quit"));
1395 switch (ask_about_saving_session(actions)) {
1400 /* use the default name */
1401 if (save_state_canfail ("")) {
1402 /* failed - don't quit */
1403 MessageDialog msg (_main_window,
1404 string_compose (_("\
1405 %1 was unable to save your session.\n\n\
1406 If you still wish to quit, please use the\n\n\
1407 \"Just quit\" option."), PROGRAM_NAME));
1408 pop_back_splash(msg);
1418 second_connection.disconnect ();
1419 point_one_second_connection.disconnect ();
1420 point_zero_something_second_connection.disconnect();
1421 fps_connection.disconnect();
1424 delete ARDOUR_UI::instance()->video_timeline;
1425 ARDOUR_UI::instance()->video_timeline = NULL;
1426 stop_video_server();
1428 /* Save state before deleting the session, as that causes some
1429 windows to be destroyed before their visible state can be
1432 save_ardour_state ();
1434 if (key_editor.get (false)) {
1435 key_editor->disconnect ();
1438 close_all_dialogs ();
1441 _session->set_clean ();
1442 _session->remove_pending_capture_state ();
1447 halt_connection.disconnect ();
1448 AudioEngine::instance()->stop ();
1449 #ifdef WINDOWS_VST_SUPPORT
1450 fst_stop_threading();
1456 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1458 ArdourDialog window (_("Unsaved Session"));
1459 Gtk::HBox dhbox; // the hbox for the image and text
1460 Gtk::Label prompt_label;
1461 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1465 assert (actions.size() >= 3);
1467 window.add_button (actions[0], RESPONSE_REJECT);
1468 window.add_button (actions[1], RESPONSE_APPLY);
1469 window.add_button (actions[2], RESPONSE_ACCEPT);
1471 window.set_default_response (RESPONSE_ACCEPT);
1473 Gtk::Button noquit_button (msg);
1474 noquit_button.set_name ("EditorGTKButton");
1478 if (_session->snap_name() == _session->name()) {
1479 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?"),
1480 _session->snap_name());
1482 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?"),
1483 _session->snap_name());
1486 prompt_label.set_text (prompt);
1487 prompt_label.set_name (X_("PrompterLabel"));
1488 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1490 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1491 dhbox.set_homogeneous (false);
1492 dhbox.pack_start (*dimage, false, false, 5);
1493 dhbox.pack_start (prompt_label, true, false, 5);
1494 window.get_vbox()->pack_start (dhbox);
1496 window.set_name (_("Prompter"));
1497 window.set_modal (true);
1498 window.set_resizable (false);
1501 prompt_label.show();
1506 ResponseType r = (ResponseType) window.run();
1511 case RESPONSE_ACCEPT: // save and get out of here
1513 case RESPONSE_APPLY: // get out of here
1524 ARDOUR_UI::every_second ()
1527 update_xrun_count ();
1528 update_buffer_load ();
1529 update_disk_space ();
1530 update_timecode_format ();
1531 update_peak_thread_work ();
1533 if (nsm && nsm->is_active ()) {
1536 if (!_was_dirty && _session->dirty ()) {
1540 else if (_was_dirty && !_session->dirty ()){
1548 ARDOUR_UI::every_point_one_seconds ()
1550 // TODO get rid of this..
1551 // ShuttleControl is updated directly via TransportStateChange signal
1555 ARDOUR_UI::every_point_zero_something_seconds ()
1557 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1559 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1560 float mpeak = editor_meter->update_meters();
1561 if (mpeak > editor_meter_max_peak) {
1562 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1563 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1570 ARDOUR_UI::set_fps_timeout_connection ()
1572 unsigned int interval = 40;
1573 if (!_session) return;
1574 if (_session->timecode_frames_per_second() != 0) {
1575 /* ideally we'll use a select() to sleep and not accumulate
1576 * idle time to provide a regular periodic signal.
1577 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1578 * However, that'll require a dedicated thread and cross-thread
1579 * signals to the GUI Thread..
1581 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1582 * _session->frame_rate() / _session->nominal_frame_rate()
1583 / _session->timecode_frames_per_second()
1585 #ifdef PLATFORM_WINDOWS
1586 // the smallest windows scheduler time-slice is ~15ms.
1587 // periodic GUI timeouts shorter than that will cause
1588 // WaitForSingleObject to spinlock (100% of one CPU Core)
1589 // and gtk never enters idle mode.
1590 // also changing timeBeginPeriod(1) does not affect that in
1591 // any beneficial way, so we just limit the max rate for now.
1592 interval = std::max(30u, interval); // at most ~33Hz.
1594 interval = std::max(8u, interval); // at most 120Hz.
1597 fps_connection.disconnect();
1598 Timers::set_fps_interval (interval);
1602 ARDOUR_UI::update_sample_rate (framecnt_t)
1606 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1608 if (!AudioEngine::instance()->connected()) {
1610 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1614 framecnt_t rate = AudioEngine::instance()->sample_rate();
1617 /* no sample rate available */
1618 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1621 if (fmod (rate, 1000.0) != 0.0) {
1622 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1623 (float) rate / 1000.0f,
1624 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1626 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1628 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1632 sample_rate_label.set_markup (buf);
1636 ARDOUR_UI::update_format ()
1639 format_label.set_text ("");
1644 s << _("File:") << X_(" <span foreground=\"green\">");
1646 switch (_session->config.get_native_file_header_format ()) {
1678 switch (_session->config.get_native_file_data_format ()) {
1692 format_label.set_markup (s.str ());
1696 ARDOUR_UI::update_xrun_count ()
1700 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1701 should also be changed.
1705 const unsigned int x = _session->get_xrun_count ();
1707 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1709 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1712 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1714 xrun_label.set_markup (buf);
1715 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1719 ARDOUR_UI::update_cpu_load ()
1723 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1724 should also be changed.
1727 double const c = AudioEngine::instance()->get_dsp_load ();
1728 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1729 cpu_load_label.set_markup (buf);
1733 ARDOUR_UI::update_peak_thread_work ()
1736 const int c = SourceFactory::peak_work_queue_length ();
1738 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1739 peak_thread_work_label.set_markup (buf);
1741 peak_thread_work_label.set_markup (X_(""));
1746 ARDOUR_UI::update_buffer_load ()
1750 uint32_t const playback = _session ? _session->playback_load () : 100;
1751 uint32_t const capture = _session ? _session->capture_load () : 100;
1753 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1754 should also be changed.
1760 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1761 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1762 playback <= 5 ? X_("red") : X_("green"),
1764 capture <= 5 ? X_("red") : X_("green"),
1768 buffer_load_label.set_markup (buf);
1770 buffer_load_label.set_text ("");
1775 ARDOUR_UI::count_recenabled_streams (Route& route)
1777 Track* track = dynamic_cast<Track*>(&route);
1778 if (track && track->rec_enable_control()->get_value()) {
1779 rec_enabled_streams += track->n_inputs().n_total();
1784 ARDOUR_UI::update_disk_space()
1786 if (_session == 0) {
1790 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1792 framecnt_t fr = _session->frame_rate();
1795 /* skip update - no SR available */
1800 /* Available space is unknown */
1801 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1802 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1803 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1805 rec_enabled_streams = 0;
1806 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1808 framecnt_t frames = opt_frames.get_value_or (0);
1810 if (rec_enabled_streams) {
1811 frames /= rec_enabled_streams;
1818 hrs = frames / (fr * 3600);
1821 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1823 frames -= hrs * fr * 3600;
1824 mins = frames / (fr * 60);
1825 frames -= mins * fr * 60;
1828 bool const low = (hrs == 0 && mins <= 30);
1832 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1833 low ? X_("red") : X_("green"),
1839 disk_space_label.set_markup (buf);
1843 ARDOUR_UI::update_timecode_format ()
1849 TimecodeSlave* tcslave;
1850 SyncSource sync_src = Config->get_sync_source();
1852 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1853 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1858 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1859 matching ? X_("green") : X_("red"),
1860 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1862 snprintf (buf, sizeof (buf), "TC: n/a");
1865 timecode_format_label.set_markup (buf);
1869 ARDOUR_UI::update_wall_clock ()
1873 static int last_min = -1;
1876 tm_now = localtime (&now);
1877 if (last_min != tm_now->tm_min) {
1879 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1880 wall_clock_label.set_text (buf);
1881 last_min = tm_now->tm_min;
1888 ARDOUR_UI::open_recent_session ()
1890 bool can_return = (_session != 0);
1892 SessionDialog recent_session_dialog;
1896 ResponseType r = (ResponseType) recent_session_dialog.run ();
1899 case RESPONSE_ACCEPT:
1903 recent_session_dialog.hide();
1910 recent_session_dialog.hide();
1914 std::string path = recent_session_dialog.session_folder();
1915 std::string state = recent_session_dialog.session_name (should_be_new);
1917 if (should_be_new == true) {
1921 _session_is_new = false;
1923 if (load_session (path, state) == 0) {
1932 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1934 if (!AudioEngine::instance()->connected()) {
1935 MessageDialog msg (parent, string_compose (
1936 _("%1 is not connected to any audio backend.\n"
1937 "You cannot open or close sessions in this condition"),
1939 pop_back_splash (msg);
1947 ARDOUR_UI::open_session ()
1949 if (!check_audioengine (_main_window)) {
1953 /* ardour sessions are folders */
1954 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1955 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1956 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1957 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1960 string session_parent_dir = Glib::path_get_dirname(_session->path());
1961 open_session_selector.set_current_folder(session_parent_dir);
1963 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1966 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1968 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1969 string default_session_folder = Config->get_default_session_parent_dir();
1970 open_session_selector.add_shortcut_folder (default_session_folder);
1972 catch (Glib::Error & e) {
1973 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1976 FileFilter session_filter;
1977 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1978 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1979 open_session_selector.add_filter (session_filter);
1981 FileFilter archive_filter;
1982 archive_filter.add_pattern (X_("*.tar.xz"));
1983 archive_filter.set_name (_("Session Archives"));
1985 open_session_selector.add_filter (archive_filter);
1987 open_session_selector.set_filter (session_filter);
1989 int response = open_session_selector.run();
1990 open_session_selector.hide ();
1992 if (response == Gtk::RESPONSE_CANCEL) {
1996 string session_path = open_session_selector.get_filename();
2000 if (session_path.length() > 0) {
2001 int rv = ARDOUR::inflate_session (session_path,
2002 Config->get_default_session_parent_dir(), path, name);
2004 _session_is_new = false;
2005 load_session (path, name);
2008 MessageDialog msg (_main_window,
2009 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2012 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2013 _session_is_new = isnew;
2014 load_session (path, name);
2020 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
2026 _session->vca_manager().create_vca (n, name_template);
2030 ARDOUR_UI::session_add_mixed_track (
2031 const ChanCount& input,
2032 const ChanCount& output,
2033 RouteGroup* route_group,
2035 const string& name_template,
2037 PluginInfoPtr instrument,
2038 Plugin::PresetRecord* pset,
2039 ARDOUR::PresentationInfo::order_t order)
2041 if (_session == 0) {
2042 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2046 if (Profile->get_mixbus ()) {
2051 list<boost::shared_ptr<MidiTrack> > tracks;
2052 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2054 if (tracks.size() != how_many) {
2055 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2060 display_insufficient_ports_message ();
2066 ARDOUR_UI::session_add_midi_bus (
2067 RouteGroup* route_group,
2069 const string& name_template,
2071 PluginInfoPtr instrument,
2072 Plugin::PresetRecord* pset,
2073 ARDOUR::PresentationInfo::order_t order)
2075 if (_session == 0) {
2076 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2080 if (Profile->get_mixbus ()) {
2086 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2087 if (routes.size() != how_many) {
2088 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2093 display_insufficient_ports_message ();
2099 ARDOUR_UI::session_add_midi_route (
2101 RouteGroup* route_group,
2103 const string& name_template,
2105 PluginInfoPtr instrument,
2106 Plugin::PresetRecord* pset,
2107 ARDOUR::PresentationInfo::order_t order)
2109 ChanCount one_midi_channel;
2110 one_midi_channel.set (DataType::MIDI, 1);
2113 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2115 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2120 ARDOUR_UI::session_add_audio_route (
2122 int32_t input_channels,
2123 int32_t output_channels,
2124 ARDOUR::TrackMode mode,
2125 RouteGroup* route_group,
2127 string const & name_template,
2129 ARDOUR::PresentationInfo::order_t order)
2131 list<boost::shared_ptr<AudioTrack> > tracks;
2134 if (_session == 0) {
2135 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2141 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2143 if (tracks.size() != how_many) {
2144 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2150 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2152 if (routes.size() != how_many) {
2153 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2160 display_insufficient_ports_message ();
2165 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2166 (*i)->set_strict_io (true);
2168 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2169 (*i)->set_strict_io (true);
2175 ARDOUR_UI::display_insufficient_ports_message ()
2177 MessageDialog msg (_main_window,
2178 string_compose (_("There are insufficient ports available\n\
2179 to create a new track or bus.\n\
2180 You should save %1, exit and\n\
2181 restart with more ports."), PROGRAM_NAME));
2182 pop_back_splash (msg);
2187 ARDOUR_UI::transport_goto_start ()
2190 _session->goto_start();
2192 /* force displayed area in editor to start no matter
2193 what "follow playhead" setting is.
2197 editor->center_screen (_session->current_start_frame ());
2203 ARDOUR_UI::transport_goto_zero ()
2206 _session->request_locate (0);
2208 /* force displayed area in editor to start no matter
2209 what "follow playhead" setting is.
2213 editor->reset_x_origin (0);
2219 ARDOUR_UI::transport_goto_wallclock ()
2221 if (_session && editor) {
2228 localtime_r (&now, &tmnow);
2230 framecnt_t frame_rate = _session->frame_rate();
2232 if (frame_rate == 0) {
2233 /* no frame rate available */
2237 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2238 frames += tmnow.tm_min * (60 * frame_rate);
2239 frames += tmnow.tm_sec * frame_rate;
2241 _session->request_locate (frames, _session->transport_rolling ());
2243 /* force displayed area in editor to start no matter
2244 what "follow playhead" setting is.
2248 editor->center_screen (frames);
2254 ARDOUR_UI::transport_goto_end ()
2257 framepos_t const frame = _session->current_end_frame();
2258 _session->request_locate (frame);
2260 /* force displayed area in editor to start no matter
2261 what "follow playhead" setting is.
2265 editor->center_screen (frame);
2271 ARDOUR_UI::transport_stop ()
2277 if (_session->is_auditioning()) {
2278 _session->cancel_audition ();
2282 _session->request_stop (false, true);
2285 /** Check if any tracks are record enabled. If none are, record enable all of them.
2286 * @return true if track record-enabled status was changed, false otherwise.
2289 ARDOUR_UI::trx_record_enable_all_tracks ()
2295 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2296 bool none_record_enabled = true;
2298 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2299 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2302 if (t->rec_enable_control()->get_value()) {
2303 none_record_enabled = false;
2308 if (none_record_enabled) {
2309 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2312 return none_record_enabled;
2316 ARDOUR_UI::transport_record (bool roll)
2319 switch (_session->record_status()) {
2320 case Session::Disabled:
2321 if (_session->ntracks() == 0) {
2322 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."));
2326 if (Profile->get_trx()) {
2327 roll = trx_record_enable_all_tracks ();
2329 _session->maybe_enable_record ();
2334 case Session::Recording:
2336 _session->request_stop();
2338 _session->disable_record (false, true);
2342 case Session::Enabled:
2343 _session->disable_record (false, true);
2349 ARDOUR_UI::transport_roll ()
2355 if (_session->is_auditioning()) {
2360 if (_session->config.get_external_sync()) {
2361 switch (Config->get_sync_source()) {
2365 /* transport controlled by the master */
2371 bool rolling = _session->transport_rolling();
2373 if (_session->get_play_loop()) {
2375 /* If loop playback is not a mode, then we should cancel
2376 it when this action is requested. If it is a mode
2377 we just leave it in place.
2380 if (!Config->get_loop_is_mode()) {
2381 /* XXX it is not possible to just leave seamless loop and keep
2382 playing at present (nov 4th 2009)
2384 if (!Config->get_seamless_loop()) {
2385 /* stop loop playback and stop rolling */
2386 _session->request_play_loop (false, true);
2387 } else if (rolling) {
2388 /* stop loop playback but keep rolling */
2389 _session->request_play_loop (false, false);
2393 } else if (_session->get_play_range () ) {
2394 /* stop playing a range if we currently are */
2395 _session->request_play_range (0, true);
2399 _session->request_transport_speed (1.0f);
2404 ARDOUR_UI::get_smart_mode() const
2406 return ( editor->get_smart_mode() );
2411 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2417 if (_session->is_auditioning()) {
2418 _session->cancel_audition ();
2422 if (_session->config.get_external_sync()) {
2423 switch (Config->get_sync_source()) {
2427 /* transport controlled by the master */
2432 bool rolling = _session->transport_rolling();
2433 bool affect_transport = true;
2435 if (rolling && roll_out_of_bounded_mode) {
2436 /* drop out of loop/range playback but leave transport rolling */
2437 if (_session->get_play_loop()) {
2438 if (_session->actively_recording()) {
2440 /* just stop using the loop, then actually stop
2443 _session->request_play_loop (false, affect_transport);
2446 if (Config->get_seamless_loop()) {
2447 /* the disk buffers contain copies of the loop - we can't
2448 just keep playing, so stop the transport. the user
2449 can restart as they wish.
2451 affect_transport = true;
2453 /* disk buffers are normal, so we can keep playing */
2454 affect_transport = false;
2456 _session->request_play_loop (false, affect_transport);
2458 } else if (_session->get_play_range ()) {
2459 affect_transport = false;
2460 _session->request_play_range (0, true);
2464 if (affect_transport) {
2466 _session->request_stop (with_abort, true);
2468 } else if (!with_abort) { /* with_abort == true means the
2469 * command was intended to stop
2470 * transport, not start.
2473 /* the only external sync condition we can be in here
2474 * would be Engine (JACK) sync, in which case we still
2478 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
2479 _session->request_play_range (&editor->get_selection().time, true);
2480 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2482 _session->request_transport_speed (1.0f);
2488 ARDOUR_UI::toggle_session_auto_loop ()
2494 Location * looploc = _session->locations()->auto_loop_location();
2500 if (_session->get_play_loop()) {
2502 /* looping enabled, our job is to disable it */
2504 _session->request_play_loop (false);
2508 /* looping not enabled, our job is to enable it.
2510 loop-is-NOT-mode: this action always starts the transport rolling.
2511 loop-IS-mode: this action simply sets the loop play mechanism, but
2512 does not start transport.
2514 if (Config->get_loop_is_mode()) {
2515 _session->request_play_loop (true, false);
2517 _session->request_play_loop (true, true);
2521 //show the loop markers
2522 looploc->set_hidden (false, this);
2526 ARDOUR_UI::transport_play_selection ()
2532 editor->play_selection ();
2536 ARDOUR_UI::transport_play_preroll ()
2541 editor->play_with_preroll ();
2545 ARDOUR_UI::transport_rec_preroll ()
2550 editor->rec_with_preroll ();
2554 ARDOUR_UI::transport_rec_count_in ()
2559 editor->rec_with_count_in ();
2563 ARDOUR_UI::transport_rewind (int option)
2565 float current_transport_speed;
2568 current_transport_speed = _session->transport_speed();
2570 if (current_transport_speed >= 0.0f) {
2573 _session->request_transport_speed (-1.0f);
2576 _session->request_transport_speed (-4.0f);
2579 _session->request_transport_speed (-0.5f);
2584 _session->request_transport_speed (current_transport_speed * 1.5f);
2590 ARDOUR_UI::transport_forward (int option)
2596 float current_transport_speed = _session->transport_speed();
2598 if (current_transport_speed <= 0.0f) {
2601 _session->request_transport_speed (1.0f);
2604 _session->request_transport_speed (4.0f);
2607 _session->request_transport_speed (0.5f);
2612 _session->request_transport_speed (current_transport_speed * 1.5f);
2617 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2623 boost::shared_ptr<Route> r;
2625 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2627 boost::shared_ptr<Track> t;
2629 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2630 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2636 ARDOUR_UI::map_transport_state ()
2639 auto_loop_button.unset_active_state ();
2640 play_selection_button.unset_active_state ();
2641 roll_button.unset_active_state ();
2642 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2643 layered_button.set_sensitive (false);
2647 shuttle_box.map_transport_state ();
2649 float sp = _session->transport_speed();
2655 if (_session->get_play_range()) {
2657 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2658 roll_button.unset_active_state ();
2659 auto_loop_button.unset_active_state ();
2661 } else if (_session->get_play_loop ()) {
2663 auto_loop_button.set_active (true);
2664 play_selection_button.set_active (false);
2665 if (Config->get_loop_is_mode()) {
2666 roll_button.set_active (true);
2668 roll_button.set_active (false);
2673 roll_button.set_active (true);
2674 play_selection_button.set_active (false);
2675 auto_loop_button.set_active (false);
2678 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2679 /* light up both roll and play-selection if they are joined */
2680 roll_button.set_active (true);
2681 play_selection_button.set_active (true);
2683 layered_button.set_sensitive (!_session->actively_recording ());
2685 stop_button.set_active (false);
2689 layered_button.set_sensitive (true);
2690 stop_button.set_active (true);
2691 roll_button.set_active (false);
2692 play_selection_button.set_active (false);
2693 if (Config->get_loop_is_mode ()) {
2694 auto_loop_button.set_active (_session->get_play_loop());
2696 auto_loop_button.set_active (false);
2698 update_disk_space ();
2703 ARDOUR_UI::blink_handler (bool blink_on)
2705 transport_rec_enable_blink (blink_on);
2706 sync_blink (blink_on);
2708 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2711 error_blink (blink_on);
2712 solo_blink (blink_on);
2713 audition_blink (blink_on);
2714 feedback_blink (blink_on);
2718 ARDOUR_UI::update_clocks ()
2720 if (!_session) return;
2722 if (editor && !editor->dragging_playhead()) {
2723 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2728 ARDOUR_UI::start_clocking ()
2730 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2731 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2733 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2738 ARDOUR_UI::stop_clocking ()
2740 clock_signal_connection.disconnect ();
2744 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2748 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2750 label->set_text (buf);
2751 bar->set_fraction (fraction);
2753 /* process events, redraws, etc. */
2755 while (gtk_events_pending()) {
2756 gtk_main_iteration ();
2759 return true; /* continue with save-as */
2763 ARDOUR_UI::save_session_as ()
2769 if (_session->dirty()) {
2770 vector<string> actions;
2771 actions.push_back (_("Abort save-as"));
2772 actions.push_back (_("Don't save now, just save-as"));
2773 actions.push_back (_("Save it first"));
2774 switch (ask_about_saving_session(actions)) {
2779 if (save_state_canfail ("")) {
2780 MessageDialog msg (_main_window,
2781 string_compose (_("\
2782 %1 was unable to save your session.\n\n\
2783 If you still wish to proceeed, please use the\n\n\
2784 \"Don't save now\" option."), PROGRAM_NAME));
2785 pop_back_splash(msg);
2791 _session->remove_pending_capture_state ();
2796 if (!save_as_dialog) {
2797 save_as_dialog = new SaveAsDialog;
2800 save_as_dialog->set_name (_session->name());
2802 int response = save_as_dialog->run ();
2804 save_as_dialog->hide ();
2807 case Gtk::RESPONSE_OK:
2816 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2817 sa.new_name = save_as_dialog->new_name ();
2818 sa.switch_to = save_as_dialog->switch_to();
2819 sa.copy_media = save_as_dialog->copy_media();
2820 sa.copy_external = save_as_dialog->copy_external();
2821 sa.include_media = save_as_dialog->include_media ();
2823 /* Only bother with a progress dialog if we're going to copy
2824 media into the save-as target. Without that choice, this
2825 will be very fast because we're only talking about a few kB's to
2826 perhaps a couple of MB's of data.
2829 ArdourDialog progress_dialog (_("Save As"), true);
2832 if (sa.include_media && sa.copy_media) {
2834 Gtk::Label* label = manage (new Gtk::Label());
2835 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2837 progress_dialog.get_vbox()->pack_start (*label);
2838 progress_dialog.get_vbox()->pack_start (*progress_bar);
2840 progress_bar->show ();
2842 /* this signal will be emitted from within this, the calling thread,
2843 * after every file is copied. It provides information on percentage
2844 * complete (in terms of total data to copy), the number of files
2845 * copied so far, and the total number to copy.
2848 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2850 progress_dialog.show_all ();
2851 progress_dialog.present ();
2854 if (_session->save_as (sa)) {
2856 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2860 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2861 * the trick is this: if the new session was copy with media included,
2862 * then Session::save_as() will have already done a neat trick to avoid
2863 * us having to unload and load the new state. But if the media was not
2864 * included, then this is required (it avoids us having to otherwise
2865 * drop all references to media (sources).
2868 if (!sa.include_media && sa.switch_to) {
2869 unload_session (false);
2870 load_session (sa.final_session_folder_name, sa.new_name);
2875 ARDOUR_UI::archive_session ()
2883 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2885 SessionArchiveDialog sad;
2886 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2887 int response = sad.run ();
2889 if (response != Gtk::RESPONSE_OK) {
2894 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2895 MessageDialog msg (_("Session Archiving failed."));
2901 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2905 struct tm local_time;
2908 localtime_r (&n, &local_time);
2909 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2910 if (switch_to_it && _session->dirty ()) {
2911 save_state_canfail ("");
2914 save_state (timebuf, switch_to_it);
2919 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2923 prompter.get_result (snapname);
2925 bool do_save = (snapname.length() != 0);
2928 char illegal = Session::session_name_is_legal(snapname);
2930 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2931 "snapshot names may not contain a '%1' character"), illegal));
2937 vector<std::string> p;
2938 get_state_files_in_directory (_session->session_directory().root_path(), p);
2939 vector<string> n = get_file_names_no_extension (p);
2941 if (find (n.begin(), n.end(), snapname) != n.end()) {
2943 do_save = overwrite_file_dialog (prompter,
2944 _("Confirm Snapshot Overwrite"),
2945 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2949 save_state (snapname, switch_to_it);
2959 /** Ask the user for the name of a new snapshot and then take it.
2963 ARDOUR_UI::snapshot_session (bool switch_to_it)
2965 if (switch_to_it && _session->dirty()) {
2966 vector<string> actions;
2967 actions.push_back (_("Abort saving snapshot"));
2968 actions.push_back (_("Don't save now, just snapshot"));
2969 actions.push_back (_("Save it first"));
2970 switch (ask_about_saving_session(actions)) {
2975 if (save_state_canfail ("")) {
2976 MessageDialog msg (_main_window,
2977 string_compose (_("\
2978 %1 was unable to save your session.\n\n\
2979 If you still wish to proceeed, please use the\n\n\
2980 \"Don't save now\" option."), PROGRAM_NAME));
2981 pop_back_splash(msg);
2987 _session->remove_pending_capture_state ();
2992 Prompter prompter (true);
2993 prompter.set_name ("Prompter");
2994 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2996 prompter.set_title (_("Snapshot and switch"));
2997 prompter.set_prompt (_("New session name"));
2999 prompter.set_title (_("Take Snapshot"));
3000 prompter.set_prompt (_("Name of new snapshot"));
3004 prompter.set_initial_text (_session->snap_name());
3006 Glib::DateTime tm (g_date_time_new_now_local ());
3007 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
3010 bool finished = false;
3012 switch (prompter.run()) {
3013 case RESPONSE_ACCEPT:
3015 finished = process_snapshot_session_prompter (prompter, switch_to_it);
3026 /** Ask the user for a new session name and then rename the session to it.
3030 ARDOUR_UI::rename_session ()
3036 Prompter prompter (true);
3039 prompter.set_name ("Prompter");
3040 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3041 prompter.set_title (_("Rename Session"));
3042 prompter.set_prompt (_("New session name"));
3045 switch (prompter.run()) {
3046 case RESPONSE_ACCEPT:
3048 prompter.get_result (name);
3050 bool do_rename = (name.length() != 0);
3053 char illegal = Session::session_name_is_legal (name);
3056 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3057 "session names may not contain a '%1' character"), illegal));
3062 switch (_session->rename (name)) {
3064 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3065 msg.set_position (WIN_POS_MOUSE);
3073 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3074 msg.set_position (WIN_POS_MOUSE);
3090 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3092 if (!_session || _session->deletion_in_progress()) {
3096 XMLNode* node = new XMLNode (X_("UI"));
3098 WM::Manager::instance().add_state (*node);
3100 node->add_child_nocopy (gui_object_state->get_state());
3102 _session->add_extra_xml (*node);
3104 if (export_video_dialog) {
3105 _session->add_extra_xml (export_video_dialog->get_state());
3108 save_state_canfail (name, switch_to_it);
3112 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3117 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3122 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3127 ARDOUR_UI::primary_clock_value_changed ()
3130 _session->request_locate (primary_clock->current_time ());
3135 ARDOUR_UI::big_clock_value_changed ()
3138 _session->request_locate (big_clock->current_time ());
3143 ARDOUR_UI::secondary_clock_value_changed ()
3146 _session->request_locate (secondary_clock->current_time ());
3151 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3153 if (_session == 0) {
3157 if (_session->step_editing()) {
3161 Session::RecordState const r = _session->record_status ();
3162 bool const h = _session->have_rec_enabled_track ();
3164 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3166 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3168 rec_button.set_active_state (Gtkmm2ext::Off);
3170 } else if (r == Session::Recording && h) {
3171 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3173 rec_button.unset_active_state ();
3178 ARDOUR_UI::process_save_template_prompter (Prompter& prompter)
3182 prompter.get_result (name);
3184 if (name.length()) {
3185 int failed = _session->save_template (name);
3187 if (failed == -2) { /* file already exists. */
3188 bool overwrite = overwrite_file_dialog (prompter,
3189 _("Confirm Template Overwrite"),
3190 _("A template already exists with that name. Do you want to overwrite it?"));
3193 _session->save_template (name, true);
3205 ARDOUR_UI::save_template ()
3207 Prompter prompter (true);
3209 if (!check_audioengine (_main_window)) {
3213 prompter.set_name (X_("Prompter"));
3214 prompter.set_title (_("Save Template"));
3215 prompter.set_prompt (_("Name for template:"));
3216 prompter.set_initial_text(_session->name() + _("-template"));
3217 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3219 bool finished = false;
3221 switch (prompter.run()) {
3222 case RESPONSE_ACCEPT:
3223 finished = process_save_template_prompter (prompter);
3233 void ARDOUR_UI::manage_templates ()
3240 ARDOUR_UI::edit_metadata ()
3242 SessionMetadataEditor dialog;
3243 dialog.set_session (_session);
3244 dialog.grab_focus ();
3249 ARDOUR_UI::import_metadata ()
3251 SessionMetadataImporter dialog;
3252 dialog.set_session (_session);
3257 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3259 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3261 MessageDialog msg (str,
3263 Gtk::MESSAGE_WARNING,
3264 Gtk::BUTTONS_YES_NO,
3268 msg.set_name (X_("OpenExistingDialog"));
3269 msg.set_title (_("Open Existing Session"));
3270 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3271 msg.set_position (Gtk::WIN_POS_CENTER);
3272 pop_back_splash (msg);
3274 switch (msg.run()) {
3283 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3285 BusProfile bus_profile;
3289 bus_profile.master_out_channels = 2;
3290 bus_profile.input_ac = AutoConnectPhysical;
3291 bus_profile.output_ac = AutoConnectMaster;
3292 bus_profile.requested_physical_in = 0; // use all available
3293 bus_profile.requested_physical_out = 0; // use all available
3297 /* get settings from advanced section of NSD */
3299 if (sd.create_master_bus()) {
3300 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3302 bus_profile.master_out_channels = 0;
3305 if (sd.connect_inputs()) {
3306 bus_profile.input_ac = AutoConnectPhysical;
3308 bus_profile.input_ac = AutoConnectOption (0);
3311 bus_profile.output_ac = AutoConnectOption (0);
3313 if (sd.connect_outputs ()) {
3314 if (sd.connect_outs_to_master()) {
3315 bus_profile.output_ac = AutoConnectMaster;
3316 } else if (sd.connect_outs_to_physical()) {
3317 bus_profile.output_ac = AutoConnectPhysical;
3321 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3322 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3325 if (build_session (session_path, session_name, bus_profile)) {
3333 ARDOUR_UI::load_from_application_api (const std::string& path)
3335 /* OS X El Capitan (and probably later) now somehow passes the command
3336 line arguments to an app via the openFile delegate protocol. Ardour
3337 already does its own command line processing, and having both
3338 pathways active causes crashes. So, if the command line was already
3339 set, do nothing here.
3342 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3346 ARDOUR_COMMAND_LINE::session_name = path;
3348 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3350 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3352 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3353 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3354 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3355 * -> SessionDialog is not displayed
3358 if (_session_dialog) {
3359 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3360 std::string session_path = path;
3361 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3362 session_path = Glib::path_get_dirname (session_path);
3364 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3365 _session_dialog->set_provided_session (session_name, session_path);
3366 _session_dialog->response (RESPONSE_NONE);
3367 _session_dialog->hide();
3372 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3373 /* /path/to/foo => /path/to/foo, foo */
3374 rv = load_session (path, basename_nosuffix (path));
3376 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3377 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3380 // if load_session fails -> pop up SessionDialog.
3382 ARDOUR_COMMAND_LINE::session_name = "";
3384 if (get_session_parameters (true, false)) {
3390 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3392 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3394 string session_name;
3395 string session_path;
3396 string template_name;
3398 bool likely_new = false;
3399 bool cancel_not_quit;
3401 /* deal with any existing DIRTY session now, rather than later. don't
3402 * treat a non-dirty session this way, so that it stays visible
3403 * as we bring up the new session dialog.
3406 if (_session && ARDOUR_UI::instance()->video_timeline) {
3407 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3410 /* if there is already a session, relabel the button
3411 on the SessionDialog so that we don't Quit directly
3413 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3415 if (_session && _session->dirty()) {
3416 if (unload_session (false)) {
3417 /* unload cancelled by user */
3420 ARDOUR_COMMAND_LINE::session_name = "";
3423 if (!load_template.empty()) {
3424 should_be_new = true;
3425 template_name = load_template;
3428 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3429 session_path = ARDOUR_COMMAND_LINE::session_name;
3431 if (!session_path.empty()) {
3432 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3433 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3434 /* session/snapshot file, change path to be dir */
3435 session_path = Glib::path_get_dirname (session_path);
3440 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3442 _session_dialog = &session_dialog;
3445 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3447 /* if they named a specific statefile, use it, otherwise they are
3448 just giving a session folder, and we want to use it as is
3449 to find the session.
3452 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3454 if (suffix != string::npos) {
3455 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3456 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3457 session_name = Glib::path_get_basename (session_name);
3459 session_path = ARDOUR_COMMAND_LINE::session_name;
3460 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3465 session_dialog.clear_given ();
3468 if (should_be_new || session_name.empty()) {
3469 /* need the dialog to get info from user */
3471 cerr << "run dialog\n";
3473 switch (session_dialog.run()) {
3474 case RESPONSE_ACCEPT:
3477 /* this is used for async * app->ShouldLoad(). */
3478 continue; // while loop
3481 if (quit_on_cancel) {
3482 ARDOUR_UI::finish ();
3483 Gtkmm2ext::Application::instance()->cleanup();
3485 pthread_cancel_all ();
3486 return -1; // caller is responsible to call exit()
3492 session_dialog.hide ();
3495 /* if we run the startup dialog again, offer more than just "new session" */
3497 should_be_new = false;
3499 session_name = session_dialog.session_name (likely_new);
3500 session_path = session_dialog.session_folder ();
3507 int rv = ARDOUR::inflate_session (session_name,
3508 Config->get_default_session_parent_dir(), session_path, session_name);
3510 MessageDialog msg (session_dialog,
3511 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3516 session_dialog.set_provided_session (session_name, session_path);
3520 // XXX check archive, inflate
3521 string::size_type suffix = session_name.find (statefile_suffix);
3523 if (suffix != string::npos) {
3524 session_name = session_name.substr (0, suffix);
3527 /* this shouldn't happen, but we catch it just in case it does */
3529 if (session_name.empty()) {
3533 if (session_dialog.use_session_template()) {
3534 template_name = session_dialog.session_template_name();
3535 _session_is_new = true;
3538 if (session_name[0] == G_DIR_SEPARATOR ||
3539 #ifdef PLATFORM_WINDOWS
3540 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3542 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3543 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3548 /* absolute path or cwd-relative path specified for session name: infer session folder
3549 from what was given.
3552 session_path = Glib::path_get_dirname (session_name);
3553 session_name = Glib::path_get_basename (session_name);
3557 session_path = session_dialog.session_folder();
3559 char illegal = Session::session_name_is_legal (session_name);
3562 MessageDialog msg (session_dialog,
3563 string_compose (_("To ensure compatibility with various systems\n"
3564 "session names may not contain a '%1' character"),
3567 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3572 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3575 if (likely_new && !nsm) {
3577 std::string existing = Glib::build_filename (session_path, session_name);
3579 if (!ask_about_loading_existing_session (existing)) {
3580 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3585 _session_is_new = false;
3590 pop_back_splash (session_dialog);
3591 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3593 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3597 char illegal = Session::session_name_is_legal(session_name);
3600 pop_back_splash (session_dialog);
3601 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3602 "session names may not contain a '%1' character"), illegal));
3604 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3608 _session_is_new = true;
3611 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3613 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3614 meta_session_setup (template_name.substr (11));
3616 } else if (likely_new && template_name.empty()) {
3618 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3622 ret = load_session (session_path, session_name, template_name);
3625 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3629 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3630 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3634 /* clear this to avoid endless attempts to load the
3638 ARDOUR_COMMAND_LINE::session_name = "";
3642 _session_dialog = NULL;
3648 ARDOUR_UI::close_session()
3650 if (!check_audioengine (_main_window)) {
3654 if (unload_session (true)) {
3658 ARDOUR_COMMAND_LINE::session_name = "";
3660 if (get_session_parameters (true, false)) {
3665 /** @param snap_name Snapshot name (without .ardour suffix).
3666 * @return -2 if the load failed because we are not connected to the AudioEngine.
3669 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3671 /* load_session calls flush_pending() which allows
3672 * GUI interaction and potentially loading another session
3673 * (that was easy via snapshot sidebar).
3674 * Recursing into load_session() from load_session() and recusive
3675 * event loops causes all kind of crashes.
3677 assert (!session_load_in_progress);
3678 if (session_load_in_progress) {
3681 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3683 Session *new_session;
3688 unload_status = unload_session ();
3690 if (unload_status < 0) {
3692 } else if (unload_status > 0) {
3698 session_loaded = false;
3700 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3703 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3706 /* this one is special */
3708 catch (AudioEngine::PortRegistrationFailure& err) {
3710 MessageDialog msg (err.what(),
3713 Gtk::BUTTONS_CLOSE);
3715 msg.set_title (_("Port Registration Error"));
3716 msg.set_secondary_text (_("Click the Close button to try again."));
3717 msg.set_position (Gtk::WIN_POS_CENTER);
3718 pop_back_splash (msg);
3721 int response = msg.run ();
3726 case RESPONSE_CANCEL:
3733 catch (SessionException e) {
3734 MessageDialog msg (string_compose(
3735 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3736 path, snap_name, e.what()),
3741 msg.set_title (_("Loading Error"));
3742 msg.set_position (Gtk::WIN_POS_CENTER);
3743 pop_back_splash (msg);
3755 MessageDialog msg (string_compose(
3756 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3762 msg.set_title (_("Loading Error"));
3763 msg.set_position (Gtk::WIN_POS_CENTER);
3764 pop_back_splash (msg);
3776 list<string> const u = new_session->unknown_processors ();
3778 MissingPluginDialog d (_session, u);
3783 if (!new_session->writable()) {
3784 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3789 msg.set_title (_("Read-only Session"));
3790 msg.set_position (Gtk::WIN_POS_CENTER);
3791 pop_back_splash (msg);
3798 /* Now the session been created, add the transport controls */
3799 new_session->add_controllable(roll_controllable);
3800 new_session->add_controllable(stop_controllable);
3801 new_session->add_controllable(goto_start_controllable);
3802 new_session->add_controllable(goto_end_controllable);
3803 new_session->add_controllable(auto_loop_controllable);
3804 new_session->add_controllable(play_selection_controllable);
3805 new_session->add_controllable(rec_controllable);
3807 set_session (new_session);
3809 session_loaded = true;
3812 _session->set_clean ();
3815 #ifdef WINDOWS_VST_SUPPORT
3816 fst_stop_threading();
3820 Timers::TimerSuspender t;
3824 #ifdef WINDOWS_VST_SUPPORT
3825 fst_start_threading();
3829 if (!mix_template.empty ()) {
3830 /* if mix_template is given, assume this is a new session */
3831 string metascript = Glib::build_filename (mix_template, "template.lua");
3832 meta_session_setup (metascript);
3837 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3838 * which is queued by set_session().
3839 * If session-loading fails we hide it explicitly.
3840 * This covers both cases in a central place.
3849 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3851 Session *new_session;
3854 session_loaded = false;
3855 x = unload_session ();
3863 _session_is_new = true;
3866 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3869 catch (SessionException e) {
3870 cerr << "Here are the errors associated with this failed session:\n";
3872 cerr << "---------\n";
3873 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3874 msg.set_title (_("Loading Error"));
3875 msg.set_position (Gtk::WIN_POS_CENTER);
3876 pop_back_splash (msg);
3881 cerr << "Here are the errors associated with this failed session:\n";
3883 cerr << "---------\n";
3884 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3885 msg.set_title (_("Loading Error"));
3886 msg.set_position (Gtk::WIN_POS_CENTER);
3887 pop_back_splash (msg);
3892 /* Give the new session the default GUI state, if such things exist */
3895 n = Config->instant_xml (X_("Editor"));
3897 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3898 new_session->add_instant_xml (*n, false);
3900 n = Config->instant_xml (X_("Mixer"));
3902 new_session->add_instant_xml (*n, false);
3905 n = Config->instant_xml (X_("Preferences"));
3907 new_session->add_instant_xml (*n, false);
3910 /* Put the playhead at 0 and scroll fully left */
3911 n = new_session->instant_xml (X_("Editor"));
3913 n->set_property (X_("playhead"), X_("0"));
3914 n->set_property (X_("left-frame"), X_("0"));
3917 set_session (new_session);
3919 session_loaded = true;
3921 new_session->save_state(new_session->name());
3927 static void _lua_print (std::string s) {
3929 std::cout << "LuaInstance: " << s << "\n";
3931 PBD::info << "LuaInstance: " << s << endmsg;
3935 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3937 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3942 lua.Print.connect (&_lua_print);
3945 lua_State* L = lua.getState();
3946 LuaInstance::register_classes (L);
3947 LuaBindings::set_session (L, _session);
3948 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3949 lua_setglobal (L, "Editor");
3951 lua.do_command ("function ardour () end");
3952 lua.do_file (script_path);
3955 luabridge::LuaRef fn = luabridge::getGlobal (L, "session_setup");
3956 if (fn.isFunction()) {
3959 } catch (luabridge::LuaException const& e) {
3960 cerr << "LuaException:" << e.what () << endl;
3965 ARDOUR_UI::launch_chat ()
3967 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3969 dialog.set_title (_("About the Chat"));
3970 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."));
3972 switch (dialog.run()) {
3975 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3976 #elif defined PLATFORM_WINDOWS
3977 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3979 open_uri("http://webchat.freenode.net/?channels=ardour");
3988 ARDOUR_UI::launch_manual ()
3990 PBD::open_uri (Config->get_tutorial_manual_url());
3994 ARDOUR_UI::launch_reference ()
3996 PBD::open_uri (Config->get_reference_manual_url());
4000 ARDOUR_UI::launch_tracker ()
4002 PBD::open_uri ("http://tracker.ardour.org");
4006 ARDOUR_UI::launch_subscribe ()
4008 PBD::open_uri ("https://community.ardour.org/s/subscribe");
4012 ARDOUR_UI::launch_cheat_sheet ()
4015 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
4017 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
4022 ARDOUR_UI::launch_website ()
4024 PBD::open_uri ("http://ardour.org");
4028 ARDOUR_UI::launch_website_dev ()
4030 PBD::open_uri ("http://ardour.org/development.html");
4034 ARDOUR_UI::launch_forums ()
4036 PBD::open_uri ("https://community.ardour.org/forums");
4040 ARDOUR_UI::launch_howto_report ()
4042 PBD::open_uri ("http://ardour.org/reporting_bugs");
4046 ARDOUR_UI::loading_message (const std::string& msg)
4048 if (ARDOUR_COMMAND_LINE::no_splash) {
4056 splash->message (msg);
4060 ARDOUR_UI::show_splash ()
4064 splash = new Splash;
4074 ARDOUR_UI::hide_splash ()
4081 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4085 removed = rep.paths.size();
4088 MessageDialog msgd (_main_window,
4089 _("No files were ready for clean-up"),
4093 msgd.set_title (_("Clean-up"));
4094 msgd.set_secondary_text (_("If this seems surprising, \n\
4095 check for any existing snapshots.\n\
4096 These may still include regions that\n\
4097 require some unused files to continue to exist."));
4103 ArdourDialog results (_("Clean-up"), true, false);
4105 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4106 CleanupResultsModelColumns() {
4110 Gtk::TreeModelColumn<std::string> visible_name;
4111 Gtk::TreeModelColumn<std::string> fullpath;
4115 CleanupResultsModelColumns results_columns;
4116 Glib::RefPtr<Gtk::ListStore> results_model;
4117 Gtk::TreeView results_display;
4119 results_model = ListStore::create (results_columns);
4120 results_display.set_model (results_model);
4121 results_display.append_column (list_title, results_columns.visible_name);
4123 results_display.set_name ("CleanupResultsList");
4124 results_display.set_headers_visible (true);
4125 results_display.set_headers_clickable (false);
4126 results_display.set_reorderable (false);
4128 Gtk::ScrolledWindow list_scroller;
4131 Gtk::HBox dhbox; // the hbox for the image and text
4132 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4133 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4135 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4137 const string dead_directory = _session->session_directory().dead_path();
4140 %1 - number of files removed
4141 %2 - location of "dead"
4142 %3 - size of files affected
4143 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4146 const char* bprefix;
4147 double space_adjusted = 0;
4149 if (rep.space < 1000) {
4151 space_adjusted = rep.space;
4152 } else if (rep.space < 1000000) {
4153 bprefix = _("kilo");
4154 space_adjusted = floorf((float)rep.space / 1000.0);
4155 } else if (rep.space < 1000000 * 1000) {
4156 bprefix = _("mega");
4157 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4159 bprefix = _("giga");
4160 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4164 txt.set_markup (string_compose (P_("\
4165 The following file was deleted from %2,\n\
4166 releasing %3 %4bytes of disk space", "\
4167 The following %1 files were deleted from %2,\n\
4168 releasing %3 %4bytes of disk space", removed),
4169 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4171 txt.set_markup (string_compose (P_("\
4172 The following file was not in use and \n\
4173 has been moved to: %2\n\n\
4174 After a restart of %5\n\n\
4175 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4176 will release an additional %3 %4bytes of disk space.\n", "\
4177 The following %1 files were not in use and \n\
4178 have been moved to: %2\n\n\
4179 After a restart of %5\n\n\
4180 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4181 will release an additional %3 %4bytes of disk space.\n", removed),
4182 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4185 dhbox.pack_start (*dimage, true, false, 5);
4186 dhbox.pack_start (txt, true, false, 5);
4188 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4189 TreeModel::Row row = *(results_model->append());
4190 row[results_columns.visible_name] = *i;
4191 row[results_columns.fullpath] = *i;
4194 list_scroller.add (results_display);
4195 list_scroller.set_size_request (-1, 150);
4196 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4198 dvbox.pack_start (dhbox, true, false, 5);
4199 dvbox.pack_start (list_scroller, true, false, 5);
4200 ddhbox.pack_start (dvbox, true, false, 5);
4202 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4203 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4204 results.set_default_response (RESPONSE_CLOSE);
4205 results.set_position (Gtk::WIN_POS_MOUSE);
4207 results_display.show();
4208 list_scroller.show();
4215 //results.get_vbox()->show();
4216 results.set_resizable (false);
4223 ARDOUR_UI::cleanup ()
4225 if (_session == 0) {
4226 /* shouldn't happen: menu item is insensitive */
4231 MessageDialog checker (_("Are you sure you want to clean-up?"),
4233 Gtk::MESSAGE_QUESTION,
4236 checker.set_title (_("Clean-up"));
4238 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4239 ALL undo/redo information will be lost if you clean-up.\n\
4240 Clean-up will move all unused files to a \"dead\" location."));
4242 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4243 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4244 checker.set_default_response (RESPONSE_CANCEL);
4246 checker.set_name (_("CleanupDialog"));
4247 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4248 checker.set_position (Gtk::WIN_POS_MOUSE);
4250 switch (checker.run()) {
4251 case RESPONSE_ACCEPT:
4257 ARDOUR::CleanupReport rep;
4259 editor->prepare_for_cleanup ();
4261 /* do not allow flush until a session is reloaded */
4263 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4265 act->set_sensitive (false);
4268 if (_session->cleanup_sources (rep)) {
4269 editor->finish_cleanup ();
4273 editor->finish_cleanup ();
4276 display_cleanup_results (rep, _("Cleaned Files"), false);
4280 ARDOUR_UI::flush_trash ()
4282 if (_session == 0) {
4283 /* shouldn't happen: menu item is insensitive */
4287 ARDOUR::CleanupReport rep;
4289 if (_session->cleanup_trash_sources (rep)) {
4293 display_cleanup_results (rep, _("deleted file"), true);
4297 ARDOUR_UI::cleanup_peakfiles ()
4299 if (_session == 0) {
4300 /* shouldn't happen: menu item is insensitive */
4304 if (! _session->can_cleanup_peakfiles ()) {
4308 // get all region-views in this session
4310 TrackViewList empty;
4312 editor->get_regions_after(rs, (framepos_t) 0, empty);
4313 std::list<RegionView*> views = rs.by_layer();
4315 // remove displayed audio-region-views waveforms
4316 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4317 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4318 if (!arv) { continue ; }
4319 arv->delete_waves();
4322 // cleanup peak files:
4323 // - stop pending peakfile threads
4324 // - close peakfiles if any
4325 // - remove peak dir in session
4326 // - setup peakfiles (background thread)
4327 _session->cleanup_peakfiles ();
4329 // re-add waves to ARV
4330 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4331 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4332 if (!arv) { continue ; }
4333 arv->create_waves();
4337 PresentationInfo::order_t
4338 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4340 if (editor->get_selection().tracks.empty()) {
4341 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4344 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4347 we want the new routes to have their order keys set starting from
4348 the highest order key in the selection + 1 (if available).
4351 if (place == RouteDialogs::AfterSelection) {
4352 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4354 order_hint = rtav->route()->presentation_info().order();
4357 } else if (place == RouteDialogs::BeforeSelection) {
4358 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4360 order_hint = rtav->route()->presentation_info().order();
4362 } else if (place == RouteDialogs::First) {
4365 /* leave order_hint at max_order */
4372 ARDOUR_UI::start_duplicate_routes ()
4374 if (!duplicate_routes_dialog) {
4375 duplicate_routes_dialog = new DuplicateRouteDialog;
4378 if (duplicate_routes_dialog->restart (_session)) {
4382 duplicate_routes_dialog->present ();
4386 ARDOUR_UI::add_route ()
4388 if (!add_route_dialog.get (false)) {
4389 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4396 if (add_route_dialog->is_visible()) {
4397 /* we're already doing this */
4401 add_route_dialog->set_position (WIN_POS_MOUSE);
4402 add_route_dialog->present();
4406 ARDOUR_UI::add_route_dialog_response (int r)
4411 case AddRouteDialog::Add:
4413 case AddRouteDialog::AddAndClose:
4414 add_route_dialog->ArdourDialog::on_response (r);
4417 add_route_dialog->ArdourDialog::on_response (r);
4421 if ((count = add_route_dialog->count()) <= 0) {
4425 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4426 string template_path = add_route_dialog->track_template();
4427 DisplaySuspender ds;
4429 if (!template_path.empty()) {
4430 if (add_route_dialog->name_template_is_default()) {
4431 _session->new_route_from_template (count, order, template_path, string());
4433 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4438 ChanCount input_chan= add_route_dialog->channels ();
4439 ChanCount output_chan;
4440 string name_template = add_route_dialog->name_template ();
4441 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4442 RouteGroup* route_group = add_route_dialog->route_group ();
4443 AutoConnectOption oac = Config->get_output_auto_connect();
4444 bool strict_io = add_route_dialog->use_strict_io ();
4446 if (oac & AutoConnectMaster) {
4447 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4448 output_chan.set (DataType::MIDI, 0);
4450 output_chan = input_chan;
4453 /* XXX do something with name template */
4455 Session::ProcessorChangeBlocker pcb (_session);
4457 switch (add_route_dialog->type_wanted()) {
4458 case AddRouteDialog::AudioTrack:
4459 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4461 case AddRouteDialog::MidiTrack:
4462 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4464 case AddRouteDialog::MixedTrack:
4465 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4467 case AddRouteDialog::AudioBus:
4468 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4470 case AddRouteDialog::MidiBus:
4471 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4473 case AddRouteDialog::VCAMaster:
4474 session_add_vca (name_template, count);
4480 ARDOUR_UI::stop_video_server (bool ask_confirm)
4482 if (!video_server_process && ask_confirm) {
4483 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4485 if (video_server_process) {
4487 ArdourDialog confirm (_("Stop Video-Server"), true);
4488 Label m (_("Do you really want to stop the Video Server?"));
4489 confirm.get_vbox()->pack_start (m, true, true);
4490 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4491 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4492 confirm.show_all ();
4493 if (confirm.run() == RESPONSE_CANCEL) {
4497 delete video_server_process;
4498 video_server_process =0;
4503 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4505 ARDOUR_UI::start_video_server( float_window, true);
4509 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4515 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4516 if (video_server_process) {
4517 popup_error(_("The Video Server is already started."));
4519 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4525 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4527 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4529 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4531 video_server_dialog->set_transient_for (*float_window);
4534 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4535 video_server_dialog->hide();
4537 ResponseType r = (ResponseType) video_server_dialog->run ();
4538 video_server_dialog->hide();
4539 if (r != RESPONSE_ACCEPT) { return false; }
4540 if (video_server_dialog->show_again()) {
4541 Config->set_show_video_server_dialog(false);
4545 std::string icsd_exec = video_server_dialog->get_exec_path();
4546 std::string icsd_docroot = video_server_dialog->get_docroot();
4547 #ifndef PLATFORM_WINDOWS
4548 if (icsd_docroot.empty()) {
4549 icsd_docroot = VideoUtils::video_get_docroot (Config);
4554 #ifdef PLATFORM_WINDOWS
4555 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4556 /* OK, allow all drive letters */
4559 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4560 warning << _("Specified docroot is not an existing directory.") << endmsg;
4563 #ifndef PLATFORM_WINDOWS
4564 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4565 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4566 warning << _("Given Video Server is not an executable file.") << endmsg;
4570 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4571 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4572 warning << _("Given Video Server is not an executable file.") << endmsg;
4578 argp=(char**) calloc(9,sizeof(char*));
4579 argp[0] = strdup(icsd_exec.c_str());
4580 argp[1] = strdup("-P");
4581 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4582 argp[3] = strdup("-p");
4583 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4584 argp[5] = strdup("-C");
4585 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4586 argp[7] = strdup(icsd_docroot.c_str());
4588 stop_video_server();
4590 #ifdef PLATFORM_WINDOWS
4591 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4592 /* OK, allow all drive letters */
4595 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4596 Config->set_video_advanced_setup(false);
4598 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4599 Config->set_video_server_url(url_str);
4600 Config->set_video_server_docroot(icsd_docroot);
4601 Config->set_video_advanced_setup(true);
4604 if (video_server_process) {
4605 delete video_server_process;
4608 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4609 if (video_server_process->start()) {
4610 warning << _("Cannot launch the video-server") << endmsg;
4613 int timeout = 120; // 6 sec
4614 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4615 Glib::usleep (50000);
4617 if (--timeout <= 0 || !video_server_process->is_running()) break;
4620 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4622 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4623 delete video_server_process;
4624 video_server_process = 0;
4632 ARDOUR_UI::add_video (Gtk::Window* float_window)
4638 if (!start_video_server(float_window, false)) {
4639 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4644 add_video_dialog->set_transient_for (*float_window);
4647 if (add_video_dialog->is_visible()) {
4648 /* we're already doing this */
4652 ResponseType r = (ResponseType) add_video_dialog->run ();
4653 add_video_dialog->hide();
4654 if (r != RESPONSE_ACCEPT) { return; }
4656 bool local_file, orig_local_file;
4657 std::string path = add_video_dialog->file_name(local_file);
4659 std::string orig_path = path;
4660 orig_local_file = local_file;
4662 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4664 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4665 warning << string_compose(_("could not open %1"), path) << endmsg;
4668 if (!local_file && path.length() == 0) {
4669 warning << _("no video-file selected") << endmsg;
4673 std::string audio_from_video;
4674 bool detect_ltc = false;
4676 switch (add_video_dialog->import_option()) {
4677 case VTL_IMPORT_TRANSCODE:
4679 TranscodeVideoDialog *transcode_video_dialog;
4680 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4681 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4682 transcode_video_dialog->hide();
4683 if (r != RESPONSE_ACCEPT) {
4684 delete transcode_video_dialog;
4688 audio_from_video = transcode_video_dialog->get_audiofile();
4690 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4693 else if (!audio_from_video.empty()) {
4694 editor->embed_audio_from_video(
4696 video_timeline->get_offset(),
4697 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4700 switch (transcode_video_dialog->import_option()) {
4701 case VTL_IMPORT_TRANSCODED:
4702 path = transcode_video_dialog->get_filename();
4705 case VTL_IMPORT_REFERENCE:
4708 delete transcode_video_dialog;
4711 delete transcode_video_dialog;
4715 case VTL_IMPORT_NONE:
4719 /* strip _session->session_directory().video_path() from video file if possible */
4720 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4721 path=path.substr(_session->session_directory().video_path().size());
4722 if (path.at(0) == G_DIR_SEPARATOR) {
4723 path=path.substr(1);
4727 video_timeline->set_update_session_fps(auto_set_session_fps);
4729 if (video_timeline->video_file_info(path, local_file)) {
4730 XMLNode* node = new XMLNode(X_("Videotimeline"));
4731 node->set_property (X_("Filename"), path);
4732 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4733 node->set_property (X_("LocalFile"), local_file);
4734 if (orig_local_file) {
4735 node->set_property (X_("OriginalVideoFile"), orig_path);
4737 node->remove_property (X_("OriginalVideoFile"));
4739 _session->add_extra_xml (*node);
4740 _session->set_dirty ();
4742 if (!audio_from_video.empty() && detect_ltc) {
4743 std::vector<LTCFileReader::LTCMap> ltc_seq;
4746 /* TODO ask user about TV standard (LTC alignment if any) */
4747 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4748 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4750 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4752 /* TODO seek near end of file, and read LTC until end.
4753 * if it fails to find any LTC frames, scan complete file
4755 * calculate drift of LTC compared to video-duration,
4756 * ask user for reference (timecode from start/mid/end)
4759 // LTCFileReader will have written error messages
4762 ::g_unlink(audio_from_video.c_str());
4764 if (ltc_seq.size() == 0) {
4765 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4767 /* the very first TC in the file is somteimes not aligned properly */
4768 int i = ltc_seq.size() -1;
4769 ARDOUR::frameoffset_t video_start_offset =
4770 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4771 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4772 video_timeline->set_offset(video_start_offset);
4776 _session->maybe_update_session_range(
4777 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4778 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4781 if (add_video_dialog->launch_xjadeo() && local_file) {
4782 editor->set_xjadeo_sensitive(true);
4783 editor->toggle_xjadeo_proc(1);
4785 editor->toggle_xjadeo_proc(0);
4787 editor->toggle_ruler_video(true);
4792 ARDOUR_UI::remove_video ()
4794 video_timeline->close_session();
4795 editor->toggle_ruler_video(false);
4798 video_timeline->set_offset_locked(false);
4799 video_timeline->set_offset(0);
4801 /* delete session state */
4802 XMLNode* node = new XMLNode(X_("Videotimeline"));
4803 _session->add_extra_xml(*node);
4804 node = new XMLNode(X_("Videomonitor"));
4805 _session->add_extra_xml(*node);
4806 node = new XMLNode(X_("Videoexport"));
4807 _session->add_extra_xml(*node);
4808 stop_video_server();
4812 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4814 if (localcacheonly) {
4815 video_timeline->vmon_update();
4817 video_timeline->flush_cache();
4819 editor->queue_visual_videotimeline_update();
4823 ARDOUR_UI::export_video (bool range)
4825 if (ARDOUR::Config->get_show_video_export_info()) {
4826 ExportVideoInfobox infobox (_session);
4827 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4828 if (infobox.show_again()) {
4829 ARDOUR::Config->set_show_video_export_info(false);
4832 case GTK_RESPONSE_YES:
4833 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4839 export_video_dialog->set_session (_session);
4840 export_video_dialog->apply_state(editor->get_selection().time, range);
4841 export_video_dialog->run ();
4842 export_video_dialog->hide ();
4846 ARDOUR_UI::preferences_settings () const
4851 node = _session->instant_xml(X_("Preferences"));
4853 node = Config->instant_xml(X_("Preferences"));
4857 node = new XMLNode (X_("Preferences"));
4864 ARDOUR_UI::mixer_settings () const
4869 node = _session->instant_xml(X_("Mixer"));
4871 node = Config->instant_xml(X_("Mixer"));
4875 node = new XMLNode (X_("Mixer"));
4882 ARDOUR_UI::main_window_settings () const
4887 node = _session->instant_xml(X_("Main"));
4889 node = Config->instant_xml(X_("Main"));
4893 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4894 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4899 node = new XMLNode (X_("Main"));
4906 ARDOUR_UI::editor_settings () const
4911 node = _session->instant_xml(X_("Editor"));
4913 node = Config->instant_xml(X_("Editor"));
4917 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4918 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4923 node = new XMLNode (X_("Editor"));
4930 ARDOUR_UI::keyboard_settings () const
4934 node = Config->extra_xml(X_("Keyboard"));
4937 node = new XMLNode (X_("Keyboard"));
4944 ARDOUR_UI::create_xrun_marker (framepos_t where)
4947 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4948 _session->locations()->add (location);
4953 ARDOUR_UI::halt_on_xrun_message ()
4955 cerr << "HALT on xrun\n";
4956 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4961 ARDOUR_UI::xrun_handler (framepos_t where)
4967 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4969 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4970 create_xrun_marker(where);
4973 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4974 halt_on_xrun_message ();
4979 ARDOUR_UI::disk_overrun_handler ()
4981 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4983 if (!have_disk_speed_dialog_displayed) {
4984 have_disk_speed_dialog_displayed = true;
4985 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4986 The disk system on your computer\n\
4987 was not able to keep up with %1.\n\
4989 Specifically, it failed to write data to disk\n\
4990 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4991 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4997 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4998 static MessageDialog *scan_dlg = NULL;
4999 static ProgressBar *scan_pbar = NULL;
5000 static HBox *scan_tbox = NULL;
5001 static Gtk::Button *scan_timeout_button;
5004 ARDOUR_UI::cancel_plugin_scan ()
5006 PluginManager::instance().cancel_plugin_scan();
5010 ARDOUR_UI::cancel_plugin_timeout ()
5012 PluginManager::instance().cancel_plugin_timeout();
5013 scan_timeout_button->set_sensitive (false);
5017 ARDOUR_UI::plugin_scan_timeout (int timeout)
5019 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5023 scan_pbar->set_sensitive (false);
5024 scan_timeout_button->set_sensitive (true);
5025 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5028 scan_pbar->set_sensitive (false);
5029 scan_timeout_button->set_sensitive (false);
5035 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5037 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5041 const bool cancelled = PluginManager::instance().cancelled();
5042 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5043 if (cancelled && scan_dlg->is_mapped()) {
5048 if (cancelled || !can_cancel) {
5053 static Gtk::Button *cancel_button;
5055 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5056 VBox* vbox = scan_dlg->get_vbox();
5057 vbox->set_size_request(400,-1);
5058 scan_dlg->set_title (_("Scanning for plugins"));
5060 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5061 cancel_button->set_name ("EditorGTKButton");
5062 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5063 cancel_button->show();
5065 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5067 scan_tbox = manage( new HBox() );
5069 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5070 scan_timeout_button->set_name ("EditorGTKButton");
5071 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5072 scan_timeout_button->show();
5074 scan_pbar = manage(new ProgressBar());
5075 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5076 scan_pbar->set_text(_("Scan Timeout"));
5079 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5080 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5082 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5085 assert(scan_dlg && scan_tbox && cancel_button);
5087 if (type == X_("closeme")) {
5091 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5094 if (!can_cancel || !cancelled) {
5095 scan_timeout_button->set_sensitive(false);
5097 cancel_button->set_sensitive(can_cancel && !cancelled);
5103 ARDOUR_UI::gui_idle_handler ()
5106 /* due to idle calls, gtk_events_pending() may always return true */
5107 while (gtk_events_pending() && --timeout) {
5108 gtk_main_iteration ();
5113 ARDOUR_UI::disk_underrun_handler ()
5115 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5117 if (!have_disk_speed_dialog_displayed) {
5118 have_disk_speed_dialog_displayed = true;
5119 MessageDialog* msg = new MessageDialog (
5120 _main_window, string_compose (_("The disk system on your computer\n\
5121 was not able to keep up with %1.\n\
5123 Specifically, it failed to read data from disk\n\
5124 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5125 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5131 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5133 have_disk_speed_dialog_displayed = false;
5138 ARDOUR_UI::session_dialog (std::string msg)
5140 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5144 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5151 ARDOUR_UI::pending_state_dialog ()
5153 HBox* hbox = manage (new HBox());
5154 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5155 ArdourDialog dialog (_("Crash Recovery"), true);
5156 Label message (string_compose (_("\
5157 This session appears to have been in the\n\
5158 middle of recording when %1 or\n\
5159 the computer was shutdown.\n\
5161 %1 can recover any captured audio for\n\
5162 you, or it can ignore it. Please decide\n\
5163 what you would like to do.\n"), PROGRAM_NAME));
5164 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5165 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5166 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5167 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5168 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5169 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5170 dialog.set_default_response (RESPONSE_ACCEPT);
5171 dialog.set_position (WIN_POS_CENTER);
5176 switch (dialog.run ()) {
5177 case RESPONSE_ACCEPT:
5185 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5187 HBox* hbox = new HBox();
5188 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5189 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5190 Label message (string_compose (_("\
5191 This session was created with a sample rate of %1 Hz, but\n\
5192 %2 is currently running at %3 Hz. If you load this session,\n\
5193 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5195 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5196 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5197 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5198 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5199 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5200 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5201 dialog.set_default_response (RESPONSE_ACCEPT);
5202 dialog.set_position (WIN_POS_CENTER);
5207 switch (dialog.run()) {
5208 case RESPONSE_ACCEPT:
5218 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5220 MessageDialog msg (string_compose (_("\
5221 This session was created with a sample rate of %1 Hz, but\n\
5222 %2 is currently running at %3 Hz.\n\
5223 Audio will be recorded and played at the wrong sample rate.\n\
5224 Re-Configure the Audio Engine in\n\
5225 Menu > Window > Audio/Midi Setup"),
5226 desired, PROGRAM_NAME, actual),
5228 Gtk::MESSAGE_WARNING);
5233 ARDOUR_UI::use_config ()
5235 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5237 set_transport_controllable_state (*node);
5242 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5244 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5245 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5247 primary_clock->set (pos);
5250 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5251 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5253 secondary_clock->set (pos);
5256 if (big_clock_window) {
5257 big_clock->set (pos);
5259 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5263 ARDOUR_UI::step_edit_status_change (bool yn)
5265 // XXX should really store pre-step edit status of things
5266 // we make insensitive
5269 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5270 rec_button.set_sensitive (false);
5272 rec_button.unset_active_state ();;
5273 rec_button.set_sensitive (true);
5278 ARDOUR_UI::record_state_changed ()
5280 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5283 /* why bother - the clock isn't visible */
5287 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5289 if (big_clock_window) {
5290 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5291 big_clock->set_active (true);
5293 big_clock->set_active (false);
5300 ARDOUR_UI::first_idle ()
5303 _session->allow_auto_play (true);
5307 editor->first_idle();
5310 /* in 1 second, hide the splash screen
5312 * Consider hiding it *now*. If a user opens opens a dialog
5313 * during that one second while the splash is still visible,
5314 * the dialog will push-back the splash.
5315 * Closing the dialog later will pop it back.
5317 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5319 Keyboard::set_can_save_keybindings (true);
5324 ARDOUR_UI::store_clock_modes ()
5326 XMLNode* node = new XMLNode(X_("ClockModes"));
5328 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5329 XMLNode* child = new XMLNode (X_("Clock"));
5331 child->set_property (X_("name"), (*x)->name());
5332 child->set_property (X_("mode"), (*x)->mode());
5333 child->set_property (X_("on"), (*x)->on());
5335 node->add_child_nocopy (*child);
5338 _session->add_extra_xml (*node);
5339 _session->set_dirty ();
5342 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5343 : Controllable (name), ui (u), type(tp)
5349 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5352 /* do nothing: these are radio-style actions */
5356 const char *action = 0;
5360 action = X_("Roll");
5363 action = X_("Stop");
5366 action = X_("GotoStart");
5369 action = X_("GotoEnd");
5372 action = X_("Loop");
5375 action = X_("PlaySelection");
5378 action = X_("Record");
5388 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5396 ARDOUR_UI::TransportControllable::get_value (void) const
5423 ARDOUR_UI::setup_profile ()
5425 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5426 Profile->set_small_screen ();
5429 if (g_getenv ("TRX")) {
5430 Profile->set_trx ();
5433 if (g_getenv ("MIXBUS")) {
5434 Profile->set_mixbus ();
5439 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5441 MissingFileDialog dialog (s, str, type);
5446 int result = dialog.run ();
5453 return 1; // quit entire session load
5456 result = dialog.get_action ();
5462 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5464 AmbiguousFileDialog dialog (file, hits);
5471 return dialog.get_which ();
5474 /** Allocate our thread-local buffers */
5476 ARDOUR_UI::get_process_buffers ()
5478 _process_thread->get_buffers ();
5481 /** Drop our thread-local buffers */
5483 ARDOUR_UI::drop_process_buffers ()
5485 _process_thread->drop_buffers ();
5489 ARDOUR_UI::feedback_detected ()
5491 _feedback_exists = true;
5495 ARDOUR_UI::successful_graph_sort ()
5497 _feedback_exists = false;
5501 ARDOUR_UI::midi_panic ()
5504 _session->midi_panic();
5509 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5511 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5512 const char* end_big = "</span>";
5513 const char* start_mono = "<tt>";
5514 const char* end_mono = "</tt>";
5516 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5517 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5518 "From now on, use the backup copy with older versions of %3"),
5519 xml_path, backup_path, PROGRAM_NAME,
5521 start_mono, end_mono), true);
5527 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5529 using namespace Menu_Helpers;
5531 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5532 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5533 i->set_active (editor_meter->meter_type () == type);
5537 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5539 using namespace Gtk::Menu_Helpers;
5541 Gtk::Menu* m = manage (new Menu);
5542 MenuList& items = m->items ();
5544 RadioMenuItem::Group group;
5546 _suspend_editor_meter_callbacks = true;
5547 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5548 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5549 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5550 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5551 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5552 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5553 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5554 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5555 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5556 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5557 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5559 m->popup (ev->button, ev->time);
5560 _suspend_editor_meter_callbacks = false;
5564 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5566 if (ev->button == 3 && editor_meter) {
5567 popup_editor_meter_menu (ev);
5574 ARDOUR_UI::reset_peak_display ()
5576 if (!_session || !_session->master_out() || !editor_meter) return;
5577 editor_meter->clear_meters();
5578 editor_meter_max_peak = -INFINITY;
5579 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5583 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5585 if (!_session || !_session->master_out()) return;
5586 if (group == _session->master_out()->route_group()) {
5587 reset_peak_display ();
5592 ARDOUR_UI::reset_route_peak_display (Route* route)
5594 if (!_session || !_session->master_out()) return;
5595 if (_session->master_out().get() == route) {
5596 reset_peak_display ();
5601 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5603 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5604 audio_midi_setup->set_position (WIN_POS_CENTER);
5606 if (desired_sample_rate != 0) {
5607 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5608 audio_midi_setup->try_autostart ();
5609 if (ARDOUR::AudioEngine::instance()->running()) {
5616 int response = audio_midi_setup->run();
5618 case Gtk::RESPONSE_DELETE_EVENT:
5619 // after latency callibration engine may run,
5620 // Running() signal was emitted, but dialog will not
5621 // have emitted a response. The user needs to close
5622 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5623 if (!AudioEngine::instance()->running()) {
5628 if (!AudioEngine::instance()->running()) {
5631 audio_midi_setup->hide ();
5639 ARDOUR_UI::transport_numpad_timeout ()
5641 _numpad_locate_happening = false;
5642 if (_numpad_timeout_connection.connected() )
5643 _numpad_timeout_connection.disconnect();
5648 ARDOUR_UI::transport_numpad_decimal ()
5650 _numpad_timeout_connection.disconnect();
5652 if (_numpad_locate_happening) {
5653 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5654 _numpad_locate_happening = false;
5656 _pending_locate_num = 0;
5657 _numpad_locate_happening = true;
5658 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5663 ARDOUR_UI::transport_numpad_event (int num)
5665 if ( _numpad_locate_happening ) {
5666 _pending_locate_num = _pending_locate_num*10 + num;
5669 case 0: toggle_roll(false, false); break;
5670 case 1: transport_rewind(1); break;
5671 case 2: transport_forward(1); break;
5672 case 3: transport_record(true); break;
5673 case 4: toggle_session_auto_loop(); break;
5674 case 5: transport_record(false); toggle_session_auto_loop(); break;
5675 case 6: toggle_punch(); break;
5676 case 7: toggle_click(); break;
5677 case 8: toggle_auto_return(); break;
5678 case 9: toggle_follow_edits(); break;
5684 ARDOUR_UI::set_flat_buttons ()
5686 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5690 ARDOUR_UI::audioengine_became_silent ()
5692 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5694 Gtk::MESSAGE_WARNING,
5698 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5700 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5701 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5702 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5703 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5704 Gtk::HBox pay_button_box;
5705 Gtk::HBox subscribe_button_box;
5707 pay_button_box.pack_start (pay_button, true, false);
5708 subscribe_button_box.pack_start (subscribe_button, true, false);
5710 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 */
5712 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5713 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5715 msg.get_vbox()->pack_start (pay_label);
5716 msg.get_vbox()->pack_start (pay_button_box);
5717 msg.get_vbox()->pack_start (subscribe_label);
5718 msg.get_vbox()->pack_start (subscribe_button_box);
5720 msg.get_vbox()->show_all ();
5722 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5723 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5724 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5729 case Gtk::RESPONSE_YES:
5730 AudioEngine::instance()->reset_silence_countdown ();
5733 case Gtk::RESPONSE_NO:
5735 save_state_canfail ("");
5739 case Gtk::RESPONSE_CANCEL:
5741 /* don't reset, save session and exit */
5747 ARDOUR_UI::hide_application ()
5749 Application::instance ()-> hide ();
5753 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5755 /* icons, titles, WM stuff */
5757 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5759 if (window_icons.empty()) {
5760 Glib::RefPtr<Gdk::Pixbuf> icon;
5761 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5762 window_icons.push_back (icon);
5764 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5765 window_icons.push_back (icon);
5767 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5768 window_icons.push_back (icon);
5770 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5771 window_icons.push_back (icon);
5775 if (!window_icons.empty()) {
5776 window.set_default_icon_list (window_icons);
5779 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5781 if (!name.empty()) {
5785 window.set_title (title.get_string());
5786 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5788 window.set_flags (CAN_FOCUS);
5789 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5791 /* This is a hack to ensure that GTK-accelerators continue to
5792 * work. Once we switch over to entirely native bindings, this will be
5793 * unnecessary and should be removed
5795 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5797 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5798 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5799 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5800 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5804 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5806 Gtkmm2ext::Bindings* bindings = 0;
5807 Gtk::Window* window = 0;
5809 /* until we get ardour bindings working, we are not handling key
5813 if (ev->type != GDK_KEY_PRESS) {
5817 if (event_window == &_main_window) {
5819 window = event_window;
5821 /* find current tab contents */
5823 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5825 /* see if it uses the ardour binding system */
5828 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5831 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5835 window = event_window;
5837 /* see if window uses ardour binding system */
5839 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5842 /* An empty binding set is treated as if it doesn't exist */
5844 if (bindings && bindings->empty()) {
5848 return key_press_focus_accelerator_handler (*window, ev, bindings);
5851 static Gtkmm2ext::Bindings*
5852 get_bindings_from_widget_heirarchy (GtkWidget** w)
5857 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5860 *w = gtk_widget_get_parent (*w);
5863 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5867 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5869 GtkWindow* win = window.gobj();
5870 GtkWidget* focus = gtk_window_get_focus (win);
5871 GtkWidget* binding_widget = focus;
5872 bool special_handling_of_unmodified_accelerators = false;
5873 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5877 /* some widget has keyboard focus */
5879 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5881 /* A particular kind of focusable widget currently has keyboard
5882 * focus. All unmodified key events should go to that widget
5883 * first and not be used as an accelerator by default
5886 special_handling_of_unmodified_accelerators = true;
5890 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5891 if (focus_bindings) {
5892 bindings = focus_bindings;
5893 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5898 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",
5901 Gtkmm2ext::show_gdk_event_state (ev->state),
5902 special_handling_of_unmodified_accelerators,
5903 Keyboard::some_magic_widget_has_focus(),
5905 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5906 ((ev->state & mask) ? "yes" : "no"),
5907 window.get_title()));
5909 /* This exists to allow us to override the way GTK handles
5910 key events. The normal sequence is:
5912 a) event is delivered to a GtkWindow
5913 b) accelerators/mnemonics are activated
5914 c) if (b) didn't handle the event, propagate to
5915 the focus widget and/or focus chain
5917 The problem with this is that if the accelerators include
5918 keys without modifiers, such as the space bar or the
5919 letter "e", then pressing the key while typing into
5920 a text entry widget results in the accelerator being
5921 activated, instead of the desired letter appearing
5924 There is no good way of fixing this, but this
5925 represents a compromise. The idea is that
5926 key events involving modifiers (not Shift)
5927 get routed into the activation pathway first, then
5928 get propagated to the focus widget if necessary.
5930 If the key event doesn't involve modifiers,
5931 we deliver to the focus widget first, thus allowing
5932 it to get "normal text" without interference
5935 Of course, this can also be problematic: if there
5936 is a widget with focus, then it will swallow
5937 all "normal text" accelerators.
5941 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5943 /* no special handling or there are modifiers in effect: accelerate first */
5945 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5946 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5947 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5949 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5950 KeyboardKey k (ev->state, ev->keyval);
5954 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5956 if (bindings->activate (k, Bindings::Press)) {
5957 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5961 if (binding_widget) {
5962 binding_widget = gtk_widget_get_parent (binding_widget);
5963 if (binding_widget) {
5964 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5973 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5975 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5976 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5980 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5982 if (gtk_window_propagate_key_event (win, ev)) {
5983 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5989 /* no modifiers, propagate first */
5991 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5993 if (gtk_window_propagate_key_event (win, ev)) {
5994 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5998 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5999 KeyboardKey k (ev->state, ev->keyval);
6003 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
6006 if (bindings->activate (k, Bindings::Press)) {
6007 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6011 if (binding_widget) {
6012 binding_widget = gtk_widget_get_parent (binding_widget);
6013 if (binding_widget) {
6014 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
6023 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
6025 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
6026 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6031 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
6036 ARDOUR_UI::load_bindings ()
6038 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
6039 error << _("Global keybindings are missing") << endmsg;
6044 ARDOUR_UI::cancel_solo ()
6047 _session->cancel_all_solo ();
6052 ARDOUR_UI::reset_focus (Gtk::Widget* w)
6054 /* this resets focus to the first focusable parent of the given widget,
6055 * or, if there is no focusable parent, cancels focus in the toplevel
6056 * window that the given widget is packed into (if there is one).
6063 Gtk::Widget* top = w->get_toplevel();
6065 if (!top || !top->is_toplevel()) {
6069 w = w->get_parent ();
6073 if (w->is_toplevel()) {
6074 /* Setting the focus widget to a Gtk::Window causes all
6075 * subsequent calls to ::has_focus() on the nominal
6076 * focus widget in that window to return
6077 * false. Workaround: never set focus to the toplevel
6083 if (w->get_can_focus ()) {
6084 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
6085 win->set_focus (*w);
6088 w = w->get_parent ();
6091 if (top == &_main_window) {
6095 /* no focusable parent found, cancel focus in top level window.
6096 C++ API cannot be used for this. Thanks, references.
6099 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);