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 "save_template_dialog.h"
173 #include "script_selector.h"
174 #include "session_archive_dialog.h"
175 #include "session_dialog.h"
176 #include "session_metadata_dialog.h"
177 #include "session_option_editor.h"
178 #include "speaker_dialog.h"
181 #include "template_dialog.h"
182 #include "time_axis_view_item.h"
183 #include "time_info_box.h"
186 #include "utils_videotl.h"
187 #include "video_server_dialog.h"
188 #include "add_video_dialog.h"
189 #include "transcode_video_dialog.h"
191 #include "pbd/i18n.h"
193 using namespace ARDOUR;
194 using namespace ARDOUR_UI_UTILS;
196 using namespace Gtkmm2ext;
197 using namespace ArdourWidgets;
200 using namespace Editing;
202 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
204 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
205 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
208 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
210 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
211 "Would you like these files to be copied and used for %1 %2.x?\n\n"
212 "(This will require you to restart %1.)"),
213 PROGRAM_NAME, PROGRAM_VERSION, version),
214 false, /* no markup */
217 true /* modal, though it hardly matters since it is the only window */
220 msg.set_default_response (Gtk::RESPONSE_YES);
223 return (msg.run() == Gtk::RESPONSE_YES);
227 libxml_generic_error_func (void* /* parsing_context*/,
235 vsnprintf (buf, sizeof (buf), msg, ap);
236 error << buf << endmsg;
241 libxml_structured_error_func (void* /* parsing_context*/,
249 replace_all (msg, "\n", "");
252 if (err->file && err->line) {
253 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
256 error << ':' << err->int2;
261 error << X_("XML error: ") << msg << endmsg;
267 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
268 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
269 , session_loaded (false)
270 , session_load_in_progress (false)
271 , gui_object_state (new GUIObjectState)
272 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
273 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
274 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
276 , global_actions (X_("global"))
277 , ignore_dual_punch (false)
278 , main_window_visibility (0)
283 , _mixer_on_top (false)
284 , _initial_verbose_plugin_scan (false)
285 , first_time_engine_run (true)
286 , secondary_clock_spacer (0)
287 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
288 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
289 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
290 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
291 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
292 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
293 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
294 , auto_input_button (ArdourButton::led_default_elements)
296 , auto_return_button (ArdourButton::led_default_elements)
297 , follow_edits_button (ArdourButton::led_default_elements)
298 , auditioning_alert_button (_("Audition"))
299 , solo_alert_button (_("Solo"))
300 , feedback_alert_button (_("Feedback"))
301 , error_alert_button ( ArdourButton::just_led_default_elements )
302 , editor_meter_peak_display()
304 , _suspend_editor_meter_callbacks (false)
305 , _numpad_locate_happening (false)
306 , _session_is_new (false)
307 , last_key_press_time (0)
311 , rc_option_editor (0)
312 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
313 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
314 , about (X_("about"), _("About"))
315 , location_ui (X_("locations"), S_("Ranges|Locations"))
316 , route_params (X_("inspector"), _("Tracks and Busses"))
317 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
318 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
319 , lua_script_window (X_("script-manager"), _("Script Manager"))
320 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
321 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
322 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
323 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
324 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
325 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
326 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
327 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
328 , video_server_process (0)
330 , have_configure_timeout (false)
331 , last_configure_time (0)
333 , have_disk_speed_dialog_displayed (false)
334 , _status_bar_visibility (X_("status-bar"))
335 , _feedback_exists (false)
336 , _log_not_acknowledged (LogLevelNone)
337 , duplicate_routes_dialog (0)
338 , editor_visibility_button (S_("Window|Editor"))
339 , mixer_visibility_button (S_("Window|Mixer"))
340 , prefs_visibility_button (S_("Window|Preferences"))
342 Gtkmm2ext::init (localedir);
344 UIConfiguration::instance().post_gui_init ();
346 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
348 /* "touch" the been-here-before path now that config has been migrated */
349 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
351 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
353 /* configuration was modified, exit immediately */
358 if (string (VERSIONSTRING).find (".pre") != string::npos) {
359 /* check this is not being run from ./ardev etc. */
360 if (!running_from_source_tree ()) {
361 pre_release_dialog ();
365 if (theArdourUI == 0) {
369 /* track main window visibility */
371 main_window_visibility = new VisibilityTracker (_main_window);
373 /* stop libxml from spewing to stdout/stderr */
375 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
376 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
378 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
379 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
380 UIConfiguration::instance().map_parameters (pc);
382 roll_button.set_controllable (roll_controllable);
383 stop_button.set_controllable (stop_controllable);
384 goto_start_button.set_controllable (goto_start_controllable);
385 goto_end_button.set_controllable (goto_end_controllable);
386 auto_loop_button.set_controllable (auto_loop_controllable);
387 play_selection_button.set_controllable (play_selection_controllable);
388 rec_button.set_controllable (rec_controllable);
390 roll_button.set_name ("transport button");
391 stop_button.set_name ("transport button");
392 goto_start_button.set_name ("transport button");
393 goto_end_button.set_name ("transport button");
394 auto_loop_button.set_name ("transport button");
395 play_selection_button.set_name ("transport button");
396 rec_button.set_name ("transport recenable button");
397 midi_panic_button.set_name ("transport button");
399 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
400 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
402 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
404 /* handle dialog requests */
406 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
408 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
410 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
412 /* handle Audio/MIDI setup when session requires it */
414 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
416 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
418 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
420 /* handle sr mismatch with a dialog - cross-thread from engine */
421 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
423 /* handle requests to quit (coming from JACK session) */
425 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
427 /* tell the user about feedback */
429 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
430 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
432 /* handle requests to deal with missing files */
434 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
436 /* and ambiguous files */
438 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
440 /* also plugin scan messages */
441 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
442 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
444 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
446 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
449 /* lets get this party started */
451 setup_gtk_ardour_enums ();
454 SessionEvent::create_per_thread_pool ("GUI", 4096);
456 /* we like keyboards */
458 keyboard = new ArdourKeyboard(*this);
460 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
462 keyboard->set_state (*node, Stateful::loading_state_version);
465 UIConfiguration::instance().reset_dpi ();
467 TimeAxisViewItem::set_constant_heights ();
469 /* Set this up so that our window proxies can register actions */
471 ActionManager::init ();
473 /* The following must happen after ARDOUR::init() so that Config is set up */
475 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
478 key_editor.set_state (*ui_xml, 0);
479 session_option_editor.set_state (*ui_xml, 0);
480 speaker_config_window.set_state (*ui_xml, 0);
481 about.set_state (*ui_xml, 0);
482 add_route_dialog.set_state (*ui_xml, 0);
483 add_video_dialog.set_state (*ui_xml, 0);
484 route_params.set_state (*ui_xml, 0);
485 bundle_manager.set_state (*ui_xml, 0);
486 location_ui.set_state (*ui_xml, 0);
487 big_clock_window.set_state (*ui_xml, 0);
488 audio_port_matrix.set_state (*ui_xml, 0);
489 midi_port_matrix.set_state (*ui_xml, 0);
490 export_video_dialog.set_state (*ui_xml, 0);
491 lua_script_window.set_state (*ui_xml, 0);
492 idleometer.set_state (*ui_xml, 0);
495 /* Separate windows */
497 WM::Manager::instance().register_window (&key_editor);
498 WM::Manager::instance().register_window (&session_option_editor);
499 WM::Manager::instance().register_window (&speaker_config_window);
500 WM::Manager::instance().register_window (&about);
501 WM::Manager::instance().register_window (&add_route_dialog);
502 WM::Manager::instance().register_window (&add_video_dialog);
503 WM::Manager::instance().register_window (&route_params);
504 WM::Manager::instance().register_window (&audio_midi_setup);
505 WM::Manager::instance().register_window (&export_video_dialog);
506 WM::Manager::instance().register_window (&lua_script_window);
507 WM::Manager::instance().register_window (&bundle_manager);
508 WM::Manager::instance().register_window (&location_ui);
509 WM::Manager::instance().register_window (&big_clock_window);
510 WM::Manager::instance().register_window (&audio_port_matrix);
511 WM::Manager::instance().register_window (&midi_port_matrix);
512 WM::Manager::instance().register_window (&idleometer);
514 /* do not retain position for add route dialog */
515 add_route_dialog.set_state_mask (WindowProxy::Size);
517 /* Trigger setting up the color scheme and loading the GTK RC file */
519 UIConfiguration::instance().load_rc_file (false);
521 _process_thread = new ProcessThread ();
522 _process_thread->init ();
524 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
530 ARDOUR_UI::pre_release_dialog ()
532 ArdourDialog d (_("Pre-Release Warning"), true, false);
533 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
535 Label* label = manage (new Label);
536 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
537 There are still several issues and bugs to be worked on,\n\
538 as well as general workflow improvements, before this can be considered\n\
539 release software. So, a few guidelines:\n\
541 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
542 though it may be so, depending on your workflow.\n\
543 2) Please wait for a helpful writeup of new features.\n\
544 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
545 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
546 making sure to note the product version number as 5.0-pre.\n\
547 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
548 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
549 can get there directly from within the program via the Help->Chat menu option.\n\
551 Full information on all the above can be found on the support page at\n\
553 http://ardour.org/support\n\
554 "), PROGRAM_NAME, VERSIONSTRING));
556 d.get_vbox()->set_border_width (12);
557 d.get_vbox()->pack_start (*label, false, false, 12);
558 d.get_vbox()->show_all ();
563 GlobalPortMatrixWindow*
564 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
569 return new GlobalPortMatrixWindow (_session, type);
573 ARDOUR_UI::attach_to_engine ()
575 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
576 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
580 ARDOUR_UI::engine_stopped ()
582 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
583 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
584 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
585 update_sample_rate (0);
590 ARDOUR_UI::engine_running ()
592 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
593 if (first_time_engine_run) {
595 first_time_engine_run = false;
599 _session->reset_xrun_count ();
601 update_disk_space ();
603 update_xrun_count ();
604 update_sample_rate (AudioEngine::instance()->sample_rate());
605 update_timecode_format ();
606 update_peak_thread_work ();
607 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
608 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
612 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
614 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
615 /* we can't rely on the original string continuing to exist when we are called
616 again in the GUI thread, so make a copy and note that we need to
619 char *copy = strdup (reason);
620 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
624 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
625 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
627 update_sample_rate (0);
631 /* if the reason is a non-empty string, it means that the backend was shutdown
632 rather than just Ardour.
635 if (strlen (reason)) {
636 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
638 msgstr = string_compose (_("\
639 The audio backend has either been shutdown or it\n\
640 disconnected %1 because %1\n\
641 was not fast enough. Try to restart\n\
642 the audio backend and save the session."), PROGRAM_NAME);
645 MessageDialog msg (_main_window, msgstr);
646 pop_back_splash (msg);
650 free (const_cast<char*> (reason));
655 ARDOUR_UI::post_engine ()
657 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
659 #ifdef AUDIOUNIT_SUPPORT
661 if (AUPluginInfo::au_get_crashlog(au_msg)) {
662 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
663 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
664 info << au_msg << endmsg;
668 ARDOUR::init_post_engine ();
670 /* connect to important signals */
672 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
673 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
674 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
675 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
676 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
678 if (setup_windows ()) {
679 throw failed_constructor ();
682 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
683 XMLNode* n = Config->extra_xml (X_("UI"));
685 _status_bar_visibility.set_state (*n);
688 check_memory_locking();
690 /* this is the first point at which all the possible actions are
691 * available, because some of the available actions are dependent on
692 * aspects of the engine/backend.
695 if (ARDOUR_COMMAND_LINE::show_key_actions) {
697 Bindings::save_all_bindings_as_html (sstr);
699 if (sstr.str().empty()) {
706 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
708 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
714 #ifdef PLATFORM_WINDOWS
720 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
721 #ifndef PLATFORM_WINDOWS
724 g_unlink (file_name);
726 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
732 #ifndef PLATFORM_WINDOWS
736 PBD::open_uri (string_compose ("file:///%1", file_name));
738 halt_connection.disconnect ();
739 AudioEngine::instance()->stop ();
744 if (ARDOUR_COMMAND_LINE::show_actions) {
747 vector<string> paths;
748 vector<string> labels;
749 vector<string> tooltips;
751 vector<Glib::RefPtr<Gtk::Action> > actions;
752 string ver_in = revision;
753 string ver = ver_in.substr(0, ver_in.find("-"));
756 output << "\n<h2>Menu actions</h2>" << endl;
757 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
758 output << " surfaces or scripts.\n</p>\n" << endl;
759 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
760 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
761 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
762 output << "<table class=\"dl\">\n <thead>" << endl;
763 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
764 output << " </thead>\n <tbody>" << endl;
766 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
768 vector<string>::iterator p;
769 vector<string>::iterator l;
771 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
772 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
773 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
775 output << " </tbody>\n </table>" << endl;
777 // output this mess to a browser for easiest X-platform use
778 // it is not pretty HTML, but it works and it's main purpose
779 // is to create raw html to fit in Ardour's manual with no editing
784 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
786 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
792 #ifdef PLATFORM_WINDOWS
798 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
799 #ifndef PLATFORM_WINDOWS
802 g_unlink (file_name);
804 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
810 #ifndef PLATFORM_WINDOWS
814 PBD::open_uri (string_compose ("file:///%1", file_name));
816 halt_connection.disconnect ();
817 AudioEngine::instance()->stop ();
821 /* this being a GUI and all, we want peakfiles */
823 AudioFileSource::set_build_peakfiles (true);
824 AudioFileSource::set_build_missing_peakfiles (true);
826 /* set default clock modes */
828 primary_clock->set_mode (AudioClock::Timecode);
829 secondary_clock->set_mode (AudioClock::BBT);
831 /* start the time-of-day-clock */
834 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
835 update_wall_clock ();
836 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
841 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
842 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
843 Config->map_parameters (pc);
845 UIConfiguration::instance().map_parameters (pc);
849 ARDOUR_UI::~ARDOUR_UI ()
851 UIConfiguration::instance().save_state();
855 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
856 // don't bother at 'real' exit. the OS cleans up for us.
857 delete big_clock; big_clock = 0;
858 delete primary_clock; primary_clock = 0;
859 delete secondary_clock; secondary_clock = 0;
860 delete _process_thread; _process_thread = 0;
861 delete time_info_box; time_info_box = 0;
862 delete meterbridge; meterbridge = 0;
863 delete luawindow; luawindow = 0;
864 delete editor; editor = 0;
865 delete mixer; mixer = 0;
866 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
868 delete gui_object_state; gui_object_state = 0;
869 delete main_window_visibility;
870 FastMeter::flush_pattern_cache ();
871 ArdourFader::flush_pattern_cache ();
875 /* Small trick to flush main-thread event pool.
876 * Other thread-pools are destroyed at pthread_exit(),
877 * but tmain thread termination is too late to trigger Pool::~Pool()
879 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.
880 delete ev->event_pool();
885 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
887 if (Splash::instance()) {
888 Splash::instance()->pop_back_for (win);
893 ARDOUR_UI::configure_timeout ()
895 if (last_configure_time == 0) {
896 /* no configure events yet */
900 /* force a gap of 0.5 seconds since the last configure event
903 if (get_microseconds() - last_configure_time < 500000) {
906 have_configure_timeout = false;
907 save_ardour_state ();
913 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
915 if (have_configure_timeout) {
916 last_configure_time = get_microseconds();
918 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
919 have_configure_timeout = true;
926 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
930 if (node.get_property ("roll", str)){
931 roll_controllable->set_id (str);
933 if (node.get_property ("stop", str)) {
934 stop_controllable->set_id (str);
936 if (node.get_property ("goto-start", str)) {
937 goto_start_controllable->set_id (str);
939 if (node.get_property ("goto-end", str)) {
940 goto_end_controllable->set_id (str);
942 if (node.get_property ("auto-loop", str)) {
943 auto_loop_controllable->set_id (str);
945 if (node.get_property ("play-selection", str)) {
946 play_selection_controllable->set_id (str);
948 if (node.get_property ("rec", str)) {
949 rec_controllable->set_id (str);
951 if (node.get_property ("shuttle", str)) {
952 shuttle_box.controllable()->set_id (str);
957 ARDOUR_UI::get_transport_controllable_state ()
959 XMLNode* node = new XMLNode(X_("TransportControllables"));
961 node->set_property (X_("roll"), roll_controllable->id());
962 node->set_property (X_("stop"), stop_controllable->id());
963 node->set_property (X_("goto-start"), goto_start_controllable->id());
964 node->set_property (X_("goto-end"), goto_end_controllable->id());
965 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
966 node->set_property (X_("play-selection"), play_selection_controllable->id());
967 node->set_property (X_("rec"), rec_controllable->id());
968 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
974 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
977 _session->save_state (snapshot_name);
982 ARDOUR_UI::autosave_session ()
984 if (g_main_depth() > 1) {
985 /* inside a recursive main loop,
986 give up because we may not be able to
992 if (!Config->get_periodic_safety_backups()) {
997 _session->maybe_write_autosave();
1004 ARDOUR_UI::session_dirty_changed ()
1011 ARDOUR_UI::update_autosave ()
1013 if (_session && _session->dirty()) {
1014 if (_autosave_connection.connected()) {
1015 _autosave_connection.disconnect();
1018 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1019 Config->get_periodic_safety_backup_interval() * 1000);
1022 if (_autosave_connection.connected()) {
1023 _autosave_connection.disconnect();
1029 ARDOUR_UI::check_announcements ()
1032 string _annc_filename;
1035 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1036 #elif defined PLATFORM_WINDOWS
1037 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1039 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1041 _annc_filename.append (VERSIONSTRING);
1043 _announce_string = "";
1045 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1046 FILE* fin = g_fopen (path.c_str(), "rb");
1048 while (!feof (fin)) {
1051 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1054 _announce_string.append (tmp, len);
1059 pingback (VERSIONSTRING, path);
1064 _hide_splash (gpointer arg)
1066 ((ARDOUR_UI*)arg)->hide_splash();
1071 ARDOUR_UI::starting ()
1073 Application* app = Application::instance ();
1074 const char *nsm_url;
1075 bool brand_new_user = ArdourStartup::required ();
1077 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1078 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1080 if (ARDOUR_COMMAND_LINE::check_announcements) {
1081 check_announcements ();
1086 /* we need to create this early because it may need to set the
1087 * audio backend end up.
1091 audio_midi_setup.get (true);
1093 std::cerr << "audio-midi engine setup failed."<< std::endl;
1097 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1098 nsm = new NSM_Client;
1099 if (!nsm->init (nsm_url)) {
1100 /* the ardour executable may have different names:
1102 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1103 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1104 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1106 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1108 const char *process_name = g_getenv ("ARDOUR_SELF");
1109 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1112 // wait for announce reply from nsm server
1113 for ( i = 0; i < 5000; ++i) {
1117 if (nsm->is_active()) {
1122 error << _("NSM server did not announce itself") << endmsg;
1125 // wait for open command from nsm server
1126 for ( i = 0; i < 5000; ++i) {
1128 Glib::usleep (1000);
1129 if (nsm->client_id ()) {
1135 error << _("NSM: no client ID provided") << endmsg;
1139 if (_session && nsm) {
1140 _session->set_nsm_state( nsm->is_active() );
1142 error << _("NSM: no session created") << endmsg;
1146 // nsm requires these actions disabled
1147 vector<string> action_names;
1148 action_names.push_back("SaveAs");
1149 action_names.push_back("Rename");
1150 action_names.push_back("New");
1151 action_names.push_back("Open");
1152 action_names.push_back("Recent");
1153 action_names.push_back("Close");
1155 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1156 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1158 act->set_sensitive (false);
1165 error << _("NSM: initialization failed") << endmsg;
1171 if (brand_new_user) {
1172 _initial_verbose_plugin_scan = true;
1177 _initial_verbose_plugin_scan = false;
1178 switch (s.response ()) {
1179 case Gtk::RESPONSE_OK:
1186 // TODO: maybe IFF brand_new_user
1187 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1188 std::string dspd (Config->get_default_session_parent_dir());
1189 Searchpath ds (ARDOUR::ardour_data_search_path());
1190 ds.add_subdirectory_to_paths ("sessions");
1191 vector<string> demos;
1192 find_files_matching_pattern (demos, ds, "*.tar.xz");
1194 ARDOUR::RecentSessions rs;
1195 ARDOUR::read_recent_sessions (rs);
1197 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1198 /* "demo-session" must be inside "demo-session.tar.xz"
1201 std::string name = basename_nosuffix (basename_nosuffix (*i));
1202 std::string path = Glib::build_filename (dspd, name);
1203 /* skip if session-dir already exists */
1204 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1207 /* skip sessions that are already in 'recent'.
1208 * eg. a new user changed <session-default-dir> shorly after installation
1210 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1211 if ((*r).first == name) {
1216 PBD::FileArchive ar (*i);
1217 if (0 == ar.inflate (dspd)) {
1218 store_recent_sessions (name, path);
1219 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1225 #ifdef NO_PLUGIN_STATE
1227 ARDOUR::RecentSessions rs;
1228 ARDOUR::read_recent_sessions (rs);
1230 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1232 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1234 /* already used Ardour, have sessions ... warn about plugin state */
1236 ArdourDialog d (_("Free/Demo Version Warning"), true);
1238 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1239 CheckButton c (_("Don't warn me about this again"));
1241 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"),
1242 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1243 _("It will not restore OR save any plugin settings"),
1244 _("If you load an existing session with plugin settings\n"
1245 "they will not be used and will be lost."),
1246 _("To get full access to updates without this limitation\n"
1247 "consider becoming a subscriber for a low cost every month.")));
1248 l.set_justify (JUSTIFY_CENTER);
1250 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1252 d.get_vbox()->pack_start (l, true, true);
1253 d.get_vbox()->pack_start (b, false, false, 12);
1254 d.get_vbox()->pack_start (c, false, false, 12);
1256 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1257 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1261 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1263 if (d.run () != RESPONSE_OK) {
1269 /* go get a session */
1271 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1273 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1274 std::cerr << "Cannot get session parameters."<< std::endl;
1281 WM::Manager::instance().show_visible ();
1283 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1284 * editor window, and we may want stuff to be hidden.
1286 _status_bar_visibility.update ();
1288 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1290 /* all other dialogs are created conditionally */
1296 ARDOUR_UI::check_memory_locking ()
1298 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1299 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1303 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1305 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1307 struct rlimit limits;
1309 long pages, page_size;
1311 size_t pages_len=sizeof(pages);
1312 if ((page_size = getpagesize()) < 0 ||
1313 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1315 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1320 ram = (int64_t) pages * (int64_t) page_size;
1323 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1327 if (limits.rlim_cur != RLIM_INFINITY) {
1329 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1333 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1334 "This might cause %1 to run out of memory before your system "
1335 "runs out of memory. \n\n"
1336 "You can view the memory limit with 'ulimit -l', "
1337 "and it is normally controlled by %2"),
1340 X_("/etc/login.conf")
1342 X_(" /etc/security/limits.conf")
1346 msg.set_default_response (RESPONSE_OK);
1348 VBox* vbox = msg.get_vbox();
1350 CheckButton cb (_("Do not show this window again"));
1351 hbox.pack_start (cb, true, false);
1352 vbox->pack_start (hbox);
1357 pop_back_splash (msg);
1361 if (cb.get_active()) {
1362 XMLNode node (X_("no-memory-warning"));
1363 Config->add_instant_xml (node);
1368 #endif // !__APPLE__
1373 ARDOUR_UI::queue_finish ()
1375 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1379 ARDOUR_UI::idle_finish ()
1382 return false; /* do not call again */
1389 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1391 if (_session->dirty()) {
1392 vector<string> actions;
1393 actions.push_back (_("Don't quit"));
1394 actions.push_back (_("Just quit"));
1395 actions.push_back (_("Save and quit"));
1396 switch (ask_about_saving_session(actions)) {
1401 /* use the default name */
1402 if (save_state_canfail ("")) {
1403 /* failed - don't quit */
1404 MessageDialog msg (_main_window,
1405 string_compose (_("\
1406 %1 was unable to save your session.\n\n\
1407 If you still wish to quit, please use the\n\n\
1408 \"Just quit\" option."), PROGRAM_NAME));
1409 pop_back_splash(msg);
1419 second_connection.disconnect ();
1420 point_one_second_connection.disconnect ();
1421 point_zero_something_second_connection.disconnect();
1422 fps_connection.disconnect();
1425 delete ARDOUR_UI::instance()->video_timeline;
1426 ARDOUR_UI::instance()->video_timeline = NULL;
1427 stop_video_server();
1429 /* Save state before deleting the session, as that causes some
1430 windows to be destroyed before their visible state can be
1433 save_ardour_state ();
1435 if (key_editor.get (false)) {
1436 key_editor->disconnect ();
1439 close_all_dialogs ();
1442 _session->set_clean ();
1443 _session->remove_pending_capture_state ();
1448 halt_connection.disconnect ();
1449 AudioEngine::instance()->stop ();
1450 #ifdef WINDOWS_VST_SUPPORT
1451 fst_stop_threading();
1457 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1459 ArdourDialog window (_("Unsaved Session"));
1460 Gtk::HBox dhbox; // the hbox for the image and text
1461 Gtk::Label prompt_label;
1462 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1466 assert (actions.size() >= 3);
1468 window.add_button (actions[0], RESPONSE_REJECT);
1469 window.add_button (actions[1], RESPONSE_APPLY);
1470 window.add_button (actions[2], RESPONSE_ACCEPT);
1472 window.set_default_response (RESPONSE_ACCEPT);
1474 Gtk::Button noquit_button (msg);
1475 noquit_button.set_name ("EditorGTKButton");
1479 if (_session->snap_name() == _session->name()) {
1480 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?"),
1481 _session->snap_name());
1483 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?"),
1484 _session->snap_name());
1487 prompt_label.set_text (prompt);
1488 prompt_label.set_name (X_("PrompterLabel"));
1489 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1491 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1492 dhbox.set_homogeneous (false);
1493 dhbox.pack_start (*dimage, false, false, 5);
1494 dhbox.pack_start (prompt_label, true, false, 5);
1495 window.get_vbox()->pack_start (dhbox);
1497 window.set_name (_("Prompter"));
1498 window.set_modal (true);
1499 window.set_resizable (false);
1502 prompt_label.show();
1507 ResponseType r = (ResponseType) window.run();
1512 case RESPONSE_ACCEPT: // save and get out of here
1514 case RESPONSE_APPLY: // get out of here
1525 ARDOUR_UI::every_second ()
1528 update_xrun_count ();
1529 update_buffer_load ();
1530 update_disk_space ();
1531 update_timecode_format ();
1532 update_peak_thread_work ();
1534 if (nsm && nsm->is_active ()) {
1537 if (!_was_dirty && _session->dirty ()) {
1541 else if (_was_dirty && !_session->dirty ()){
1549 ARDOUR_UI::every_point_one_seconds ()
1551 // TODO get rid of this..
1552 // ShuttleControl is updated directly via TransportStateChange signal
1556 ARDOUR_UI::every_point_zero_something_seconds ()
1558 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1560 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1561 float mpeak = editor_meter->update_meters();
1562 if (mpeak > editor_meter_max_peak) {
1563 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1564 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1571 ARDOUR_UI::set_fps_timeout_connection ()
1573 unsigned int interval = 40;
1574 if (!_session) return;
1575 if (_session->timecode_frames_per_second() != 0) {
1576 /* ideally we'll use a select() to sleep and not accumulate
1577 * idle time to provide a regular periodic signal.
1578 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1579 * However, that'll require a dedicated thread and cross-thread
1580 * signals to the GUI Thread..
1582 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1583 * _session->frame_rate() / _session->nominal_frame_rate()
1584 / _session->timecode_frames_per_second()
1586 #ifdef PLATFORM_WINDOWS
1587 // the smallest windows scheduler time-slice is ~15ms.
1588 // periodic GUI timeouts shorter than that will cause
1589 // WaitForSingleObject to spinlock (100% of one CPU Core)
1590 // and gtk never enters idle mode.
1591 // also changing timeBeginPeriod(1) does not affect that in
1592 // any beneficial way, so we just limit the max rate for now.
1593 interval = std::max(30u, interval); // at most ~33Hz.
1595 interval = std::max(8u, interval); // at most 120Hz.
1598 fps_connection.disconnect();
1599 Timers::set_fps_interval (interval);
1603 ARDOUR_UI::update_sample_rate (framecnt_t)
1607 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1609 if (!AudioEngine::instance()->connected()) {
1611 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1615 framecnt_t rate = AudioEngine::instance()->sample_rate();
1618 /* no sample rate available */
1619 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1622 if (fmod (rate, 1000.0) != 0.0) {
1623 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1624 (float) rate / 1000.0f,
1625 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1627 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1629 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1633 sample_rate_label.set_markup (buf);
1637 ARDOUR_UI::update_format ()
1640 format_label.set_text ("");
1645 s << _("File:") << X_(" <span foreground=\"green\">");
1647 switch (_session->config.get_native_file_header_format ()) {
1679 switch (_session->config.get_native_file_data_format ()) {
1693 format_label.set_markup (s.str ());
1697 ARDOUR_UI::update_xrun_count ()
1701 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1702 should also be changed.
1706 const unsigned int x = _session->get_xrun_count ();
1708 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1710 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1713 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1715 xrun_label.set_markup (buf);
1716 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1720 ARDOUR_UI::update_cpu_load ()
1724 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1725 should also be changed.
1728 double const c = AudioEngine::instance()->get_dsp_load ();
1729 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1730 cpu_load_label.set_markup (buf);
1734 ARDOUR_UI::update_peak_thread_work ()
1737 const int c = SourceFactory::peak_work_queue_length ();
1739 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1740 peak_thread_work_label.set_markup (buf);
1742 peak_thread_work_label.set_markup (X_(""));
1747 ARDOUR_UI::update_buffer_load ()
1751 uint32_t const playback = _session ? _session->playback_load () : 100;
1752 uint32_t const capture = _session ? _session->capture_load () : 100;
1754 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1755 should also be changed.
1761 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1762 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1763 playback <= 5 ? X_("red") : X_("green"),
1765 capture <= 5 ? X_("red") : X_("green"),
1769 buffer_load_label.set_markup (buf);
1771 buffer_load_label.set_text ("");
1776 ARDOUR_UI::count_recenabled_streams (Route& route)
1778 Track* track = dynamic_cast<Track*>(&route);
1779 if (track && track->rec_enable_control()->get_value()) {
1780 rec_enabled_streams += track->n_inputs().n_total();
1785 ARDOUR_UI::update_disk_space()
1787 if (_session == 0) {
1791 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1793 framecnt_t fr = _session->frame_rate();
1796 /* skip update - no SR available */
1801 /* Available space is unknown */
1802 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1803 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1804 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1806 rec_enabled_streams = 0;
1807 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1809 framecnt_t frames = opt_frames.get_value_or (0);
1811 if (rec_enabled_streams) {
1812 frames /= rec_enabled_streams;
1819 hrs = frames / (fr * 3600);
1822 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1824 frames -= hrs * fr * 3600;
1825 mins = frames / (fr * 60);
1826 frames -= mins * fr * 60;
1829 bool const low = (hrs == 0 && mins <= 30);
1833 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1834 low ? X_("red") : X_("green"),
1840 disk_space_label.set_markup (buf);
1844 ARDOUR_UI::update_timecode_format ()
1850 TimecodeSlave* tcslave;
1851 SyncSource sync_src = Config->get_sync_source();
1853 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1854 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1859 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1860 matching ? X_("green") : X_("red"),
1861 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1863 snprintf (buf, sizeof (buf), "TC: n/a");
1866 timecode_format_label.set_markup (buf);
1870 ARDOUR_UI::update_wall_clock ()
1874 static int last_min = -1;
1877 tm_now = localtime (&now);
1878 if (last_min != tm_now->tm_min) {
1880 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1881 wall_clock_label.set_text (buf);
1882 last_min = tm_now->tm_min;
1889 ARDOUR_UI::open_recent_session ()
1891 bool can_return = (_session != 0);
1893 SessionDialog recent_session_dialog;
1897 ResponseType r = (ResponseType) recent_session_dialog.run ();
1900 case RESPONSE_ACCEPT:
1904 recent_session_dialog.hide();
1911 recent_session_dialog.hide();
1915 std::string path = recent_session_dialog.session_folder();
1916 std::string state = recent_session_dialog.session_name (should_be_new);
1918 if (should_be_new == true) {
1922 _session_is_new = false;
1924 if (load_session (path, state) == 0) {
1933 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1935 if (!AudioEngine::instance()->connected()) {
1936 MessageDialog msg (parent, string_compose (
1937 _("%1 is not connected to any audio backend.\n"
1938 "You cannot open or close sessions in this condition"),
1940 pop_back_splash (msg);
1948 ARDOUR_UI::open_session ()
1950 if (!check_audioengine (_main_window)) {
1954 /* ardour sessions are folders */
1955 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1956 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1957 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1958 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1961 string session_parent_dir = Glib::path_get_dirname(_session->path());
1962 open_session_selector.set_current_folder(session_parent_dir);
1964 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1967 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1969 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1970 string default_session_folder = Config->get_default_session_parent_dir();
1971 open_session_selector.add_shortcut_folder (default_session_folder);
1973 catch (Glib::Error & e) {
1974 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1977 FileFilter session_filter;
1978 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1979 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1980 open_session_selector.add_filter (session_filter);
1982 FileFilter archive_filter;
1983 archive_filter.add_pattern (X_("*.tar.xz"));
1984 archive_filter.set_name (_("Session Archives"));
1986 open_session_selector.add_filter (archive_filter);
1988 open_session_selector.set_filter (session_filter);
1990 int response = open_session_selector.run();
1991 open_session_selector.hide ();
1993 if (response == Gtk::RESPONSE_CANCEL) {
1997 string session_path = open_session_selector.get_filename();
2001 if (session_path.length() > 0) {
2002 int rv = ARDOUR::inflate_session (session_path,
2003 Config->get_default_session_parent_dir(), path, name);
2005 _session_is_new = false;
2006 load_session (path, name);
2009 MessageDialog msg (_main_window,
2010 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2013 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2014 _session_is_new = isnew;
2015 load_session (path, name);
2021 ARDOUR_UI::session_add_mixed_track (
2022 const ChanCount& input,
2023 const ChanCount& output,
2024 RouteGroup* route_group,
2026 const string& name_template,
2028 PluginInfoPtr instrument,
2029 Plugin::PresetRecord* pset,
2030 ARDOUR::PresentationInfo::order_t order)
2034 if (Profile->get_mixbus ()) {
2039 list<boost::shared_ptr<MidiTrack> > tracks;
2040 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2042 if (tracks.size() != how_many) {
2043 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2048 display_insufficient_ports_message ();
2054 ARDOUR_UI::session_add_midi_bus (
2055 RouteGroup* route_group,
2057 const string& name_template,
2059 PluginInfoPtr instrument,
2060 Plugin::PresetRecord* pset,
2061 ARDOUR::PresentationInfo::order_t order)
2063 if (_session == 0) {
2064 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2068 if (Profile->get_mixbus ()) {
2074 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2075 if (routes.size() != how_many) {
2076 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2081 display_insufficient_ports_message ();
2087 ARDOUR_UI::session_add_midi_route (
2089 RouteGroup* route_group,
2091 const string& name_template,
2093 PluginInfoPtr instrument,
2094 Plugin::PresetRecord* pset,
2095 ARDOUR::PresentationInfo::order_t order)
2097 ChanCount one_midi_channel;
2098 one_midi_channel.set (DataType::MIDI, 1);
2101 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2103 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2108 ARDOUR_UI::session_add_audio_route (
2110 int32_t input_channels,
2111 int32_t output_channels,
2112 ARDOUR::TrackMode mode,
2113 RouteGroup* route_group,
2115 string const & name_template,
2117 ARDOUR::PresentationInfo::order_t order)
2119 list<boost::shared_ptr<AudioTrack> > tracks;
2126 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2128 if (tracks.size() != how_many) {
2129 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2135 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2137 if (routes.size() != how_many) {
2138 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2145 display_insufficient_ports_message ();
2150 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2151 (*i)->set_strict_io (true);
2153 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2154 (*i)->set_strict_io (true);
2160 ARDOUR_UI::display_insufficient_ports_message ()
2162 MessageDialog msg (_main_window,
2163 string_compose (_("There are insufficient ports available\n\
2164 to create a new track or bus.\n\
2165 You should save %1, exit and\n\
2166 restart with more ports."), PROGRAM_NAME));
2167 pop_back_splash (msg);
2172 ARDOUR_UI::transport_goto_start ()
2175 _session->goto_start();
2177 /* force displayed area in editor to start no matter
2178 what "follow playhead" setting is.
2182 editor->center_screen (_session->current_start_frame ());
2188 ARDOUR_UI::transport_goto_zero ()
2191 _session->request_locate (0);
2193 /* force displayed area in editor to start no matter
2194 what "follow playhead" setting is.
2198 editor->reset_x_origin (0);
2204 ARDOUR_UI::transport_goto_wallclock ()
2206 if (_session && editor) {
2213 localtime_r (&now, &tmnow);
2215 framecnt_t frame_rate = _session->frame_rate();
2217 if (frame_rate == 0) {
2218 /* no frame rate available */
2222 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2223 frames += tmnow.tm_min * (60 * frame_rate);
2224 frames += tmnow.tm_sec * frame_rate;
2226 _session->request_locate (frames, _session->transport_rolling ());
2228 /* force displayed area in editor to start no matter
2229 what "follow playhead" setting is.
2233 editor->center_screen (frames);
2239 ARDOUR_UI::transport_goto_end ()
2242 framepos_t const frame = _session->current_end_frame();
2243 _session->request_locate (frame);
2245 /* force displayed area in editor to start no matter
2246 what "follow playhead" setting is.
2250 editor->center_screen (frame);
2256 ARDOUR_UI::transport_stop ()
2262 if (_session->is_auditioning()) {
2263 _session->cancel_audition ();
2267 _session->request_stop (false, true);
2270 /** Check if any tracks are record enabled. If none are, record enable all of them.
2271 * @return true if track record-enabled status was changed, false otherwise.
2274 ARDOUR_UI::trx_record_enable_all_tracks ()
2280 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2281 bool none_record_enabled = true;
2283 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2284 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2287 if (t->rec_enable_control()->get_value()) {
2288 none_record_enabled = false;
2293 if (none_record_enabled) {
2294 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2297 return none_record_enabled;
2301 ARDOUR_UI::transport_record (bool roll)
2304 switch (_session->record_status()) {
2305 case Session::Disabled:
2306 if (_session->ntracks() == 0) {
2307 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."));
2311 if (Profile->get_trx()) {
2312 roll = trx_record_enable_all_tracks ();
2314 _session->maybe_enable_record ();
2319 case Session::Recording:
2321 _session->request_stop();
2323 _session->disable_record (false, true);
2327 case Session::Enabled:
2328 _session->disable_record (false, true);
2334 ARDOUR_UI::transport_roll ()
2340 if (_session->is_auditioning()) {
2345 if (_session->config.get_external_sync()) {
2346 switch (Config->get_sync_source()) {
2350 /* transport controlled by the master */
2356 bool rolling = _session->transport_rolling();
2358 if (_session->get_play_loop()) {
2360 /* If loop playback is not a mode, then we should cancel
2361 it when this action is requested. If it is a mode
2362 we just leave it in place.
2365 if (!Config->get_loop_is_mode()) {
2366 /* XXX it is not possible to just leave seamless loop and keep
2367 playing at present (nov 4th 2009)
2369 if (!Config->get_seamless_loop()) {
2370 /* stop loop playback and stop rolling */
2371 _session->request_play_loop (false, true);
2372 } else if (rolling) {
2373 /* stop loop playback but keep rolling */
2374 _session->request_play_loop (false, false);
2378 } else if (_session->get_play_range () ) {
2379 /* stop playing a range if we currently are */
2380 _session->request_play_range (0, true);
2384 _session->request_transport_speed (1.0f);
2389 ARDOUR_UI::get_smart_mode() const
2391 return ( editor->get_smart_mode() );
2396 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2402 if (_session->is_auditioning()) {
2403 _session->cancel_audition ();
2407 if (_session->config.get_external_sync()) {
2408 switch (Config->get_sync_source()) {
2412 /* transport controlled by the master */
2417 bool rolling = _session->transport_rolling();
2418 bool affect_transport = true;
2420 if (rolling && roll_out_of_bounded_mode) {
2421 /* drop out of loop/range playback but leave transport rolling */
2422 if (_session->get_play_loop()) {
2423 if (_session->actively_recording()) {
2425 /* just stop using the loop, then actually stop
2428 _session->request_play_loop (false, affect_transport);
2431 if (Config->get_seamless_loop()) {
2432 /* the disk buffers contain copies of the loop - we can't
2433 just keep playing, so stop the transport. the user
2434 can restart as they wish.
2436 affect_transport = true;
2438 /* disk buffers are normal, so we can keep playing */
2439 affect_transport = false;
2441 _session->request_play_loop (false, affect_transport);
2443 } else if (_session->get_play_range ()) {
2444 affect_transport = false;
2445 _session->request_play_range (0, true);
2449 if (affect_transport) {
2451 _session->request_stop (with_abort, true);
2453 } else if (!with_abort) { /* with_abort == true means the
2454 * command was intended to stop
2455 * transport, not start.
2458 /* the only external sync condition we can be in here
2459 * would be Engine (JACK) sync, in which case we still
2463 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
2464 _session->request_play_range (&editor->get_selection().time, true);
2465 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2467 _session->request_transport_speed (1.0f);
2473 ARDOUR_UI::toggle_session_auto_loop ()
2479 Location * looploc = _session->locations()->auto_loop_location();
2485 if (_session->get_play_loop()) {
2487 /* looping enabled, our job is to disable it */
2489 _session->request_play_loop (false);
2493 /* looping not enabled, our job is to enable it.
2495 loop-is-NOT-mode: this action always starts the transport rolling.
2496 loop-IS-mode: this action simply sets the loop play mechanism, but
2497 does not start transport.
2499 if (Config->get_loop_is_mode()) {
2500 _session->request_play_loop (true, false);
2502 _session->request_play_loop (true, true);
2506 //show the loop markers
2507 looploc->set_hidden (false, this);
2511 ARDOUR_UI::transport_play_selection ()
2517 editor->play_selection ();
2521 ARDOUR_UI::transport_play_preroll ()
2526 editor->play_with_preroll ();
2530 ARDOUR_UI::transport_rec_preroll ()
2535 editor->rec_with_preroll ();
2539 ARDOUR_UI::transport_rec_count_in ()
2544 editor->rec_with_count_in ();
2548 ARDOUR_UI::transport_rewind (int option)
2550 float current_transport_speed;
2553 current_transport_speed = _session->transport_speed();
2555 if (current_transport_speed >= 0.0f) {
2558 _session->request_transport_speed (-1.0f);
2561 _session->request_transport_speed (-4.0f);
2564 _session->request_transport_speed (-0.5f);
2569 _session->request_transport_speed (current_transport_speed * 1.5f);
2575 ARDOUR_UI::transport_forward (int option)
2581 float current_transport_speed = _session->transport_speed();
2583 if (current_transport_speed <= 0.0f) {
2586 _session->request_transport_speed (1.0f);
2589 _session->request_transport_speed (4.0f);
2592 _session->request_transport_speed (0.5f);
2597 _session->request_transport_speed (current_transport_speed * 1.5f);
2602 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2608 boost::shared_ptr<Route> r;
2610 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2612 boost::shared_ptr<Track> t;
2614 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2615 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2621 ARDOUR_UI::map_transport_state ()
2624 auto_loop_button.unset_active_state ();
2625 play_selection_button.unset_active_state ();
2626 roll_button.unset_active_state ();
2627 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2628 layered_button.set_sensitive (false);
2632 shuttle_box.map_transport_state ();
2634 float sp = _session->transport_speed();
2640 if (_session->get_play_range()) {
2642 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2643 roll_button.unset_active_state ();
2644 auto_loop_button.unset_active_state ();
2646 } else if (_session->get_play_loop ()) {
2648 auto_loop_button.set_active (true);
2649 play_selection_button.set_active (false);
2650 if (Config->get_loop_is_mode()) {
2651 roll_button.set_active (true);
2653 roll_button.set_active (false);
2658 roll_button.set_active (true);
2659 play_selection_button.set_active (false);
2660 auto_loop_button.set_active (false);
2663 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2664 /* light up both roll and play-selection if they are joined */
2665 roll_button.set_active (true);
2666 play_selection_button.set_active (true);
2668 layered_button.set_sensitive (!_session->actively_recording ());
2670 stop_button.set_active (false);
2674 layered_button.set_sensitive (true);
2675 stop_button.set_active (true);
2676 roll_button.set_active (false);
2677 play_selection_button.set_active (false);
2678 if (Config->get_loop_is_mode ()) {
2679 auto_loop_button.set_active (_session->get_play_loop());
2681 auto_loop_button.set_active (false);
2683 update_disk_space ();
2688 ARDOUR_UI::blink_handler (bool blink_on)
2690 transport_rec_enable_blink (blink_on);
2691 sync_blink (blink_on);
2693 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2696 error_blink (blink_on);
2697 solo_blink (blink_on);
2698 audition_blink (blink_on);
2699 feedback_blink (blink_on);
2703 ARDOUR_UI::update_clocks ()
2705 if (!_session) return;
2707 if (editor && !editor->dragging_playhead()) {
2708 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2713 ARDOUR_UI::start_clocking ()
2715 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2716 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2718 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2723 ARDOUR_UI::stop_clocking ()
2725 clock_signal_connection.disconnect ();
2729 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2733 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2735 label->set_text (buf);
2736 bar->set_fraction (fraction);
2738 /* process events, redraws, etc. */
2740 while (gtk_events_pending()) {
2741 gtk_main_iteration ();
2744 return true; /* continue with save-as */
2748 ARDOUR_UI::save_session_as ()
2754 if (_session->dirty()) {
2755 vector<string> actions;
2756 actions.push_back (_("Abort save-as"));
2757 actions.push_back (_("Don't save now, just save-as"));
2758 actions.push_back (_("Save it first"));
2759 switch (ask_about_saving_session(actions)) {
2764 if (save_state_canfail ("")) {
2765 MessageDialog msg (_main_window,
2766 string_compose (_("\
2767 %1 was unable to save your session.\n\n\
2768 If you still wish to proceeed, please use the\n\n\
2769 \"Don't save now\" option."), PROGRAM_NAME));
2770 pop_back_splash(msg);
2776 _session->remove_pending_capture_state ();
2781 if (!save_as_dialog) {
2782 save_as_dialog = new SaveAsDialog;
2785 save_as_dialog->set_name (_session->name());
2787 int response = save_as_dialog->run ();
2789 save_as_dialog->hide ();
2792 case Gtk::RESPONSE_OK:
2801 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2802 sa.new_name = save_as_dialog->new_name ();
2803 sa.switch_to = save_as_dialog->switch_to();
2804 sa.copy_media = save_as_dialog->copy_media();
2805 sa.copy_external = save_as_dialog->copy_external();
2806 sa.include_media = save_as_dialog->include_media ();
2808 /* Only bother with a progress dialog if we're going to copy
2809 media into the save-as target. Without that choice, this
2810 will be very fast because we're only talking about a few kB's to
2811 perhaps a couple of MB's of data.
2814 ArdourDialog progress_dialog (_("Save As"), true);
2817 if (sa.include_media && sa.copy_media) {
2819 Gtk::Label* label = manage (new Gtk::Label());
2820 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2822 progress_dialog.get_vbox()->pack_start (*label);
2823 progress_dialog.get_vbox()->pack_start (*progress_bar);
2825 progress_bar->show ();
2827 /* this signal will be emitted from within this, the calling thread,
2828 * after every file is copied. It provides information on percentage
2829 * complete (in terms of total data to copy), the number of files
2830 * copied so far, and the total number to copy.
2833 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2835 progress_dialog.show_all ();
2836 progress_dialog.present ();
2839 if (_session->save_as (sa)) {
2841 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2845 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2846 * the trick is this: if the new session was copy with media included,
2847 * then Session::save_as() will have already done a neat trick to avoid
2848 * us having to unload and load the new state. But if the media was not
2849 * included, then this is required (it avoids us having to otherwise
2850 * drop all references to media (sources).
2853 if (!sa.include_media && sa.switch_to) {
2854 unload_session (false);
2855 load_session (sa.final_session_folder_name, sa.new_name);
2860 ARDOUR_UI::archive_session ()
2868 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2870 SessionArchiveDialog sad;
2871 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2872 int response = sad.run ();
2874 if (response != Gtk::RESPONSE_OK) {
2879 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2880 MessageDialog msg (_("Session Archiving failed."));
2886 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2890 struct tm local_time;
2893 localtime_r (&n, &local_time);
2894 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2895 if (switch_to_it && _session->dirty ()) {
2896 save_state_canfail ("");
2899 save_state (timebuf, switch_to_it);
2904 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2908 prompter.get_result (snapname);
2910 bool do_save = (snapname.length() != 0);
2913 char illegal = Session::session_name_is_legal(snapname);
2915 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2916 "snapshot names may not contain a '%1' character"), illegal));
2922 vector<std::string> p;
2923 get_state_files_in_directory (_session->session_directory().root_path(), p);
2924 vector<string> n = get_file_names_no_extension (p);
2926 if (find (n.begin(), n.end(), snapname) != n.end()) {
2928 do_save = overwrite_file_dialog (prompter,
2929 _("Confirm Snapshot Overwrite"),
2930 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2934 save_state (snapname, switch_to_it);
2944 /** Ask the user for the name of a new snapshot and then take it.
2948 ARDOUR_UI::snapshot_session (bool switch_to_it)
2950 if (switch_to_it && _session->dirty()) {
2951 vector<string> actions;
2952 actions.push_back (_("Abort saving snapshot"));
2953 actions.push_back (_("Don't save now, just snapshot"));
2954 actions.push_back (_("Save it first"));
2955 switch (ask_about_saving_session(actions)) {
2960 if (save_state_canfail ("")) {
2961 MessageDialog msg (_main_window,
2962 string_compose (_("\
2963 %1 was unable to save your session.\n\n\
2964 If you still wish to proceeed, please use the\n\n\
2965 \"Don't save now\" option."), PROGRAM_NAME));
2966 pop_back_splash(msg);
2972 _session->remove_pending_capture_state ();
2977 Prompter prompter (true);
2978 prompter.set_name ("Prompter");
2979 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2981 prompter.set_title (_("Snapshot and switch"));
2982 prompter.set_prompt (_("New session name"));
2984 prompter.set_title (_("Take Snapshot"));
2985 prompter.set_prompt (_("Name of new snapshot"));
2989 prompter.set_initial_text (_session->snap_name());
2991 Glib::DateTime tm (g_date_time_new_now_local ());
2992 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2995 bool finished = false;
2997 switch (prompter.run()) {
2998 case RESPONSE_ACCEPT:
3000 finished = process_snapshot_session_prompter (prompter, switch_to_it);
3011 /** Ask the user for a new session name and then rename the session to it.
3015 ARDOUR_UI::rename_session ()
3021 Prompter prompter (true);
3024 prompter.set_name ("Prompter");
3025 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3026 prompter.set_title (_("Rename Session"));
3027 prompter.set_prompt (_("New session name"));
3030 switch (prompter.run()) {
3031 case RESPONSE_ACCEPT:
3033 prompter.get_result (name);
3035 bool do_rename = (name.length() != 0);
3038 char illegal = Session::session_name_is_legal (name);
3041 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3042 "session names may not contain a '%1' character"), illegal));
3047 switch (_session->rename (name)) {
3049 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3050 msg.set_position (WIN_POS_MOUSE);
3058 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3059 msg.set_position (WIN_POS_MOUSE);
3075 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3077 if (!_session || _session->deletion_in_progress()) {
3081 XMLNode* node = new XMLNode (X_("UI"));
3083 WM::Manager::instance().add_state (*node);
3085 node->add_child_nocopy (gui_object_state->get_state());
3087 _session->add_extra_xml (*node);
3089 if (export_video_dialog) {
3090 _session->add_extra_xml (export_video_dialog->get_state());
3093 save_state_canfail (name, switch_to_it);
3097 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3102 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3107 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3112 ARDOUR_UI::primary_clock_value_changed ()
3115 _session->request_locate (primary_clock->current_time ());
3120 ARDOUR_UI::big_clock_value_changed ()
3123 _session->request_locate (big_clock->current_time ());
3128 ARDOUR_UI::secondary_clock_value_changed ()
3131 _session->request_locate (secondary_clock->current_time ());
3136 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3138 if (_session == 0) {
3142 if (_session->step_editing()) {
3146 Session::RecordState const r = _session->record_status ();
3147 bool const h = _session->have_rec_enabled_track ();
3149 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3151 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3153 rec_button.set_active_state (Gtkmm2ext::Off);
3155 } else if (r == Session::Recording && h) {
3156 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3158 rec_button.unset_active_state ();
3163 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3165 if (response == RESPONSE_ACCEPT) {
3166 const string name = d->get_template_name ();
3167 const string desc = d->get_description ();
3169 int failed = _session->save_template (name, desc);
3171 if (failed == -2) { /* file already exists. */
3172 bool overwrite = overwrite_file_dialog (*d,
3173 _("Confirm Template Overwrite"),
3174 _("A template already exists with that name. Do you want to overwrite it?"));
3177 _session->save_template (name, desc, true);
3189 ARDOUR_UI::save_template ()
3191 if (!check_audioengine (_main_window)) {
3195 const std::string desc = SessionMetadata::Metadata()->description ();
3196 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3197 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3201 void ARDOUR_UI::manage_templates ()
3208 ARDOUR_UI::edit_metadata ()
3210 SessionMetadataEditor dialog;
3211 dialog.set_session (_session);
3212 dialog.grab_focus ();
3217 ARDOUR_UI::import_metadata ()
3219 SessionMetadataImporter dialog;
3220 dialog.set_session (_session);
3225 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3227 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3229 MessageDialog msg (str,
3231 Gtk::MESSAGE_WARNING,
3232 Gtk::BUTTONS_YES_NO,
3236 msg.set_name (X_("OpenExistingDialog"));
3237 msg.set_title (_("Open Existing Session"));
3238 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3239 msg.set_position (Gtk::WIN_POS_CENTER);
3240 pop_back_splash (msg);
3242 switch (msg.run()) {
3251 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3253 BusProfile bus_profile;
3256 bus_profile.master_out_channels = 2;
3258 /* get settings from advanced section of NSD */
3259 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3262 // NULL profile: no master, no monitor
3263 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3271 ARDOUR_UI::load_from_application_api (const std::string& path)
3273 /* OS X El Capitan (and probably later) now somehow passes the command
3274 line arguments to an app via the openFile delegate protocol. Ardour
3275 already does its own command line processing, and having both
3276 pathways active causes crashes. So, if the command line was already
3277 set, do nothing here.
3280 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3284 ARDOUR_COMMAND_LINE::session_name = path;
3286 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3288 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3290 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3291 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3292 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3293 * -> SessionDialog is not displayed
3296 if (_session_dialog) {
3297 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3298 std::string session_path = path;
3299 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3300 session_path = Glib::path_get_dirname (session_path);
3302 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3303 _session_dialog->set_provided_session (session_name, session_path);
3304 _session_dialog->response (RESPONSE_NONE);
3305 _session_dialog->hide();
3310 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3311 /* /path/to/foo => /path/to/foo, foo */
3312 rv = load_session (path, basename_nosuffix (path));
3314 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3315 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3318 // if load_session fails -> pop up SessionDialog.
3320 ARDOUR_COMMAND_LINE::session_name = "";
3322 if (get_session_parameters (true, false)) {
3328 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3330 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3332 string session_name;
3333 string session_path;
3334 string template_name;
3336 bool likely_new = false;
3337 bool cancel_not_quit;
3339 /* deal with any existing DIRTY session now, rather than later. don't
3340 * treat a non-dirty session this way, so that it stays visible
3341 * as we bring up the new session dialog.
3344 if (_session && ARDOUR_UI::instance()->video_timeline) {
3345 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3348 /* if there is already a session, relabel the button
3349 on the SessionDialog so that we don't Quit directly
3351 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3353 if (_session && _session->dirty()) {
3354 if (unload_session (false)) {
3355 /* unload cancelled by user */
3358 ARDOUR_COMMAND_LINE::session_name = "";
3361 if (!load_template.empty()) {
3362 should_be_new = true;
3363 template_name = load_template;
3366 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3367 session_path = ARDOUR_COMMAND_LINE::session_name;
3369 if (!session_path.empty()) {
3370 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3371 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3372 /* session/snapshot file, change path to be dir */
3373 session_path = Glib::path_get_dirname (session_path);
3378 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3380 _session_dialog = &session_dialog;
3383 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3385 /* if they named a specific statefile, use it, otherwise they are
3386 just giving a session folder, and we want to use it as is
3387 to find the session.
3390 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3392 if (suffix != string::npos) {
3393 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3394 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3395 session_name = Glib::path_get_basename (session_name);
3397 session_path = ARDOUR_COMMAND_LINE::session_name;
3398 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3403 session_dialog.clear_given ();
3406 if (should_be_new || session_name.empty()) {
3407 /* need the dialog to get info from user */
3409 cerr << "run dialog\n";
3411 switch (session_dialog.run()) {
3412 case RESPONSE_ACCEPT:
3415 /* this is used for async * app->ShouldLoad(). */
3416 continue; // while loop
3419 if (quit_on_cancel) {
3420 ARDOUR_UI::finish ();
3421 Gtkmm2ext::Application::instance()->cleanup();
3423 pthread_cancel_all ();
3424 return -1; // caller is responsible to call exit()
3430 session_dialog.hide ();
3433 /* if we run the startup dialog again, offer more than just "new session" */
3435 should_be_new = false;
3437 session_name = session_dialog.session_name (likely_new);
3438 session_path = session_dialog.session_folder ();
3445 int rv = ARDOUR::inflate_session (session_name,
3446 Config->get_default_session_parent_dir(), session_path, session_name);
3448 MessageDialog msg (session_dialog,
3449 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3454 session_dialog.set_provided_session (session_name, session_path);
3458 // XXX check archive, inflate
3459 string::size_type suffix = session_name.find (statefile_suffix);
3461 if (suffix != string::npos) {
3462 session_name = session_name.substr (0, suffix);
3465 /* this shouldn't happen, but we catch it just in case it does */
3467 if (session_name.empty()) {
3471 if (session_dialog.use_session_template()) {
3472 template_name = session_dialog.session_template_name();
3473 _session_is_new = true;
3476 if (session_name[0] == G_DIR_SEPARATOR ||
3477 #ifdef PLATFORM_WINDOWS
3478 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3480 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3481 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3486 /* absolute path or cwd-relative path specified for session name: infer session folder
3487 from what was given.
3490 session_path = Glib::path_get_dirname (session_name);
3491 session_name = Glib::path_get_basename (session_name);
3495 session_path = session_dialog.session_folder();
3497 char illegal = Session::session_name_is_legal (session_name);
3500 MessageDialog msg (session_dialog,
3501 string_compose (_("To ensure compatibility with various systems\n"
3502 "session names may not contain a '%1' character"),
3505 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3510 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3513 if (likely_new && !nsm) {
3515 std::string existing = Glib::build_filename (session_path, session_name);
3517 if (!ask_about_loading_existing_session (existing)) {
3518 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3523 _session_is_new = false;
3528 pop_back_splash (session_dialog);
3529 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3531 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3535 char illegal = Session::session_name_is_legal(session_name);
3538 pop_back_splash (session_dialog);
3539 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3540 "session names may not contain a '%1' character"), illegal));
3542 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3546 _session_is_new = true;
3549 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3551 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3552 meta_session_setup (template_name.substr (11));
3554 } else if (likely_new && template_name.empty()) {
3556 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3560 ret = load_session (session_path, session_name, template_name);
3563 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3567 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3568 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3572 /* clear this to avoid endless attempts to load the
3576 ARDOUR_COMMAND_LINE::session_name = "";
3580 _session_dialog = NULL;
3586 ARDOUR_UI::close_session()
3588 if (!check_audioengine (_main_window)) {
3592 if (unload_session (true)) {
3596 ARDOUR_COMMAND_LINE::session_name = "";
3598 if (get_session_parameters (true, false)) {
3603 /** @param snap_name Snapshot name (without .ardour suffix).
3604 * @return -2 if the load failed because we are not connected to the AudioEngine.
3607 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3609 /* load_session calls flush_pending() which allows
3610 * GUI interaction and potentially loading another session
3611 * (that was easy via snapshot sidebar).
3612 * Recursing into load_session() from load_session() and recusive
3613 * event loops causes all kind of crashes.
3615 assert (!session_load_in_progress);
3616 if (session_load_in_progress) {
3619 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3621 Session *new_session;
3626 unload_status = unload_session ();
3628 if (unload_status < 0) {
3630 } else if (unload_status > 0) {
3636 session_loaded = false;
3638 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3641 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3644 /* this one is special */
3646 catch (AudioEngine::PortRegistrationFailure& err) {
3648 MessageDialog msg (err.what(),
3651 Gtk::BUTTONS_CLOSE);
3653 msg.set_title (_("Port Registration Error"));
3654 msg.set_secondary_text (_("Click the Close button to try again."));
3655 msg.set_position (Gtk::WIN_POS_CENTER);
3656 pop_back_splash (msg);
3659 int response = msg.run ();
3664 case RESPONSE_CANCEL:
3671 catch (SessionException e) {
3672 MessageDialog msg (string_compose(
3673 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3674 path, snap_name, e.what()),
3679 msg.set_title (_("Loading Error"));
3680 msg.set_position (Gtk::WIN_POS_CENTER);
3681 pop_back_splash (msg);
3693 MessageDialog msg (string_compose(
3694 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3700 msg.set_title (_("Loading Error"));
3701 msg.set_position (Gtk::WIN_POS_CENTER);
3702 pop_back_splash (msg);
3714 list<string> const u = new_session->unknown_processors ();
3716 MissingPluginDialog d (_session, u);
3721 if (!new_session->writable()) {
3722 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3727 msg.set_title (_("Read-only Session"));
3728 msg.set_position (Gtk::WIN_POS_CENTER);
3729 pop_back_splash (msg);
3736 /* Now the session been created, add the transport controls */
3737 new_session->add_controllable(roll_controllable);
3738 new_session->add_controllable(stop_controllable);
3739 new_session->add_controllable(goto_start_controllable);
3740 new_session->add_controllable(goto_end_controllable);
3741 new_session->add_controllable(auto_loop_controllable);
3742 new_session->add_controllable(play_selection_controllable);
3743 new_session->add_controllable(rec_controllable);
3745 set_session (new_session);
3747 session_loaded = true;
3750 _session->set_clean ();
3753 #ifdef WINDOWS_VST_SUPPORT
3754 fst_stop_threading();
3758 Timers::TimerSuspender t;
3762 #ifdef WINDOWS_VST_SUPPORT
3763 fst_start_threading();
3767 if (!mix_template.empty ()) {
3768 /* if mix_template is given, assume this is a new session */
3769 string metascript = Glib::build_filename (mix_template, "template.lua");
3770 meta_session_setup (metascript);
3775 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3776 * which is queued by set_session().
3777 * If session-loading fails we hide it explicitly.
3778 * This covers both cases in a central place.
3787 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3789 Session *new_session;
3792 session_loaded = false;
3793 x = unload_session ();
3801 _session_is_new = true;
3804 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3807 catch (SessionException e) {
3808 cerr << "Here are the errors associated with this failed session:\n";
3810 cerr << "---------\n";
3811 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3812 msg.set_title (_("Loading Error"));
3813 msg.set_position (Gtk::WIN_POS_CENTER);
3814 pop_back_splash (msg);
3819 cerr << "Here are the errors associated with this failed session:\n";
3821 cerr << "---------\n";
3822 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3823 msg.set_title (_("Loading Error"));
3824 msg.set_position (Gtk::WIN_POS_CENTER);
3825 pop_back_splash (msg);
3830 /* Give the new session the default GUI state, if such things exist */
3833 n = Config->instant_xml (X_("Editor"));
3835 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3836 new_session->add_instant_xml (*n, false);
3838 n = Config->instant_xml (X_("Mixer"));
3840 new_session->add_instant_xml (*n, false);
3843 n = Config->instant_xml (X_("Preferences"));
3845 new_session->add_instant_xml (*n, false);
3848 /* Put the playhead at 0 and scroll fully left */
3849 n = new_session->instant_xml (X_("Editor"));
3851 n->set_property (X_("playhead"), X_("0"));
3852 n->set_property (X_("left-frame"), X_("0"));
3855 set_session (new_session);
3857 session_loaded = true;
3859 new_session->save_state(new_session->name());
3865 static void _lua_print (std::string s) {
3867 std::cout << "LuaInstance: " << s << "\n";
3869 PBD::info << "LuaInstance: " << s << endmsg;
3872 std::map<std::string, std::string>
3873 ARDOUR_UI::route_setup_info (const std::string& script_path)
3875 std::map<std::string, std::string> rv;
3877 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3882 lua.Print.connect (&_lua_print);
3885 lua_State* L = lua.getState();
3886 LuaInstance::register_classes (L);
3887 LuaBindings::set_session (L, _session);
3888 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3889 lua_setglobal (L, "Editor");
3891 lua.do_command ("function ardour () end");
3892 lua.do_file (script_path);
3895 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3896 if (!fn.isFunction ()) {
3899 luabridge::LuaRef rs = fn ();
3900 if (!rs.isTable ()) {
3903 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3904 if (!i.key().isString()) {
3907 std::string key = i.key().tostring();
3908 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3909 rv[key] = i.value().tostring();
3912 } catch (luabridge::LuaException const& e) {
3913 cerr << "LuaException:" << e.what () << endl;
3919 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3921 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3924 assert (add_route_dialog);
3927 if ((count = add_route_dialog->count()) <= 0) {
3932 lua.Print.connect (&_lua_print);
3935 lua_State* L = lua.getState();
3936 LuaInstance::register_classes (L);
3937 LuaBindings::set_session (L, _session);
3938 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3939 lua_setglobal (L, "Editor");
3941 lua.do_command ("function ardour () end");
3942 lua.do_file (script_path);
3944 luabridge::LuaRef args (luabridge::newTable (L));
3946 args["name"] = add_route_dialog->name_template ();
3947 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3948 args["group"] = add_route_dialog->route_group ();
3949 args["strict_io"] = add_route_dialog->use_strict_io ();
3950 args["instrument"] = add_route_dialog->requested_instrument ();
3951 args["track_mode"] = add_route_dialog->mode ();
3952 args["channels"] = add_route_dialog->channel_count ();
3953 args["how_many"] = count;
3956 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3957 if (fn.isFunction()) {
3960 } catch (luabridge::LuaException const& e) {
3961 cerr << "LuaException:" << e.what () << endl;
3963 display_insufficient_ports_message ();
3968 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3970 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3975 lua.Print.connect (&_lua_print);
3978 lua_State* L = lua.getState();
3979 LuaInstance::register_classes (L);
3980 LuaBindings::set_session (L, _session);
3981 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3982 lua_setglobal (L, "Editor");
3984 lua.do_command ("function ardour () end");
3985 lua.do_file (script_path);
3988 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3989 if (fn.isFunction()) {
3992 } catch (luabridge::LuaException const& e) {
3993 cerr << "LuaException:" << e.what () << endl;
3995 display_insufficient_ports_message ();
4000 ARDOUR_UI::launch_chat ()
4002 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
4004 dialog.set_title (_("About the Chat"));
4005 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."));
4007 switch (dialog.run()) {
4010 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
4011 #elif defined PLATFORM_WINDOWS
4012 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
4014 open_uri("http://webchat.freenode.net/?channels=ardour");
4023 ARDOUR_UI::launch_manual ()
4025 PBD::open_uri (Config->get_tutorial_manual_url());
4029 ARDOUR_UI::launch_reference ()
4031 PBD::open_uri (Config->get_reference_manual_url());
4035 ARDOUR_UI::launch_tracker ()
4037 PBD::open_uri ("http://tracker.ardour.org");
4041 ARDOUR_UI::launch_subscribe ()
4043 PBD::open_uri ("https://community.ardour.org/s/subscribe");
4047 ARDOUR_UI::launch_cheat_sheet ()
4050 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
4052 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
4057 ARDOUR_UI::launch_website ()
4059 PBD::open_uri ("http://ardour.org");
4063 ARDOUR_UI::launch_website_dev ()
4065 PBD::open_uri ("http://ardour.org/development.html");
4069 ARDOUR_UI::launch_forums ()
4071 PBD::open_uri ("https://community.ardour.org/forums");
4075 ARDOUR_UI::launch_howto_report ()
4077 PBD::open_uri ("http://ardour.org/reporting_bugs");
4081 ARDOUR_UI::loading_message (const std::string& msg)
4083 if (ARDOUR_COMMAND_LINE::no_splash) {
4091 splash->message (msg);
4095 ARDOUR_UI::show_splash ()
4099 splash = new Splash;
4109 ARDOUR_UI::hide_splash ()
4116 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4120 removed = rep.paths.size();
4123 MessageDialog msgd (_main_window,
4124 _("No files were ready for clean-up"),
4128 msgd.set_title (_("Clean-up"));
4129 msgd.set_secondary_text (_("If this seems surprising, \n\
4130 check for any existing snapshots.\n\
4131 These may still include regions that\n\
4132 require some unused files to continue to exist."));
4138 ArdourDialog results (_("Clean-up"), true, false);
4140 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4141 CleanupResultsModelColumns() {
4145 Gtk::TreeModelColumn<std::string> visible_name;
4146 Gtk::TreeModelColumn<std::string> fullpath;
4150 CleanupResultsModelColumns results_columns;
4151 Glib::RefPtr<Gtk::ListStore> results_model;
4152 Gtk::TreeView results_display;
4154 results_model = ListStore::create (results_columns);
4155 results_display.set_model (results_model);
4156 results_display.append_column (list_title, results_columns.visible_name);
4158 results_display.set_name ("CleanupResultsList");
4159 results_display.set_headers_visible (true);
4160 results_display.set_headers_clickable (false);
4161 results_display.set_reorderable (false);
4163 Gtk::ScrolledWindow list_scroller;
4166 Gtk::HBox dhbox; // the hbox for the image and text
4167 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4168 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4170 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4172 const string dead_directory = _session->session_directory().dead_path();
4175 %1 - number of files removed
4176 %2 - location of "dead"
4177 %3 - size of files affected
4178 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4181 const char* bprefix;
4182 double space_adjusted = 0;
4184 if (rep.space < 1000) {
4186 space_adjusted = rep.space;
4187 } else if (rep.space < 1000000) {
4188 bprefix = _("kilo");
4189 space_adjusted = floorf((float)rep.space / 1000.0);
4190 } else if (rep.space < 1000000 * 1000) {
4191 bprefix = _("mega");
4192 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4194 bprefix = _("giga");
4195 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4199 txt.set_markup (string_compose (P_("\
4200 The following file was deleted from %2,\n\
4201 releasing %3 %4bytes of disk space", "\
4202 The following %1 files were deleted from %2,\n\
4203 releasing %3 %4bytes of disk space", removed),
4204 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4206 txt.set_markup (string_compose (P_("\
4207 The following file was not in use and \n\
4208 has been moved to: %2\n\n\
4209 After a restart of %5\n\n\
4210 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4211 will release an additional %3 %4bytes of disk space.\n", "\
4212 The following %1 files were not in use and \n\
4213 have been moved to: %2\n\n\
4214 After a restart of %5\n\n\
4215 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4216 will release an additional %3 %4bytes of disk space.\n", removed),
4217 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4220 dhbox.pack_start (*dimage, true, false, 5);
4221 dhbox.pack_start (txt, true, false, 5);
4223 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4224 TreeModel::Row row = *(results_model->append());
4225 row[results_columns.visible_name] = *i;
4226 row[results_columns.fullpath] = *i;
4229 list_scroller.add (results_display);
4230 list_scroller.set_size_request (-1, 150);
4231 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4233 dvbox.pack_start (dhbox, true, false, 5);
4234 dvbox.pack_start (list_scroller, true, false, 5);
4235 ddhbox.pack_start (dvbox, true, false, 5);
4237 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4238 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4239 results.set_default_response (RESPONSE_CLOSE);
4240 results.set_position (Gtk::WIN_POS_MOUSE);
4242 results_display.show();
4243 list_scroller.show();
4250 //results.get_vbox()->show();
4251 results.set_resizable (false);
4258 ARDOUR_UI::cleanup ()
4260 if (_session == 0) {
4261 /* shouldn't happen: menu item is insensitive */
4266 MessageDialog checker (_("Are you sure you want to clean-up?"),
4268 Gtk::MESSAGE_QUESTION,
4271 checker.set_title (_("Clean-up"));
4273 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4274 ALL undo/redo information will be lost if you clean-up.\n\
4275 Clean-up will move all unused files to a \"dead\" location."));
4277 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4278 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4279 checker.set_default_response (RESPONSE_CANCEL);
4281 checker.set_name (_("CleanupDialog"));
4282 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4283 checker.set_position (Gtk::WIN_POS_MOUSE);
4285 switch (checker.run()) {
4286 case RESPONSE_ACCEPT:
4292 ARDOUR::CleanupReport rep;
4294 editor->prepare_for_cleanup ();
4296 /* do not allow flush until a session is reloaded */
4298 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4300 act->set_sensitive (false);
4303 if (_session->cleanup_sources (rep)) {
4304 editor->finish_cleanup ();
4308 editor->finish_cleanup ();
4311 display_cleanup_results (rep, _("Cleaned Files"), false);
4315 ARDOUR_UI::flush_trash ()
4317 if (_session == 0) {
4318 /* shouldn't happen: menu item is insensitive */
4322 ARDOUR::CleanupReport rep;
4324 if (_session->cleanup_trash_sources (rep)) {
4328 display_cleanup_results (rep, _("deleted file"), true);
4332 ARDOUR_UI::cleanup_peakfiles ()
4334 if (_session == 0) {
4335 /* shouldn't happen: menu item is insensitive */
4339 if (! _session->can_cleanup_peakfiles ()) {
4343 // get all region-views in this session
4345 TrackViewList empty;
4347 editor->get_regions_after(rs, (framepos_t) 0, empty);
4348 std::list<RegionView*> views = rs.by_layer();
4350 // remove displayed audio-region-views waveforms
4351 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4352 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4353 if (!arv) { continue ; }
4354 arv->delete_waves();
4357 // cleanup peak files:
4358 // - stop pending peakfile threads
4359 // - close peakfiles if any
4360 // - remove peak dir in session
4361 // - setup peakfiles (background thread)
4362 _session->cleanup_peakfiles ();
4364 // re-add waves to ARV
4365 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4366 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4367 if (!arv) { continue ; }
4368 arv->create_waves();
4372 PresentationInfo::order_t
4373 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4375 if (editor->get_selection().tracks.empty()) {
4376 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4379 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4382 we want the new routes to have their order keys set starting from
4383 the highest order key in the selection + 1 (if available).
4386 if (place == RouteDialogs::AfterSelection) {
4387 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4389 order_hint = rtav->route()->presentation_info().order();
4392 } else if (place == RouteDialogs::BeforeSelection) {
4393 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4395 order_hint = rtav->route()->presentation_info().order();
4397 } else if (place == RouteDialogs::First) {
4400 /* leave order_hint at max_order */
4407 ARDOUR_UI::start_duplicate_routes ()
4409 if (!duplicate_routes_dialog) {
4410 duplicate_routes_dialog = new DuplicateRouteDialog;
4413 if (duplicate_routes_dialog->restart (_session)) {
4417 duplicate_routes_dialog->present ();
4421 ARDOUR_UI::add_route ()
4423 if (!add_route_dialog.get (false)) {
4424 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4431 if (add_route_dialog->is_visible()) {
4432 /* we're already doing this */
4436 add_route_dialog->set_position (WIN_POS_MOUSE);
4437 add_route_dialog->present();
4441 ARDOUR_UI::add_route_dialog_response (int r)
4444 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4451 case AddRouteDialog::Add:
4452 add_route_dialog->reset_name_edited ();
4454 case AddRouteDialog::AddAndClose:
4455 add_route_dialog->ArdourDialog::on_response (r);
4458 add_route_dialog->ArdourDialog::on_response (r);
4462 std::string template_path = add_route_dialog->get_template_path();
4463 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4464 meta_route_setup (template_path.substr (11));
4468 if ((count = add_route_dialog->count()) <= 0) {
4472 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4473 const string name_template = add_route_dialog->name_template ();
4474 DisplaySuspender ds;
4476 if (!template_path.empty ()) {
4477 if (add_route_dialog->name_template_is_default ()) {
4478 _session->new_route_from_template (count, order, template_path, string ());
4480 _session->new_route_from_template (count, order, template_path, name_template);
4485 ChanCount input_chan= add_route_dialog->channels ();
4486 ChanCount output_chan;
4487 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4488 RouteGroup* route_group = add_route_dialog->route_group ();
4489 AutoConnectOption oac = Config->get_output_auto_connect();
4490 bool strict_io = add_route_dialog->use_strict_io ();
4492 if (oac & AutoConnectMaster) {
4493 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4494 output_chan.set (DataType::MIDI, 0);
4496 output_chan = input_chan;
4499 /* XXX do something with name template */
4501 Session::ProcessorChangeBlocker pcb (_session);
4503 switch (add_route_dialog->type_wanted()) {
4504 case AddRouteDialog::AudioTrack:
4505 session_add_audio_route (true, input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4507 case AddRouteDialog::MidiTrack:
4508 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4510 case AddRouteDialog::MixedTrack:
4511 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4513 case AddRouteDialog::AudioBus:
4514 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4516 case AddRouteDialog::MidiBus:
4517 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4519 case AddRouteDialog::VCAMaster:
4520 _session->vca_manager().create_vca (count, name_template);
4526 ARDOUR_UI::stop_video_server (bool ask_confirm)
4528 if (!video_server_process && ask_confirm) {
4529 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4531 if (video_server_process) {
4533 ArdourDialog confirm (_("Stop Video-Server"), true);
4534 Label m (_("Do you really want to stop the Video Server?"));
4535 confirm.get_vbox()->pack_start (m, true, true);
4536 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4537 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4538 confirm.show_all ();
4539 if (confirm.run() == RESPONSE_CANCEL) {
4543 delete video_server_process;
4544 video_server_process =0;
4549 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4551 ARDOUR_UI::start_video_server( float_window, true);
4555 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4561 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4562 if (video_server_process) {
4563 popup_error(_("The Video Server is already started."));
4565 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4571 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4573 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4575 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4577 video_server_dialog->set_transient_for (*float_window);
4580 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4581 video_server_dialog->hide();
4583 ResponseType r = (ResponseType) video_server_dialog->run ();
4584 video_server_dialog->hide();
4585 if (r != RESPONSE_ACCEPT) { return false; }
4586 if (video_server_dialog->show_again()) {
4587 Config->set_show_video_server_dialog(false);
4591 std::string icsd_exec = video_server_dialog->get_exec_path();
4592 std::string icsd_docroot = video_server_dialog->get_docroot();
4593 #ifndef PLATFORM_WINDOWS
4594 if (icsd_docroot.empty()) {
4595 icsd_docroot = VideoUtils::video_get_docroot (Config);
4600 #ifdef PLATFORM_WINDOWS
4601 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4602 /* OK, allow all drive letters */
4605 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4606 warning << _("Specified docroot is not an existing directory.") << endmsg;
4609 #ifndef PLATFORM_WINDOWS
4610 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4611 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4612 warning << _("Given Video Server is not an executable file.") << endmsg;
4616 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4617 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4618 warning << _("Given Video Server is not an executable file.") << endmsg;
4624 argp=(char**) calloc(9,sizeof(char*));
4625 argp[0] = strdup(icsd_exec.c_str());
4626 argp[1] = strdup("-P");
4627 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4628 argp[3] = strdup("-p");
4629 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4630 argp[5] = strdup("-C");
4631 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4632 argp[7] = strdup(icsd_docroot.c_str());
4634 stop_video_server();
4636 #ifdef PLATFORM_WINDOWS
4637 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4638 /* OK, allow all drive letters */
4641 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4642 Config->set_video_advanced_setup(false);
4644 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4645 Config->set_video_server_url(url_str);
4646 Config->set_video_server_docroot(icsd_docroot);
4647 Config->set_video_advanced_setup(true);
4650 if (video_server_process) {
4651 delete video_server_process;
4654 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4655 if (video_server_process->start()) {
4656 warning << _("Cannot launch the video-server") << endmsg;
4659 int timeout = 120; // 6 sec
4660 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4661 Glib::usleep (50000);
4663 if (--timeout <= 0 || !video_server_process->is_running()) break;
4666 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4668 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4669 delete video_server_process;
4670 video_server_process = 0;
4678 ARDOUR_UI::add_video (Gtk::Window* float_window)
4684 if (!start_video_server(float_window, false)) {
4685 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4690 add_video_dialog->set_transient_for (*float_window);
4693 if (add_video_dialog->is_visible()) {
4694 /* we're already doing this */
4698 ResponseType r = (ResponseType) add_video_dialog->run ();
4699 add_video_dialog->hide();
4700 if (r != RESPONSE_ACCEPT) { return; }
4702 bool local_file, orig_local_file;
4703 std::string path = add_video_dialog->file_name(local_file);
4705 std::string orig_path = path;
4706 orig_local_file = local_file;
4708 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4710 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4711 warning << string_compose(_("could not open %1"), path) << endmsg;
4714 if (!local_file && path.length() == 0) {
4715 warning << _("no video-file selected") << endmsg;
4719 std::string audio_from_video;
4720 bool detect_ltc = false;
4722 switch (add_video_dialog->import_option()) {
4723 case VTL_IMPORT_TRANSCODE:
4725 TranscodeVideoDialog *transcode_video_dialog;
4726 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4727 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4728 transcode_video_dialog->hide();
4729 if (r != RESPONSE_ACCEPT) {
4730 delete transcode_video_dialog;
4734 audio_from_video = transcode_video_dialog->get_audiofile();
4736 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4739 else if (!audio_from_video.empty()) {
4740 editor->embed_audio_from_video(
4742 video_timeline->get_offset(),
4743 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4746 switch (transcode_video_dialog->import_option()) {
4747 case VTL_IMPORT_TRANSCODED:
4748 path = transcode_video_dialog->get_filename();
4751 case VTL_IMPORT_REFERENCE:
4754 delete transcode_video_dialog;
4757 delete transcode_video_dialog;
4761 case VTL_IMPORT_NONE:
4765 /* strip _session->session_directory().video_path() from video file if possible */
4766 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4767 path=path.substr(_session->session_directory().video_path().size());
4768 if (path.at(0) == G_DIR_SEPARATOR) {
4769 path=path.substr(1);
4773 video_timeline->set_update_session_fps(auto_set_session_fps);
4775 if (video_timeline->video_file_info(path, local_file)) {
4776 XMLNode* node = new XMLNode(X_("Videotimeline"));
4777 node->set_property (X_("Filename"), path);
4778 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4779 node->set_property (X_("LocalFile"), local_file);
4780 if (orig_local_file) {
4781 node->set_property (X_("OriginalVideoFile"), orig_path);
4783 node->remove_property (X_("OriginalVideoFile"));
4785 _session->add_extra_xml (*node);
4786 _session->set_dirty ();
4788 if (!audio_from_video.empty() && detect_ltc) {
4789 std::vector<LTCFileReader::LTCMap> ltc_seq;
4792 /* TODO ask user about TV standard (LTC alignment if any) */
4793 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4794 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4796 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4798 /* TODO seek near end of file, and read LTC until end.
4799 * if it fails to find any LTC frames, scan complete file
4801 * calculate drift of LTC compared to video-duration,
4802 * ask user for reference (timecode from start/mid/end)
4805 // LTCFileReader will have written error messages
4808 ::g_unlink(audio_from_video.c_str());
4810 if (ltc_seq.size() == 0) {
4811 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4813 /* the very first TC in the file is somteimes not aligned properly */
4814 int i = ltc_seq.size() -1;
4815 ARDOUR::frameoffset_t video_start_offset =
4816 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4817 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4818 video_timeline->set_offset(video_start_offset);
4822 _session->maybe_update_session_range(
4823 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4824 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4827 if (add_video_dialog->launch_xjadeo() && local_file) {
4828 editor->set_xjadeo_sensitive(true);
4829 editor->toggle_xjadeo_proc(1);
4831 editor->toggle_xjadeo_proc(0);
4833 editor->toggle_ruler_video(true);
4838 ARDOUR_UI::remove_video ()
4840 video_timeline->close_session();
4841 editor->toggle_ruler_video(false);
4844 video_timeline->set_offset_locked(false);
4845 video_timeline->set_offset(0);
4847 /* delete session state */
4848 XMLNode* node = new XMLNode(X_("Videotimeline"));
4849 _session->add_extra_xml(*node);
4850 node = new XMLNode(X_("Videomonitor"));
4851 _session->add_extra_xml(*node);
4852 node = new XMLNode(X_("Videoexport"));
4853 _session->add_extra_xml(*node);
4854 stop_video_server();
4858 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4860 if (localcacheonly) {
4861 video_timeline->vmon_update();
4863 video_timeline->flush_cache();
4865 editor->queue_visual_videotimeline_update();
4869 ARDOUR_UI::export_video (bool range)
4871 if (ARDOUR::Config->get_show_video_export_info()) {
4872 ExportVideoInfobox infobox (_session);
4873 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4874 if (infobox.show_again()) {
4875 ARDOUR::Config->set_show_video_export_info(false);
4878 case GTK_RESPONSE_YES:
4879 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4885 export_video_dialog->set_session (_session);
4886 export_video_dialog->apply_state(editor->get_selection().time, range);
4887 export_video_dialog->run ();
4888 export_video_dialog->hide ();
4892 ARDOUR_UI::preferences_settings () const
4897 node = _session->instant_xml(X_("Preferences"));
4899 node = Config->instant_xml(X_("Preferences"));
4903 node = new XMLNode (X_("Preferences"));
4910 ARDOUR_UI::mixer_settings () const
4915 node = _session->instant_xml(X_("Mixer"));
4917 node = Config->instant_xml(X_("Mixer"));
4921 node = new XMLNode (X_("Mixer"));
4928 ARDOUR_UI::main_window_settings () const
4933 node = _session->instant_xml(X_("Main"));
4935 node = Config->instant_xml(X_("Main"));
4939 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4940 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4945 node = new XMLNode (X_("Main"));
4952 ARDOUR_UI::editor_settings () const
4957 node = _session->instant_xml(X_("Editor"));
4959 node = Config->instant_xml(X_("Editor"));
4963 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4964 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4969 node = new XMLNode (X_("Editor"));
4976 ARDOUR_UI::keyboard_settings () const
4980 node = Config->extra_xml(X_("Keyboard"));
4983 node = new XMLNode (X_("Keyboard"));
4990 ARDOUR_UI::create_xrun_marker (framepos_t where)
4993 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4994 _session->locations()->add (location);
4999 ARDOUR_UI::halt_on_xrun_message ()
5001 cerr << "HALT on xrun\n";
5002 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
5007 ARDOUR_UI::xrun_handler (framepos_t where)
5013 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
5015 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
5016 create_xrun_marker(where);
5019 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
5020 halt_on_xrun_message ();
5025 ARDOUR_UI::disk_overrun_handler ()
5027 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
5029 if (!have_disk_speed_dialog_displayed) {
5030 have_disk_speed_dialog_displayed = true;
5031 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
5032 The disk system on your computer\n\
5033 was not able to keep up with %1.\n\
5035 Specifically, it failed to write data to disk\n\
5036 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
5037 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5043 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
5044 static MessageDialog *scan_dlg = NULL;
5045 static ProgressBar *scan_pbar = NULL;
5046 static HBox *scan_tbox = NULL;
5047 static Gtk::Button *scan_timeout_button;
5050 ARDOUR_UI::cancel_plugin_scan ()
5052 PluginManager::instance().cancel_plugin_scan();
5056 ARDOUR_UI::cancel_plugin_timeout ()
5058 PluginManager::instance().cancel_plugin_timeout();
5059 scan_timeout_button->set_sensitive (false);
5063 ARDOUR_UI::plugin_scan_timeout (int timeout)
5065 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5069 scan_pbar->set_sensitive (false);
5070 scan_timeout_button->set_sensitive (true);
5071 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5074 scan_pbar->set_sensitive (false);
5075 scan_timeout_button->set_sensitive (false);
5081 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5083 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5087 const bool cancelled = PluginManager::instance().cancelled();
5088 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5089 if (cancelled && scan_dlg->is_mapped()) {
5094 if (cancelled || !can_cancel) {
5099 static Gtk::Button *cancel_button;
5101 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5102 VBox* vbox = scan_dlg->get_vbox();
5103 vbox->set_size_request(400,-1);
5104 scan_dlg->set_title (_("Scanning for plugins"));
5106 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5107 cancel_button->set_name ("EditorGTKButton");
5108 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5109 cancel_button->show();
5111 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5113 scan_tbox = manage( new HBox() );
5115 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5116 scan_timeout_button->set_name ("EditorGTKButton");
5117 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5118 scan_timeout_button->show();
5120 scan_pbar = manage(new ProgressBar());
5121 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5122 scan_pbar->set_text(_("Scan Timeout"));
5125 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5126 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5128 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5131 assert(scan_dlg && scan_tbox && cancel_button);
5133 if (type == X_("closeme")) {
5137 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5140 if (!can_cancel || !cancelled) {
5141 scan_timeout_button->set_sensitive(false);
5143 cancel_button->set_sensitive(can_cancel && !cancelled);
5149 ARDOUR_UI::gui_idle_handler ()
5152 /* due to idle calls, gtk_events_pending() may always return true */
5153 while (gtk_events_pending() && --timeout) {
5154 gtk_main_iteration ();
5159 ARDOUR_UI::disk_underrun_handler ()
5161 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5163 if (!have_disk_speed_dialog_displayed) {
5164 have_disk_speed_dialog_displayed = true;
5165 MessageDialog* msg = new MessageDialog (
5166 _main_window, string_compose (_("The disk system on your computer\n\
5167 was not able to keep up with %1.\n\
5169 Specifically, it failed to read data from disk\n\
5170 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5171 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5177 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5179 have_disk_speed_dialog_displayed = false;
5184 ARDOUR_UI::session_dialog (std::string msg)
5186 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5190 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5197 ARDOUR_UI::pending_state_dialog ()
5199 HBox* hbox = manage (new HBox());
5200 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5201 ArdourDialog dialog (_("Crash Recovery"), true);
5202 Label message (string_compose (_("\
5203 This session appears to have been in the\n\
5204 middle of recording when %1 or\n\
5205 the computer was shutdown.\n\
5207 %1 can recover any captured audio for\n\
5208 you, or it can ignore it. Please decide\n\
5209 what you would like to do.\n"), PROGRAM_NAME));
5210 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5211 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5212 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5213 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5214 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5215 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5216 dialog.set_default_response (RESPONSE_ACCEPT);
5217 dialog.set_position (WIN_POS_CENTER);
5222 switch (dialog.run ()) {
5223 case RESPONSE_ACCEPT:
5231 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5233 HBox* hbox = new HBox();
5234 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5235 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5236 Label message (string_compose (_("\
5237 This session was created with a sample rate of %1 Hz, but\n\
5238 %2 is currently running at %3 Hz. If you load this session,\n\
5239 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5241 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5242 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5243 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5244 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5245 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5246 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5247 dialog.set_default_response (RESPONSE_ACCEPT);
5248 dialog.set_position (WIN_POS_CENTER);
5253 switch (dialog.run()) {
5254 case RESPONSE_ACCEPT:
5264 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5266 MessageDialog msg (string_compose (_("\
5267 This session was created with a sample rate of %1 Hz, but\n\
5268 %2 is currently running at %3 Hz.\n\
5269 Audio will be recorded and played at the wrong sample rate.\n\
5270 Re-Configure the Audio Engine in\n\
5271 Menu > Window > Audio/Midi Setup"),
5272 desired, PROGRAM_NAME, actual),
5274 Gtk::MESSAGE_WARNING);
5279 ARDOUR_UI::use_config ()
5281 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5283 set_transport_controllable_state (*node);
5288 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5290 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5291 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5293 primary_clock->set (pos);
5296 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5297 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5299 secondary_clock->set (pos);
5302 if (big_clock_window) {
5303 big_clock->set (pos);
5305 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5309 ARDOUR_UI::step_edit_status_change (bool yn)
5311 // XXX should really store pre-step edit status of things
5312 // we make insensitive
5315 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5316 rec_button.set_sensitive (false);
5318 rec_button.unset_active_state ();;
5319 rec_button.set_sensitive (true);
5324 ARDOUR_UI::record_state_changed ()
5326 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5329 /* why bother - the clock isn't visible */
5333 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5335 if (big_clock_window) {
5336 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5337 big_clock->set_active (true);
5339 big_clock->set_active (false);
5346 ARDOUR_UI::first_idle ()
5349 _session->allow_auto_play (true);
5353 editor->first_idle();
5356 /* in 1 second, hide the splash screen
5358 * Consider hiding it *now*. If a user opens opens a dialog
5359 * during that one second while the splash is still visible,
5360 * the dialog will push-back the splash.
5361 * Closing the dialog later will pop it back.
5363 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5365 Keyboard::set_can_save_keybindings (true);
5370 ARDOUR_UI::store_clock_modes ()
5372 XMLNode* node = new XMLNode(X_("ClockModes"));
5374 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5375 XMLNode* child = new XMLNode (X_("Clock"));
5377 child->set_property (X_("name"), (*x)->name());
5378 child->set_property (X_("mode"), (*x)->mode());
5379 child->set_property (X_("on"), (*x)->on());
5381 node->add_child_nocopy (*child);
5384 _session->add_extra_xml (*node);
5385 _session->set_dirty ();
5388 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5389 : Controllable (name), ui (u), type(tp)
5395 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5398 /* do nothing: these are radio-style actions */
5402 const char *action = 0;
5406 action = X_("Roll");
5409 action = X_("Stop");
5412 action = X_("GotoStart");
5415 action = X_("GotoEnd");
5418 action = X_("Loop");
5421 action = X_("PlaySelection");
5424 action = X_("Record");
5434 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5442 ARDOUR_UI::TransportControllable::get_value (void) const
5469 ARDOUR_UI::setup_profile ()
5471 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5472 Profile->set_small_screen ();
5475 if (g_getenv ("TRX")) {
5476 Profile->set_trx ();
5479 if (g_getenv ("MIXBUS")) {
5480 Profile->set_mixbus ();
5485 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5487 MissingFileDialog dialog (s, str, type);
5492 int result = dialog.run ();
5499 return 1; // quit entire session load
5502 result = dialog.get_action ();
5508 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5510 AmbiguousFileDialog dialog (file, hits);
5517 return dialog.get_which ();
5520 /** Allocate our thread-local buffers */
5522 ARDOUR_UI::get_process_buffers ()
5524 _process_thread->get_buffers ();
5527 /** Drop our thread-local buffers */
5529 ARDOUR_UI::drop_process_buffers ()
5531 _process_thread->drop_buffers ();
5535 ARDOUR_UI::feedback_detected ()
5537 _feedback_exists = true;
5541 ARDOUR_UI::successful_graph_sort ()
5543 _feedback_exists = false;
5547 ARDOUR_UI::midi_panic ()
5550 _session->midi_panic();
5555 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5557 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5558 const char* end_big = "</span>";
5559 const char* start_mono = "<tt>";
5560 const char* end_mono = "</tt>";
5562 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5563 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5564 "From now on, use the backup copy with older versions of %3"),
5565 xml_path, backup_path, PROGRAM_NAME,
5567 start_mono, end_mono), true);
5573 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5575 using namespace Menu_Helpers;
5577 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5578 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5579 i->set_active (editor_meter->meter_type () == type);
5583 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5585 using namespace Gtk::Menu_Helpers;
5587 Gtk::Menu* m = manage (new Menu);
5588 MenuList& items = m->items ();
5590 RadioMenuItem::Group group;
5592 _suspend_editor_meter_callbacks = true;
5593 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5594 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5595 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5596 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5597 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5598 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5599 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5600 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5601 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5602 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5603 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5605 m->popup (ev->button, ev->time);
5606 _suspend_editor_meter_callbacks = false;
5610 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5612 if (ev->button == 3 && editor_meter) {
5613 popup_editor_meter_menu (ev);
5620 ARDOUR_UI::reset_peak_display ()
5622 if (!_session || !_session->master_out() || !editor_meter) return;
5623 editor_meter->clear_meters();
5624 editor_meter_max_peak = -INFINITY;
5625 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5629 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5631 if (!_session || !_session->master_out()) return;
5632 if (group == _session->master_out()->route_group()) {
5633 reset_peak_display ();
5638 ARDOUR_UI::reset_route_peak_display (Route* route)
5640 if (!_session || !_session->master_out()) return;
5641 if (_session->master_out().get() == route) {
5642 reset_peak_display ();
5647 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5649 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5650 audio_midi_setup->set_position (WIN_POS_CENTER);
5652 if (desired_sample_rate != 0) {
5653 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5654 audio_midi_setup->try_autostart ();
5655 if (ARDOUR::AudioEngine::instance()->running()) {
5662 int response = audio_midi_setup->run();
5664 case Gtk::RESPONSE_DELETE_EVENT:
5665 // after latency callibration engine may run,
5666 // Running() signal was emitted, but dialog will not
5667 // have emitted a response. The user needs to close
5668 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5669 if (!AudioEngine::instance()->running()) {
5674 if (!AudioEngine::instance()->running()) {
5677 audio_midi_setup->hide ();
5685 ARDOUR_UI::transport_numpad_timeout ()
5687 _numpad_locate_happening = false;
5688 if (_numpad_timeout_connection.connected() )
5689 _numpad_timeout_connection.disconnect();
5694 ARDOUR_UI::transport_numpad_decimal ()
5696 _numpad_timeout_connection.disconnect();
5698 if (_numpad_locate_happening) {
5699 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5700 _numpad_locate_happening = false;
5702 _pending_locate_num = 0;
5703 _numpad_locate_happening = true;
5704 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5709 ARDOUR_UI::transport_numpad_event (int num)
5711 if ( _numpad_locate_happening ) {
5712 _pending_locate_num = _pending_locate_num*10 + num;
5715 case 0: toggle_roll(false, false); break;
5716 case 1: transport_rewind(1); break;
5717 case 2: transport_forward(1); break;
5718 case 3: transport_record(true); break;
5719 case 4: toggle_session_auto_loop(); break;
5720 case 5: transport_record(false); toggle_session_auto_loop(); break;
5721 case 6: toggle_punch(); break;
5722 case 7: toggle_click(); break;
5723 case 8: toggle_auto_return(); break;
5724 case 9: toggle_follow_edits(); break;
5730 ARDOUR_UI::set_flat_buttons ()
5732 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5736 ARDOUR_UI::audioengine_became_silent ()
5738 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5740 Gtk::MESSAGE_WARNING,
5744 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5746 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5747 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5748 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5749 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5750 Gtk::HBox pay_button_box;
5751 Gtk::HBox subscribe_button_box;
5753 pay_button_box.pack_start (pay_button, true, false);
5754 subscribe_button_box.pack_start (subscribe_button, true, false);
5756 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 */
5758 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5759 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5761 msg.get_vbox()->pack_start (pay_label);
5762 msg.get_vbox()->pack_start (pay_button_box);
5763 msg.get_vbox()->pack_start (subscribe_label);
5764 msg.get_vbox()->pack_start (subscribe_button_box);
5766 msg.get_vbox()->show_all ();
5768 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5769 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5770 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5775 case Gtk::RESPONSE_YES:
5776 AudioEngine::instance()->reset_silence_countdown ();
5779 case Gtk::RESPONSE_NO:
5781 save_state_canfail ("");
5785 case Gtk::RESPONSE_CANCEL:
5787 /* don't reset, save session and exit */
5793 ARDOUR_UI::hide_application ()
5795 Application::instance ()-> hide ();
5799 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5801 /* icons, titles, WM stuff */
5803 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5805 if (window_icons.empty()) {
5806 Glib::RefPtr<Gdk::Pixbuf> icon;
5807 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5808 window_icons.push_back (icon);
5810 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5811 window_icons.push_back (icon);
5813 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5814 window_icons.push_back (icon);
5816 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5817 window_icons.push_back (icon);
5821 if (!window_icons.empty()) {
5822 window.set_default_icon_list (window_icons);
5825 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5827 if (!name.empty()) {
5831 window.set_title (title.get_string());
5832 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5834 window.set_flags (CAN_FOCUS);
5835 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5837 /* This is a hack to ensure that GTK-accelerators continue to
5838 * work. Once we switch over to entirely native bindings, this will be
5839 * unnecessary and should be removed
5841 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5843 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5844 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5845 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5846 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5850 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5852 Gtkmm2ext::Bindings* bindings = 0;
5853 Gtk::Window* window = 0;
5855 /* until we get ardour bindings working, we are not handling key
5859 if (ev->type != GDK_KEY_PRESS) {
5863 if (event_window == &_main_window) {
5865 window = event_window;
5867 /* find current tab contents */
5869 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5871 /* see if it uses the ardour binding system */
5874 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5877 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5881 window = event_window;
5883 /* see if window uses ardour binding system */
5885 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5888 /* An empty binding set is treated as if it doesn't exist */
5890 if (bindings && bindings->empty()) {
5894 return key_press_focus_accelerator_handler (*window, ev, bindings);
5897 static Gtkmm2ext::Bindings*
5898 get_bindings_from_widget_heirarchy (GtkWidget** w)
5903 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5906 *w = gtk_widget_get_parent (*w);
5909 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5913 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5915 GtkWindow* win = window.gobj();
5916 GtkWidget* focus = gtk_window_get_focus (win);
5917 GtkWidget* binding_widget = focus;
5918 bool special_handling_of_unmodified_accelerators = false;
5919 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5923 /* some widget has keyboard focus */
5925 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5927 /* A particular kind of focusable widget currently has keyboard
5928 * focus. All unmodified key events should go to that widget
5929 * first and not be used as an accelerator by default
5932 special_handling_of_unmodified_accelerators = true;
5936 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5937 if (focus_bindings) {
5938 bindings = focus_bindings;
5939 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5944 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",
5947 Gtkmm2ext::show_gdk_event_state (ev->state),
5948 special_handling_of_unmodified_accelerators,
5949 Keyboard::some_magic_widget_has_focus(),
5951 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5952 ((ev->state & mask) ? "yes" : "no"),
5953 window.get_title()));
5955 /* This exists to allow us to override the way GTK handles
5956 key events. The normal sequence is:
5958 a) event is delivered to a GtkWindow
5959 b) accelerators/mnemonics are activated
5960 c) if (b) didn't handle the event, propagate to
5961 the focus widget and/or focus chain
5963 The problem with this is that if the accelerators include
5964 keys without modifiers, such as the space bar or the
5965 letter "e", then pressing the key while typing into
5966 a text entry widget results in the accelerator being
5967 activated, instead of the desired letter appearing
5970 There is no good way of fixing this, but this
5971 represents a compromise. The idea is that
5972 key events involving modifiers (not Shift)
5973 get routed into the activation pathway first, then
5974 get propagated to the focus widget if necessary.
5976 If the key event doesn't involve modifiers,
5977 we deliver to the focus widget first, thus allowing
5978 it to get "normal text" without interference
5981 Of course, this can also be problematic: if there
5982 is a widget with focus, then it will swallow
5983 all "normal text" accelerators.
5987 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5989 /* no special handling or there are modifiers in effect: accelerate first */
5991 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5992 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5993 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5995 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5996 KeyboardKey k (ev->state, ev->keyval);
6000 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
6002 if (bindings->activate (k, Bindings::Press)) {
6003 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6007 if (binding_widget) {
6008 binding_widget = gtk_widget_get_parent (binding_widget);
6009 if (binding_widget) {
6010 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
6019 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
6021 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
6022 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6026 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
6028 if (gtk_window_propagate_key_event (win, ev)) {
6029 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
6035 /* no modifiers, propagate first */
6037 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
6039 if (gtk_window_propagate_key_event (win, ev)) {
6040 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
6044 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
6045 KeyboardKey k (ev->state, ev->keyval);
6049 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
6052 if (bindings->activate (k, Bindings::Press)) {
6053 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6057 if (binding_widget) {
6058 binding_widget = gtk_widget_get_parent (binding_widget);
6059 if (binding_widget) {
6060 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
6069 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
6071 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
6072 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6077 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
6082 ARDOUR_UI::load_bindings ()
6084 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
6085 error << _("Global keybindings are missing") << endmsg;
6090 ARDOUR_UI::cancel_solo ()
6093 _session->cancel_all_solo ();
6098 ARDOUR_UI::reset_focus (Gtk::Widget* w)
6100 /* this resets focus to the first focusable parent of the given widget,
6101 * or, if there is no focusable parent, cancels focus in the toplevel
6102 * window that the given widget is packed into (if there is one).
6109 Gtk::Widget* top = w->get_toplevel();
6111 if (!top || !top->is_toplevel()) {
6115 w = w->get_parent ();
6119 if (w->is_toplevel()) {
6120 /* Setting the focus widget to a Gtk::Window causes all
6121 * subsequent calls to ::has_focus() on the nominal
6122 * focus widget in that window to return
6123 * false. Workaround: never set focus to the toplevel
6129 if (w->get_can_focus ()) {
6130 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
6131 win->set_focus (*w);
6134 w = w->get_parent ();
6137 if (top == &_main_window) {
6141 /* no focusable parent found, cancel focus in top level window.
6142 C++ API cannot be used for this. Thanks, references.
6145 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);