2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/accelmap.h>
51 #include <gtkmm/messagedialog.h>
52 #include <gtkmm/stock.h>
53 #include <gtkmm/uimanager.h>
55 #include "pbd/error.h"
56 #include "pbd/basename.h"
57 #include "pbd/compose.h"
58 #include "pbd/convert.h"
59 #include "pbd/failed_constructor.h"
60 #include "pbd/file_archive.h"
61 #include "pbd/enumwriter.h"
62 #include "pbd/memento_command.h"
63 #include "pbd/openuri.h"
64 #include "pbd/stl_delete.h"
65 #include "pbd/types_convert.h"
66 #include "pbd/unwind.h"
67 #include "pbd/file_utils.h"
68 #include "pbd/localtime_r.h"
69 #include "pbd/pthread_utils.h"
70 #include "pbd/replace_all.h"
71 #include "pbd/scoped_file_descriptor.h"
72 #include "pbd/xml++.h"
74 #include "gtkmm2ext/application.h"
75 #include "gtkmm2ext/bindings.h"
76 #include "gtkmm2ext/gtk_ui.h"
77 #include "gtkmm2ext/utils.h"
78 #include "gtkmm2ext/window_title.h"
80 #include "widgets/fastmeter.h"
81 #include "widgets/prompter.h"
83 #include "ardour/ardour.h"
84 #include "ardour/audio_backend.h"
85 #include "ardour/audio_track.h"
86 #include "ardour/audioengine.h"
87 #include "ardour/audiofilesource.h"
88 #include "ardour/automation_watch.h"
89 #include "ardour/diskstream.h"
90 #include "ardour/filename_extensions.h"
91 #include "ardour/filesystem_paths.h"
92 #include "ardour/ltc_file_reader.h"
93 #include "ardour/midi_track.h"
94 #include "ardour/port.h"
95 #include "ardour/plugin_manager.h"
96 #include "ardour/process_thread.h"
97 #include "ardour/profile.h"
98 #include "ardour/recent_sessions.h"
99 #include "ardour/record_enable_control.h"
100 #include "ardour/revision.h"
101 #include "ardour/session_directory.h"
102 #include "ardour/session_route.h"
103 #include "ardour/session_state_utils.h"
104 #include "ardour/session_utils.h"
105 #include "ardour/source_factory.h"
106 #include "ardour/slave.h"
107 #include "ardour/system_exec.h"
108 #include "ardour/track.h"
109 #include "ardour/vca_manager.h"
110 #include "ardour/utils.h"
112 #include "LuaBridge/LuaBridge.h"
114 #ifdef WINDOWS_VST_SUPPORT
117 #ifdef AUDIOUNIT_SUPPORT
118 #include "ardour/audio_unit.h"
121 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
126 #include "timecode/time.h"
128 typedef uint64_t microseconds_t;
132 #include "enums_convert.h"
134 #include "add_route_dialog.h"
135 #include "ambiguous_file_dialog.h"
136 #include "ardour_ui.h"
137 #include "audio_clock.h"
138 #include "audio_region_view.h"
139 #include "big_clock_window.h"
140 #include "bundle_manager.h"
141 #include "duplicate_routes_dialog.h"
143 #include "engine_dialog.h"
144 #include "export_video_dialog.h"
145 #include "export_video_infobox.h"
146 #include "gain_meter.h"
147 #include "global_port_matrix.h"
148 #include "gui_object.h"
149 #include "gui_thread.h"
150 #include "idleometer.h"
151 #include "keyboard.h"
152 #include "keyeditor.h"
153 #include "location_ui.h"
154 #include "lua_script_manager.h"
155 #include "luawindow.h"
156 #include "main_clock.h"
157 #include "missing_file_dialog.h"
158 #include "missing_plugin_dialog.h"
159 #include "mixer_ui.h"
160 #include "meterbridge.h"
161 #include "meter_patterns.h"
162 #include "mouse_cursors.h"
165 #include "pingback.h"
166 #include "processor_box.h"
167 #include "public_editor.h"
168 #include "rc_option_editor.h"
169 #include "route_time_axis.h"
170 #include "route_params_ui.h"
171 #include "save_as_dialog.h"
172 #include "script_selector.h"
173 #include "session_archive_dialog.h"
174 #include "session_dialog.h"
175 #include "session_metadata_dialog.h"
176 #include "session_option_editor.h"
177 #include "speaker_dialog.h"
180 #include "template_dialog.h"
181 #include "time_axis_view_item.h"
182 #include "time_info_box.h"
185 #include "utils_videotl.h"
186 #include "video_server_dialog.h"
187 #include "add_video_dialog.h"
188 #include "transcode_video_dialog.h"
190 #include "pbd/i18n.h"
192 using namespace ARDOUR;
193 using namespace ARDOUR_UI_UTILS;
195 using namespace Gtkmm2ext;
196 using namespace ArdourWidgets;
199 using namespace Editing;
201 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
203 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
204 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
207 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
209 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
210 "Would you like these files to be copied and used for %1 %2.x?\n\n"
211 "(This will require you to restart %1.)"),
212 PROGRAM_NAME, PROGRAM_VERSION, version),
213 false, /* no markup */
216 true /* modal, though it hardly matters since it is the only window */
219 msg.set_default_response (Gtk::RESPONSE_YES);
222 return (msg.run() == Gtk::RESPONSE_YES);
226 libxml_generic_error_func (void* /* parsing_context*/,
234 vsnprintf (buf, sizeof (buf), msg, ap);
235 error << buf << endmsg;
240 libxml_structured_error_func (void* /* parsing_context*/,
248 replace_all (msg, "\n", "");
251 if (err->file && err->line) {
252 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
255 error << ':' << err->int2;
260 error << X_("XML error: ") << msg << endmsg;
266 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
267 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
268 , session_loaded (false)
269 , session_load_in_progress (false)
270 , gui_object_state (new GUIObjectState)
271 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
272 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
273 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
275 , global_actions (X_("global"))
276 , ignore_dual_punch (false)
277 , main_window_visibility (0)
282 , _mixer_on_top (false)
283 , _initial_verbose_plugin_scan (false)
284 , first_time_engine_run (true)
285 , secondary_clock_spacer (0)
286 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
287 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
288 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
289 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
290 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
291 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
292 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
293 , auto_input_button (ArdourButton::led_default_elements)
295 , auto_return_button (ArdourButton::led_default_elements)
296 , follow_edits_button (ArdourButton::led_default_elements)
297 , auditioning_alert_button (_("Audition"))
298 , solo_alert_button (_("Solo"))
299 , feedback_alert_button (_("Feedback"))
300 , error_alert_button ( ArdourButton::just_led_default_elements )
301 , editor_meter_peak_display()
303 , _suspend_editor_meter_callbacks (false)
304 , _numpad_locate_happening (false)
305 , _session_is_new (false)
306 , last_key_press_time (0)
310 , rc_option_editor (0)
311 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
312 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
313 , about (X_("about"), _("About"))
314 , location_ui (X_("locations"), S_("Ranges|Locations"))
315 , route_params (X_("inspector"), _("Tracks and Busses"))
316 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
317 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
318 , lua_script_window (X_("script-manager"), _("Script Manager"))
319 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
320 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
321 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
322 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
323 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
324 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
325 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
326 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
327 , video_server_process (0)
329 , have_configure_timeout (false)
330 , last_configure_time (0)
332 , have_disk_speed_dialog_displayed (false)
333 , _status_bar_visibility (X_("status-bar"))
334 , _feedback_exists (false)
335 , _log_not_acknowledged (LogLevelNone)
336 , duplicate_routes_dialog (0)
337 , editor_visibility_button (S_("Window|Editor"))
338 , mixer_visibility_button (S_("Window|Mixer"))
339 , prefs_visibility_button (S_("Window|Preferences"))
341 Gtkmm2ext::init (localedir);
343 UIConfiguration::instance().post_gui_init ();
345 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
347 /* "touch" the been-here-before path now that config has been migrated */
348 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
350 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
352 /* configuration was modified, exit immediately */
357 if (string (VERSIONSTRING).find (".pre") != string::npos) {
358 /* check this is not being run from ./ardev etc. */
359 if (!running_from_source_tree ()) {
360 pre_release_dialog ();
364 if (theArdourUI == 0) {
368 /* track main window visibility */
370 main_window_visibility = new VisibilityTracker (_main_window);
372 /* stop libxml from spewing to stdout/stderr */
374 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
375 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
377 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
378 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
379 UIConfiguration::instance().map_parameters (pc);
381 roll_button.set_controllable (roll_controllable);
382 stop_button.set_controllable (stop_controllable);
383 goto_start_button.set_controllable (goto_start_controllable);
384 goto_end_button.set_controllable (goto_end_controllable);
385 auto_loop_button.set_controllable (auto_loop_controllable);
386 play_selection_button.set_controllable (play_selection_controllable);
387 rec_button.set_controllable (rec_controllable);
389 roll_button.set_name ("transport button");
390 stop_button.set_name ("transport button");
391 goto_start_button.set_name ("transport button");
392 goto_end_button.set_name ("transport button");
393 auto_loop_button.set_name ("transport button");
394 play_selection_button.set_name ("transport button");
395 rec_button.set_name ("transport recenable button");
396 midi_panic_button.set_name ("transport button");
398 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
399 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
401 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
403 /* handle dialog requests */
405 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
407 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
409 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
411 /* handle Audio/MIDI setup when session requires it */
413 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
415 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
417 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
419 /* handle sr mismatch with a dialog - cross-thread from engine */
420 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
422 /* handle requests to quit (coming from JACK session) */
424 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
426 /* tell the user about feedback */
428 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
429 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
431 /* handle requests to deal with missing files */
433 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
435 /* and ambiguous files */
437 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
439 /* also plugin scan messages */
440 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
441 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
443 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
445 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
448 /* lets get this party started */
450 setup_gtk_ardour_enums ();
453 SessionEvent::create_per_thread_pool ("GUI", 4096);
455 /* we like keyboards */
457 keyboard = new ArdourKeyboard(*this);
459 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
461 keyboard->set_state (*node, Stateful::loading_state_version);
464 UIConfiguration::instance().reset_dpi ();
466 TimeAxisViewItem::set_constant_heights ();
468 /* Set this up so that our window proxies can register actions */
470 ActionManager::init ();
472 /* The following must happen after ARDOUR::init() so that Config is set up */
474 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
477 key_editor.set_state (*ui_xml, 0);
478 session_option_editor.set_state (*ui_xml, 0);
479 speaker_config_window.set_state (*ui_xml, 0);
480 about.set_state (*ui_xml, 0);
481 add_route_dialog.set_state (*ui_xml, 0);
482 add_video_dialog.set_state (*ui_xml, 0);
483 route_params.set_state (*ui_xml, 0);
484 bundle_manager.set_state (*ui_xml, 0);
485 location_ui.set_state (*ui_xml, 0);
486 big_clock_window.set_state (*ui_xml, 0);
487 audio_port_matrix.set_state (*ui_xml, 0);
488 midi_port_matrix.set_state (*ui_xml, 0);
489 export_video_dialog.set_state (*ui_xml, 0);
490 lua_script_window.set_state (*ui_xml, 0);
491 idleometer.set_state (*ui_xml, 0);
494 /* Separate windows */
496 WM::Manager::instance().register_window (&key_editor);
497 WM::Manager::instance().register_window (&session_option_editor);
498 WM::Manager::instance().register_window (&speaker_config_window);
499 WM::Manager::instance().register_window (&about);
500 WM::Manager::instance().register_window (&add_route_dialog);
501 WM::Manager::instance().register_window (&add_video_dialog);
502 WM::Manager::instance().register_window (&route_params);
503 WM::Manager::instance().register_window (&audio_midi_setup);
504 WM::Manager::instance().register_window (&export_video_dialog);
505 WM::Manager::instance().register_window (&lua_script_window);
506 WM::Manager::instance().register_window (&bundle_manager);
507 WM::Manager::instance().register_window (&location_ui);
508 WM::Manager::instance().register_window (&big_clock_window);
509 WM::Manager::instance().register_window (&audio_port_matrix);
510 WM::Manager::instance().register_window (&midi_port_matrix);
511 WM::Manager::instance().register_window (&idleometer);
513 /* do not retain position for add route dialog */
514 add_route_dialog.set_state_mask (WindowProxy::Size);
516 /* Trigger setting up the color scheme and loading the GTK RC file */
518 UIConfiguration::instance().load_rc_file (false);
520 _process_thread = new ProcessThread ();
521 _process_thread->init ();
523 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
529 ARDOUR_UI::pre_release_dialog ()
531 ArdourDialog d (_("Pre-Release Warning"), true, false);
532 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
534 Label* label = manage (new Label);
535 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
536 There are still several issues and bugs to be worked on,\n\
537 as well as general workflow improvements, before this can be considered\n\
538 release software. So, a few guidelines:\n\
540 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
541 though it may be so, depending on your workflow.\n\
542 2) Please wait for a helpful writeup of new features.\n\
543 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
544 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
545 making sure to note the product version number as 5.0-pre.\n\
546 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
547 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
548 can get there directly from within the program via the Help->Chat menu option.\n\
550 Full information on all the above can be found on the support page at\n\
552 http://ardour.org/support\n\
553 "), PROGRAM_NAME, VERSIONSTRING));
555 d.get_vbox()->set_border_width (12);
556 d.get_vbox()->pack_start (*label, false, false, 12);
557 d.get_vbox()->show_all ();
562 GlobalPortMatrixWindow*
563 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
568 return new GlobalPortMatrixWindow (_session, type);
572 ARDOUR_UI::attach_to_engine ()
574 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
575 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
579 ARDOUR_UI::engine_stopped ()
581 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
582 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
583 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
584 update_sample_rate (0);
589 ARDOUR_UI::engine_running ()
591 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
592 if (first_time_engine_run) {
594 first_time_engine_run = false;
598 _session->reset_xrun_count ();
600 update_disk_space ();
602 update_xrun_count ();
603 update_sample_rate (AudioEngine::instance()->sample_rate());
604 update_timecode_format ();
605 update_peak_thread_work ();
606 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
607 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
611 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
613 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
614 /* we can't rely on the original string continuing to exist when we are called
615 again in the GUI thread, so make a copy and note that we need to
618 char *copy = strdup (reason);
619 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
623 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
624 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
626 update_sample_rate (0);
630 /* if the reason is a non-empty string, it means that the backend was shutdown
631 rather than just Ardour.
634 if (strlen (reason)) {
635 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
637 msgstr = string_compose (_("\
638 The audio backend has either been shutdown or it\n\
639 disconnected %1 because %1\n\
640 was not fast enough. Try to restart\n\
641 the audio backend and save the session."), PROGRAM_NAME);
644 MessageDialog msg (_main_window, msgstr);
645 pop_back_splash (msg);
649 free (const_cast<char*> (reason));
654 ARDOUR_UI::post_engine ()
656 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
658 #ifdef AUDIOUNIT_SUPPORT
660 if (AUPluginInfo::au_get_crashlog(au_msg)) {
661 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
662 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
663 info << au_msg << endmsg;
667 ARDOUR::init_post_engine ();
669 /* connect to important signals */
671 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
672 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
673 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
674 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
675 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
677 if (setup_windows ()) {
678 throw failed_constructor ();
681 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
682 XMLNode* n = Config->extra_xml (X_("UI"));
684 _status_bar_visibility.set_state (*n);
687 check_memory_locking();
689 /* this is the first point at which all the possible actions are
690 * available, because some of the available actions are dependent on
691 * aspects of the engine/backend.
694 if (ARDOUR_COMMAND_LINE::show_key_actions) {
696 Bindings::save_all_bindings_as_html (sstr);
698 if (sstr.str().empty()) {
705 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
707 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
713 #ifdef PLATFORM_WINDOWS
719 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
720 #ifndef PLATFORM_WINDOWS
723 g_unlink (file_name);
725 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
731 #ifndef PLATFORM_WINDOWS
735 PBD::open_uri (string_compose ("file:///%1", file_name));
737 halt_connection.disconnect ();
738 AudioEngine::instance()->stop ();
743 if (ARDOUR_COMMAND_LINE::show_actions) {
746 vector<string> paths;
747 vector<string> labels;
748 vector<string> tooltips;
750 vector<Glib::RefPtr<Gtk::Action> > actions;
751 string ver_in = revision;
752 string ver = ver_in.substr(0, ver_in.find("-"));
755 output << "\n<h2>Menu actions</h2>" << endl;
756 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
757 output << " surfaces or scripts.\n</p>\n" << endl;
758 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
759 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
760 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
761 output << "<table class=\"dl\">\n <thead>" << endl;
762 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
763 output << " </thead>\n <tbody>" << endl;
765 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
767 vector<string>::iterator p;
768 vector<string>::iterator l;
770 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
771 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
772 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
774 output << " </tbody>\n </table>" << endl;
776 // output this mess to a browser for easiest X-platform use
777 // it is not pretty HTML, but it works and it's main purpose
778 // is to create raw html to fit in Ardour's manual with no editing
783 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
785 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
791 #ifdef PLATFORM_WINDOWS
797 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
798 #ifndef PLATFORM_WINDOWS
801 g_unlink (file_name);
803 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
809 #ifndef PLATFORM_WINDOWS
813 PBD::open_uri (string_compose ("file:///%1", file_name));
815 halt_connection.disconnect ();
816 AudioEngine::instance()->stop ();
820 /* this being a GUI and all, we want peakfiles */
822 AudioFileSource::set_build_peakfiles (true);
823 AudioFileSource::set_build_missing_peakfiles (true);
825 /* set default clock modes */
827 primary_clock->set_mode (AudioClock::Timecode);
828 secondary_clock->set_mode (AudioClock::BBT);
830 /* start the time-of-day-clock */
833 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
834 update_wall_clock ();
835 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
840 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
841 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
842 Config->map_parameters (pc);
844 UIConfiguration::instance().map_parameters (pc);
848 ARDOUR_UI::~ARDOUR_UI ()
850 UIConfiguration::instance().save_state();
854 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
855 // don't bother at 'real' exit. the OS cleans up for us.
856 delete big_clock; big_clock = 0;
857 delete primary_clock; primary_clock = 0;
858 delete secondary_clock; secondary_clock = 0;
859 delete _process_thread; _process_thread = 0;
860 delete time_info_box; time_info_box = 0;
861 delete meterbridge; meterbridge = 0;
862 delete luawindow; luawindow = 0;
863 delete editor; editor = 0;
864 delete mixer; mixer = 0;
865 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
867 delete gui_object_state; gui_object_state = 0;
868 delete main_window_visibility;
869 FastMeter::flush_pattern_cache ();
870 ArdourFader::flush_pattern_cache ();
874 /* Small trick to flush main-thread event pool.
875 * Other thread-pools are destroyed at pthread_exit(),
876 * but tmain thread termination is too late to trigger Pool::~Pool()
878 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
879 delete ev->event_pool();
884 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
886 if (Splash::instance()) {
887 Splash::instance()->pop_back_for (win);
892 ARDOUR_UI::configure_timeout ()
894 if (last_configure_time == 0) {
895 /* no configure events yet */
899 /* force a gap of 0.5 seconds since the last configure event
902 if (get_microseconds() - last_configure_time < 500000) {
905 have_configure_timeout = false;
906 save_ardour_state ();
912 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
914 if (have_configure_timeout) {
915 last_configure_time = get_microseconds();
917 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
918 have_configure_timeout = true;
925 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
929 if (node.get_property ("roll", str)){
930 roll_controllable->set_id (str);
932 if (node.get_property ("stop", str)) {
933 stop_controllable->set_id (str);
935 if (node.get_property ("goto-start", str)) {
936 goto_start_controllable->set_id (str);
938 if (node.get_property ("goto-end", str)) {
939 goto_end_controllable->set_id (str);
941 if (node.get_property ("auto-loop", str)) {
942 auto_loop_controllable->set_id (str);
944 if (node.get_property ("play-selection", str)) {
945 play_selection_controllable->set_id (str);
947 if (node.get_property ("rec", str)) {
948 rec_controllable->set_id (str);
950 if (node.get_property ("shuttle", str)) {
951 shuttle_box.controllable()->set_id (str);
956 ARDOUR_UI::get_transport_controllable_state ()
958 XMLNode* node = new XMLNode(X_("TransportControllables"));
960 node->set_property (X_("roll"), roll_controllable->id());
961 node->set_property (X_("stop"), stop_controllable->id());
962 node->set_property (X_("goto-start"), goto_start_controllable->id());
963 node->set_property (X_("goto-end"), goto_end_controllable->id());
964 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
965 node->set_property (X_("play-selection"), play_selection_controllable->id());
966 node->set_property (X_("rec"), rec_controllable->id());
967 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
973 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
976 _session->save_state (snapshot_name);
981 ARDOUR_UI::autosave_session ()
983 if (g_main_depth() > 1) {
984 /* inside a recursive main loop,
985 give up because we may not be able to
991 if (!Config->get_periodic_safety_backups()) {
996 _session->maybe_write_autosave();
1003 ARDOUR_UI::session_dirty_changed ()
1010 ARDOUR_UI::update_autosave ()
1012 if (_session && _session->dirty()) {
1013 if (_autosave_connection.connected()) {
1014 _autosave_connection.disconnect();
1017 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1018 Config->get_periodic_safety_backup_interval() * 1000);
1021 if (_autosave_connection.connected()) {
1022 _autosave_connection.disconnect();
1028 ARDOUR_UI::check_announcements ()
1031 string _annc_filename;
1034 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1035 #elif defined PLATFORM_WINDOWS
1036 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1038 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1040 _annc_filename.append (VERSIONSTRING);
1042 _announce_string = "";
1044 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1045 FILE* fin = g_fopen (path.c_str(), "rb");
1047 while (!feof (fin)) {
1050 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1053 _announce_string.append (tmp, len);
1058 pingback (VERSIONSTRING, path);
1063 _hide_splash (gpointer arg)
1065 ((ARDOUR_UI*)arg)->hide_splash();
1070 ARDOUR_UI::starting ()
1072 Application* app = Application::instance ();
1073 const char *nsm_url;
1074 bool brand_new_user = ArdourStartup::required ();
1076 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1077 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1079 if (ARDOUR_COMMAND_LINE::check_announcements) {
1080 check_announcements ();
1085 /* we need to create this early because it may need to set the
1086 * audio backend end up.
1090 audio_midi_setup.get (true);
1092 std::cerr << "audio-midi engine setup failed."<< std::endl;
1096 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1097 nsm = new NSM_Client;
1098 if (!nsm->init (nsm_url)) {
1099 /* the ardour executable may have different names:
1101 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1102 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1103 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1105 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1107 const char *process_name = g_getenv ("ARDOUR_SELF");
1108 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1111 // wait for announce reply from nsm server
1112 for ( i = 0; i < 5000; ++i) {
1116 if (nsm->is_active()) {
1121 error << _("NSM server did not announce itself") << endmsg;
1124 // wait for open command from nsm server
1125 for ( i = 0; i < 5000; ++i) {
1127 Glib::usleep (1000);
1128 if (nsm->client_id ()) {
1134 error << _("NSM: no client ID provided") << endmsg;
1138 if (_session && nsm) {
1139 _session->set_nsm_state( nsm->is_active() );
1141 error << _("NSM: no session created") << endmsg;
1145 // nsm requires these actions disabled
1146 vector<string> action_names;
1147 action_names.push_back("SaveAs");
1148 action_names.push_back("Rename");
1149 action_names.push_back("New");
1150 action_names.push_back("Open");
1151 action_names.push_back("Recent");
1152 action_names.push_back("Close");
1154 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1155 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1157 act->set_sensitive (false);
1164 error << _("NSM: initialization failed") << endmsg;
1170 if (brand_new_user) {
1171 _initial_verbose_plugin_scan = true;
1176 _initial_verbose_plugin_scan = false;
1177 switch (s.response ()) {
1178 case Gtk::RESPONSE_OK:
1185 // TODO: maybe IFF brand_new_user
1186 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1187 std::string dspd (Config->get_default_session_parent_dir());
1188 Searchpath ds (ARDOUR::ardour_data_search_path());
1189 ds.add_subdirectory_to_paths ("sessions");
1190 vector<string> demos;
1191 find_files_matching_pattern (demos, ds, "*.tar.xz");
1193 ARDOUR::RecentSessions rs;
1194 ARDOUR::read_recent_sessions (rs);
1196 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1197 /* "demo-session" must be inside "demo-session.tar.xz"
1200 std::string name = basename_nosuffix (basename_nosuffix (*i));
1201 std::string path = Glib::build_filename (dspd, name);
1202 /* skip if session-dir already exists */
1203 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1206 /* skip sessions that are already in 'recent'.
1207 * eg. a new user changed <session-default-dir> shorly after installation
1209 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1210 if ((*r).first == name) {
1215 PBD::FileArchive ar (*i);
1216 if (0 == ar.inflate (dspd)) {
1217 store_recent_sessions (name, path);
1218 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1224 #ifdef NO_PLUGIN_STATE
1226 ARDOUR::RecentSessions rs;
1227 ARDOUR::read_recent_sessions (rs);
1229 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1231 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1233 /* already used Ardour, have sessions ... warn about plugin state */
1235 ArdourDialog d (_("Free/Demo Version Warning"), true);
1237 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1238 CheckButton c (_("Don't warn me about this again"));
1240 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1241 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1242 _("It will not restore OR save any plugin settings"),
1243 _("If you load an existing session with plugin settings\n"
1244 "they will not be used and will be lost."),
1245 _("To get full access to updates without this limitation\n"
1246 "consider becoming a subscriber for a low cost every month.")));
1247 l.set_justify (JUSTIFY_CENTER);
1249 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1251 d.get_vbox()->pack_start (l, true, true);
1252 d.get_vbox()->pack_start (b, false, false, 12);
1253 d.get_vbox()->pack_start (c, false, false, 12);
1255 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1256 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1260 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1262 if (d.run () != RESPONSE_OK) {
1268 /* go get a session */
1270 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1272 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1273 std::cerr << "Cannot get session parameters."<< std::endl;
1280 WM::Manager::instance().show_visible ();
1282 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1283 * editor window, and we may want stuff to be hidden.
1285 _status_bar_visibility.update ();
1287 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1289 /* all other dialogs are created conditionally */
1295 ARDOUR_UI::check_memory_locking ()
1297 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1298 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1302 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1304 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1306 struct rlimit limits;
1308 long pages, page_size;
1310 size_t pages_len=sizeof(pages);
1311 if ((page_size = getpagesize()) < 0 ||
1312 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1314 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1319 ram = (int64_t) pages * (int64_t) page_size;
1322 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1326 if (limits.rlim_cur != RLIM_INFINITY) {
1328 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1332 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1333 "This might cause %1 to run out of memory before your system "
1334 "runs out of memory. \n\n"
1335 "You can view the memory limit with 'ulimit -l', "
1336 "and it is normally controlled by %2"),
1339 X_("/etc/login.conf")
1341 X_(" /etc/security/limits.conf")
1345 msg.set_default_response (RESPONSE_OK);
1347 VBox* vbox = msg.get_vbox();
1349 CheckButton cb (_("Do not show this window again"));
1350 hbox.pack_start (cb, true, false);
1351 vbox->pack_start (hbox);
1356 pop_back_splash (msg);
1360 if (cb.get_active()) {
1361 XMLNode node (X_("no-memory-warning"));
1362 Config->add_instant_xml (node);
1367 #endif // !__APPLE__
1372 ARDOUR_UI::queue_finish ()
1374 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1378 ARDOUR_UI::idle_finish ()
1381 return false; /* do not call again */
1388 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1390 if (_session->dirty()) {
1391 vector<string> actions;
1392 actions.push_back (_("Don't quit"));
1393 actions.push_back (_("Just quit"));
1394 actions.push_back (_("Save and quit"));
1395 switch (ask_about_saving_session(actions)) {
1400 /* use the default name */
1401 if (save_state_canfail ("")) {
1402 /* failed - don't quit */
1403 MessageDialog msg (_main_window,
1404 string_compose (_("\
1405 %1 was unable to save your session.\n\n\
1406 If you still wish to quit, please use the\n\n\
1407 \"Just quit\" option."), PROGRAM_NAME));
1408 pop_back_splash(msg);
1418 second_connection.disconnect ();
1419 point_one_second_connection.disconnect ();
1420 point_zero_something_second_connection.disconnect();
1421 fps_connection.disconnect();
1424 delete ARDOUR_UI::instance()->video_timeline;
1425 ARDOUR_UI::instance()->video_timeline = NULL;
1426 stop_video_server();
1428 /* Save state before deleting the session, as that causes some
1429 windows to be destroyed before their visible state can be
1432 save_ardour_state ();
1434 if (key_editor.get (false)) {
1435 key_editor->disconnect ();
1438 close_all_dialogs ();
1441 _session->set_clean ();
1442 _session->remove_pending_capture_state ();
1447 halt_connection.disconnect ();
1448 AudioEngine::instance()->stop ();
1449 #ifdef WINDOWS_VST_SUPPORT
1450 fst_stop_threading();
1456 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1458 ArdourDialog window (_("Unsaved Session"));
1459 Gtk::HBox dhbox; // the hbox for the image and text
1460 Gtk::Label prompt_label;
1461 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1465 assert (actions.size() >= 3);
1467 window.add_button (actions[0], RESPONSE_REJECT);
1468 window.add_button (actions[1], RESPONSE_APPLY);
1469 window.add_button (actions[2], RESPONSE_ACCEPT);
1471 window.set_default_response (RESPONSE_ACCEPT);
1473 Gtk::Button noquit_button (msg);
1474 noquit_button.set_name ("EditorGTKButton");
1478 if (_session->snap_name() == _session->name()) {
1479 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1480 _session->snap_name());
1482 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1483 _session->snap_name());
1486 prompt_label.set_text (prompt);
1487 prompt_label.set_name (X_("PrompterLabel"));
1488 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1490 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1491 dhbox.set_homogeneous (false);
1492 dhbox.pack_start (*dimage, false, false, 5);
1493 dhbox.pack_start (prompt_label, true, false, 5);
1494 window.get_vbox()->pack_start (dhbox);
1496 window.set_name (_("Prompter"));
1497 window.set_modal (true);
1498 window.set_resizable (false);
1501 prompt_label.show();
1506 ResponseType r = (ResponseType) window.run();
1511 case RESPONSE_ACCEPT: // save and get out of here
1513 case RESPONSE_APPLY: // get out of here
1524 ARDOUR_UI::every_second ()
1527 update_xrun_count ();
1528 update_buffer_load ();
1529 update_disk_space ();
1530 update_timecode_format ();
1531 update_peak_thread_work ();
1533 if (nsm && nsm->is_active ()) {
1536 if (!_was_dirty && _session->dirty ()) {
1540 else if (_was_dirty && !_session->dirty ()){
1548 ARDOUR_UI::every_point_one_seconds ()
1550 // TODO get rid of this..
1551 // ShuttleControl is updated directly via TransportStateChange signal
1555 ARDOUR_UI::every_point_zero_something_seconds ()
1557 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1559 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1560 float mpeak = editor_meter->update_meters();
1561 if (mpeak > editor_meter_max_peak) {
1562 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1563 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1570 ARDOUR_UI::set_fps_timeout_connection ()
1572 unsigned int interval = 40;
1573 if (!_session) return;
1574 if (_session->timecode_frames_per_second() != 0) {
1575 /* ideally we'll use a select() to sleep and not accumulate
1576 * idle time to provide a regular periodic signal.
1577 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1578 * However, that'll require a dedicated thread and cross-thread
1579 * signals to the GUI Thread..
1581 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1582 * _session->frame_rate() / _session->nominal_frame_rate()
1583 / _session->timecode_frames_per_second()
1585 #ifdef PLATFORM_WINDOWS
1586 // the smallest windows scheduler time-slice is ~15ms.
1587 // periodic GUI timeouts shorter than that will cause
1588 // WaitForSingleObject to spinlock (100% of one CPU Core)
1589 // and gtk never enters idle mode.
1590 // also changing timeBeginPeriod(1) does not affect that in
1591 // any beneficial way, so we just limit the max rate for now.
1592 interval = std::max(30u, interval); // at most ~33Hz.
1594 interval = std::max(8u, interval); // at most 120Hz.
1597 fps_connection.disconnect();
1598 Timers::set_fps_interval (interval);
1602 ARDOUR_UI::update_sample_rate (framecnt_t)
1606 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1608 if (!AudioEngine::instance()->connected()) {
1610 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1614 framecnt_t rate = AudioEngine::instance()->sample_rate();
1617 /* no sample rate available */
1618 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1621 if (fmod (rate, 1000.0) != 0.0) {
1622 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1623 (float) rate / 1000.0f,
1624 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1626 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1628 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1632 sample_rate_label.set_markup (buf);
1636 ARDOUR_UI::update_format ()
1639 format_label.set_text ("");
1644 s << _("File:") << X_(" <span foreground=\"green\">");
1646 switch (_session->config.get_native_file_header_format ()) {
1678 switch (_session->config.get_native_file_data_format ()) {
1692 format_label.set_markup (s.str ());
1696 ARDOUR_UI::update_xrun_count ()
1700 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1701 should also be changed.
1705 const unsigned int x = _session->get_xrun_count ();
1707 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1709 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1712 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1714 xrun_label.set_markup (buf);
1715 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1719 ARDOUR_UI::update_cpu_load ()
1723 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1724 should also be changed.
1727 double const c = AudioEngine::instance()->get_dsp_load ();
1728 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1729 cpu_load_label.set_markup (buf);
1733 ARDOUR_UI::update_peak_thread_work ()
1736 const int c = SourceFactory::peak_work_queue_length ();
1738 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1739 peak_thread_work_label.set_markup (buf);
1741 peak_thread_work_label.set_markup (X_(""));
1746 ARDOUR_UI::update_buffer_load ()
1750 uint32_t const playback = _session ? _session->playback_load () : 100;
1751 uint32_t const capture = _session ? _session->capture_load () : 100;
1753 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1754 should also be changed.
1760 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1761 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1762 playback <= 5 ? X_("red") : X_("green"),
1764 capture <= 5 ? X_("red") : X_("green"),
1768 buffer_load_label.set_markup (buf);
1770 buffer_load_label.set_text ("");
1775 ARDOUR_UI::count_recenabled_streams (Route& route)
1777 Track* track = dynamic_cast<Track*>(&route);
1778 if (track && track->rec_enable_control()->get_value()) {
1779 rec_enabled_streams += track->n_inputs().n_total();
1784 ARDOUR_UI::update_disk_space()
1786 if (_session == 0) {
1790 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1792 framecnt_t fr = _session->frame_rate();
1795 /* skip update - no SR available */
1800 /* Available space is unknown */
1801 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1802 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1803 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1805 rec_enabled_streams = 0;
1806 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1808 framecnt_t frames = opt_frames.get_value_or (0);
1810 if (rec_enabled_streams) {
1811 frames /= rec_enabled_streams;
1818 hrs = frames / (fr * 3600);
1821 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1823 frames -= hrs * fr * 3600;
1824 mins = frames / (fr * 60);
1825 frames -= mins * fr * 60;
1828 bool const low = (hrs == 0 && mins <= 30);
1832 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1833 low ? X_("red") : X_("green"),
1839 disk_space_label.set_markup (buf);
1843 ARDOUR_UI::update_timecode_format ()
1849 TimecodeSlave* tcslave;
1850 SyncSource sync_src = Config->get_sync_source();
1852 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1853 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1858 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1859 matching ? X_("green") : X_("red"),
1860 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1862 snprintf (buf, sizeof (buf), "TC: n/a");
1865 timecode_format_label.set_markup (buf);
1869 ARDOUR_UI::update_wall_clock ()
1873 static int last_min = -1;
1876 tm_now = localtime (&now);
1877 if (last_min != tm_now->tm_min) {
1879 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1880 wall_clock_label.set_text (buf);
1881 last_min = tm_now->tm_min;
1888 ARDOUR_UI::open_recent_session ()
1890 bool can_return = (_session != 0);
1892 SessionDialog recent_session_dialog;
1896 ResponseType r = (ResponseType) recent_session_dialog.run ();
1899 case RESPONSE_ACCEPT:
1903 recent_session_dialog.hide();
1910 recent_session_dialog.hide();
1914 std::string path = recent_session_dialog.session_folder();
1915 std::string state = recent_session_dialog.session_name (should_be_new);
1917 if (should_be_new == true) {
1921 _session_is_new = false;
1923 if (load_session (path, state) == 0) {
1932 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1934 if (!AudioEngine::instance()->connected()) {
1935 MessageDialog msg (parent, string_compose (
1936 _("%1 is not connected to any audio backend.\n"
1937 "You cannot open or close sessions in this condition"),
1939 pop_back_splash (msg);
1947 ARDOUR_UI::open_session ()
1949 if (!check_audioengine (_main_window)) {
1953 /* ardour sessions are folders */
1954 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1955 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1956 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1957 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1960 string session_parent_dir = Glib::path_get_dirname(_session->path());
1961 open_session_selector.set_current_folder(session_parent_dir);
1963 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1966 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1968 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1969 string default_session_folder = Config->get_default_session_parent_dir();
1970 open_session_selector.add_shortcut_folder (default_session_folder);
1972 catch (Glib::Error & e) {
1973 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1976 FileFilter session_filter;
1977 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1978 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1979 open_session_selector.add_filter (session_filter);
1981 FileFilter archive_filter;
1982 archive_filter.add_pattern (X_("*.tar.xz"));
1983 archive_filter.set_name (_("Session Archives"));
1985 open_session_selector.add_filter (archive_filter);
1987 open_session_selector.set_filter (session_filter);
1989 int response = open_session_selector.run();
1990 open_session_selector.hide ();
1992 if (response == Gtk::RESPONSE_CANCEL) {
1996 string session_path = open_session_selector.get_filename();
2000 if (session_path.length() > 0) {
2001 int rv = ARDOUR::inflate_session (session_path,
2002 Config->get_default_session_parent_dir(), path, name);
2004 _session_is_new = false;
2005 load_session (path, name);
2008 MessageDialog msg (_main_window,
2009 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2012 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2013 _session_is_new = isnew;
2014 load_session (path, name);
2020 ARDOUR_UI::session_add_mixed_track (
2021 const ChanCount& input,
2022 const ChanCount& output,
2023 RouteGroup* route_group,
2025 const string& name_template,
2027 PluginInfoPtr instrument,
2028 Plugin::PresetRecord* pset,
2029 ARDOUR::PresentationInfo::order_t order)
2033 if (Profile->get_mixbus ()) {
2038 list<boost::shared_ptr<MidiTrack> > tracks;
2039 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2041 if (tracks.size() != how_many) {
2042 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2047 display_insufficient_ports_message ();
2053 ARDOUR_UI::session_add_midi_bus (
2054 RouteGroup* route_group,
2056 const string& name_template,
2058 PluginInfoPtr instrument,
2059 Plugin::PresetRecord* pset,
2060 ARDOUR::PresentationInfo::order_t order)
2062 if (_session == 0) {
2063 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2067 if (Profile->get_mixbus ()) {
2073 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2074 if (routes.size() != how_many) {
2075 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2080 display_insufficient_ports_message ();
2086 ARDOUR_UI::session_add_midi_route (
2088 RouteGroup* route_group,
2090 const string& name_template,
2092 PluginInfoPtr instrument,
2093 Plugin::PresetRecord* pset,
2094 ARDOUR::PresentationInfo::order_t order)
2096 ChanCount one_midi_channel;
2097 one_midi_channel.set (DataType::MIDI, 1);
2100 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2102 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2107 ARDOUR_UI::session_add_audio_route (
2109 int32_t input_channels,
2110 int32_t output_channels,
2111 ARDOUR::TrackMode mode,
2112 RouteGroup* route_group,
2114 string const & name_template,
2116 ARDOUR::PresentationInfo::order_t order)
2118 list<boost::shared_ptr<AudioTrack> > tracks;
2125 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2127 if (tracks.size() != how_many) {
2128 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2134 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2136 if (routes.size() != how_many) {
2137 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2144 display_insufficient_ports_message ();
2149 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2150 (*i)->set_strict_io (true);
2152 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2153 (*i)->set_strict_io (true);
2159 ARDOUR_UI::display_insufficient_ports_message ()
2161 MessageDialog msg (_main_window,
2162 string_compose (_("There are insufficient ports available\n\
2163 to create a new track or bus.\n\
2164 You should save %1, exit and\n\
2165 restart with more ports."), PROGRAM_NAME));
2166 pop_back_splash (msg);
2171 ARDOUR_UI::transport_goto_start ()
2174 _session->goto_start();
2176 /* force displayed area in editor to start no matter
2177 what "follow playhead" setting is.
2181 editor->center_screen (_session->current_start_frame ());
2187 ARDOUR_UI::transport_goto_zero ()
2190 _session->request_locate (0);
2192 /* force displayed area in editor to start no matter
2193 what "follow playhead" setting is.
2197 editor->reset_x_origin (0);
2203 ARDOUR_UI::transport_goto_wallclock ()
2205 if (_session && editor) {
2212 localtime_r (&now, &tmnow);
2214 framecnt_t frame_rate = _session->frame_rate();
2216 if (frame_rate == 0) {
2217 /* no frame rate available */
2221 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2222 frames += tmnow.tm_min * (60 * frame_rate);
2223 frames += tmnow.tm_sec * frame_rate;
2225 _session->request_locate (frames, _session->transport_rolling ());
2227 /* force displayed area in editor to start no matter
2228 what "follow playhead" setting is.
2232 editor->center_screen (frames);
2238 ARDOUR_UI::transport_goto_end ()
2241 framepos_t const frame = _session->current_end_frame();
2242 _session->request_locate (frame);
2244 /* force displayed area in editor to start no matter
2245 what "follow playhead" setting is.
2249 editor->center_screen (frame);
2255 ARDOUR_UI::transport_stop ()
2261 if (_session->is_auditioning()) {
2262 _session->cancel_audition ();
2266 _session->request_stop (false, true);
2269 /** Check if any tracks are record enabled. If none are, record enable all of them.
2270 * @return true if track record-enabled status was changed, false otherwise.
2273 ARDOUR_UI::trx_record_enable_all_tracks ()
2279 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2280 bool none_record_enabled = true;
2282 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2283 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2286 if (t->rec_enable_control()->get_value()) {
2287 none_record_enabled = false;
2292 if (none_record_enabled) {
2293 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2296 return none_record_enabled;
2300 ARDOUR_UI::transport_record (bool roll)
2303 switch (_session->record_status()) {
2304 case Session::Disabled:
2305 if (_session->ntracks() == 0) {
2306 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."));
2310 if (Profile->get_trx()) {
2311 roll = trx_record_enable_all_tracks ();
2313 _session->maybe_enable_record ();
2318 case Session::Recording:
2320 _session->request_stop();
2322 _session->disable_record (false, true);
2326 case Session::Enabled:
2327 _session->disable_record (false, true);
2333 ARDOUR_UI::transport_roll ()
2339 if (_session->is_auditioning()) {
2344 if (_session->config.get_external_sync()) {
2345 switch (Config->get_sync_source()) {
2349 /* transport controlled by the master */
2355 bool rolling = _session->transport_rolling();
2357 if (_session->get_play_loop()) {
2359 /* If loop playback is not a mode, then we should cancel
2360 it when this action is requested. If it is a mode
2361 we just leave it in place.
2364 if (!Config->get_loop_is_mode()) {
2365 /* XXX it is not possible to just leave seamless loop and keep
2366 playing at present (nov 4th 2009)
2368 if (!Config->get_seamless_loop()) {
2369 /* stop loop playback and stop rolling */
2370 _session->request_play_loop (false, true);
2371 } else if (rolling) {
2372 /* stop loop playback but keep rolling */
2373 _session->request_play_loop (false, false);
2377 } else if (_session->get_play_range () ) {
2378 /* stop playing a range if we currently are */
2379 _session->request_play_range (0, true);
2383 _session->request_transport_speed (1.0f);
2388 ARDOUR_UI::get_smart_mode() const
2390 return ( editor->get_smart_mode() );
2395 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2401 if (_session->is_auditioning()) {
2402 _session->cancel_audition ();
2406 if (_session->config.get_external_sync()) {
2407 switch (Config->get_sync_source()) {
2411 /* transport controlled by the master */
2416 bool rolling = _session->transport_rolling();
2417 bool affect_transport = true;
2419 if (rolling && roll_out_of_bounded_mode) {
2420 /* drop out of loop/range playback but leave transport rolling */
2421 if (_session->get_play_loop()) {
2422 if (_session->actively_recording()) {
2424 /* just stop using the loop, then actually stop
2427 _session->request_play_loop (false, affect_transport);
2430 if (Config->get_seamless_loop()) {
2431 /* the disk buffers contain copies of the loop - we can't
2432 just keep playing, so stop the transport. the user
2433 can restart as they wish.
2435 affect_transport = true;
2437 /* disk buffers are normal, so we can keep playing */
2438 affect_transport = false;
2440 _session->request_play_loop (false, affect_transport);
2442 } else if (_session->get_play_range ()) {
2443 affect_transport = false;
2444 _session->request_play_range (0, true);
2448 if (affect_transport) {
2450 _session->request_stop (with_abort, true);
2452 } else if (!with_abort) { /* with_abort == true means the
2453 * command was intended to stop
2454 * transport, not start.
2457 /* the only external sync condition we can be in here
2458 * would be Engine (JACK) sync, in which case we still
2462 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
2463 _session->request_play_range (&editor->get_selection().time, true);
2464 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2466 _session->request_transport_speed (1.0f);
2472 ARDOUR_UI::toggle_session_auto_loop ()
2478 Location * looploc = _session->locations()->auto_loop_location();
2484 if (_session->get_play_loop()) {
2486 /* looping enabled, our job is to disable it */
2488 _session->request_play_loop (false);
2492 /* looping not enabled, our job is to enable it.
2494 loop-is-NOT-mode: this action always starts the transport rolling.
2495 loop-IS-mode: this action simply sets the loop play mechanism, but
2496 does not start transport.
2498 if (Config->get_loop_is_mode()) {
2499 _session->request_play_loop (true, false);
2501 _session->request_play_loop (true, true);
2505 //show the loop markers
2506 looploc->set_hidden (false, this);
2510 ARDOUR_UI::transport_play_selection ()
2516 editor->play_selection ();
2520 ARDOUR_UI::transport_play_preroll ()
2525 editor->play_with_preroll ();
2529 ARDOUR_UI::transport_rec_preroll ()
2534 editor->rec_with_preroll ();
2538 ARDOUR_UI::transport_rec_count_in ()
2543 editor->rec_with_count_in ();
2547 ARDOUR_UI::transport_rewind (int option)
2549 float current_transport_speed;
2552 current_transport_speed = _session->transport_speed();
2554 if (current_transport_speed >= 0.0f) {
2557 _session->request_transport_speed (-1.0f);
2560 _session->request_transport_speed (-4.0f);
2563 _session->request_transport_speed (-0.5f);
2568 _session->request_transport_speed (current_transport_speed * 1.5f);
2574 ARDOUR_UI::transport_forward (int option)
2580 float current_transport_speed = _session->transport_speed();
2582 if (current_transport_speed <= 0.0f) {
2585 _session->request_transport_speed (1.0f);
2588 _session->request_transport_speed (4.0f);
2591 _session->request_transport_speed (0.5f);
2596 _session->request_transport_speed (current_transport_speed * 1.5f);
2601 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2607 boost::shared_ptr<Route> r;
2609 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2611 boost::shared_ptr<Track> t;
2613 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2614 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2620 ARDOUR_UI::map_transport_state ()
2623 auto_loop_button.unset_active_state ();
2624 play_selection_button.unset_active_state ();
2625 roll_button.unset_active_state ();
2626 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2627 layered_button.set_sensitive (false);
2631 shuttle_box.map_transport_state ();
2633 float sp = _session->transport_speed();
2639 if (_session->get_play_range()) {
2641 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2642 roll_button.unset_active_state ();
2643 auto_loop_button.unset_active_state ();
2645 } else if (_session->get_play_loop ()) {
2647 auto_loop_button.set_active (true);
2648 play_selection_button.set_active (false);
2649 if (Config->get_loop_is_mode()) {
2650 roll_button.set_active (true);
2652 roll_button.set_active (false);
2657 roll_button.set_active (true);
2658 play_selection_button.set_active (false);
2659 auto_loop_button.set_active (false);
2662 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2663 /* light up both roll and play-selection if they are joined */
2664 roll_button.set_active (true);
2665 play_selection_button.set_active (true);
2667 layered_button.set_sensitive (!_session->actively_recording ());
2669 stop_button.set_active (false);
2673 layered_button.set_sensitive (true);
2674 stop_button.set_active (true);
2675 roll_button.set_active (false);
2676 play_selection_button.set_active (false);
2677 if (Config->get_loop_is_mode ()) {
2678 auto_loop_button.set_active (_session->get_play_loop());
2680 auto_loop_button.set_active (false);
2682 update_disk_space ();
2687 ARDOUR_UI::blink_handler (bool blink_on)
2689 transport_rec_enable_blink (blink_on);
2690 sync_blink (blink_on);
2692 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2695 error_blink (blink_on);
2696 solo_blink (blink_on);
2697 audition_blink (blink_on);
2698 feedback_blink (blink_on);
2702 ARDOUR_UI::update_clocks ()
2704 if (!_session) return;
2706 if (editor && !editor->dragging_playhead()) {
2707 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2712 ARDOUR_UI::start_clocking ()
2714 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2715 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2717 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2722 ARDOUR_UI::stop_clocking ()
2724 clock_signal_connection.disconnect ();
2728 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2732 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2734 label->set_text (buf);
2735 bar->set_fraction (fraction);
2737 /* process events, redraws, etc. */
2739 while (gtk_events_pending()) {
2740 gtk_main_iteration ();
2743 return true; /* continue with save-as */
2747 ARDOUR_UI::save_session_as ()
2753 if (_session->dirty()) {
2754 vector<string> actions;
2755 actions.push_back (_("Abort save-as"));
2756 actions.push_back (_("Don't save now, just save-as"));
2757 actions.push_back (_("Save it first"));
2758 switch (ask_about_saving_session(actions)) {
2763 if (save_state_canfail ("")) {
2764 MessageDialog msg (_main_window,
2765 string_compose (_("\
2766 %1 was unable to save your session.\n\n\
2767 If you still wish to proceeed, please use the\n\n\
2768 \"Don't save now\" option."), PROGRAM_NAME));
2769 pop_back_splash(msg);
2775 _session->remove_pending_capture_state ();
2780 if (!save_as_dialog) {
2781 save_as_dialog = new SaveAsDialog;
2784 save_as_dialog->set_name (_session->name());
2786 int response = save_as_dialog->run ();
2788 save_as_dialog->hide ();
2791 case Gtk::RESPONSE_OK:
2800 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2801 sa.new_name = save_as_dialog->new_name ();
2802 sa.switch_to = save_as_dialog->switch_to();
2803 sa.copy_media = save_as_dialog->copy_media();
2804 sa.copy_external = save_as_dialog->copy_external();
2805 sa.include_media = save_as_dialog->include_media ();
2807 /* Only bother with a progress dialog if we're going to copy
2808 media into the save-as target. Without that choice, this
2809 will be very fast because we're only talking about a few kB's to
2810 perhaps a couple of MB's of data.
2813 ArdourDialog progress_dialog (_("Save As"), true);
2816 if (sa.include_media && sa.copy_media) {
2818 Gtk::Label* label = manage (new Gtk::Label());
2819 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2821 progress_dialog.get_vbox()->pack_start (*label);
2822 progress_dialog.get_vbox()->pack_start (*progress_bar);
2824 progress_bar->show ();
2826 /* this signal will be emitted from within this, the calling thread,
2827 * after every file is copied. It provides information on percentage
2828 * complete (in terms of total data to copy), the number of files
2829 * copied so far, and the total number to copy.
2832 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2834 progress_dialog.show_all ();
2835 progress_dialog.present ();
2838 if (_session->save_as (sa)) {
2840 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2844 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2845 * the trick is this: if the new session was copy with media included,
2846 * then Session::save_as() will have already done a neat trick to avoid
2847 * us having to unload and load the new state. But if the media was not
2848 * included, then this is required (it avoids us having to otherwise
2849 * drop all references to media (sources).
2852 if (!sa.include_media && sa.switch_to) {
2853 unload_session (false);
2854 load_session (sa.final_session_folder_name, sa.new_name);
2859 ARDOUR_UI::archive_session ()
2867 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2869 SessionArchiveDialog sad;
2870 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2871 int response = sad.run ();
2873 if (response != Gtk::RESPONSE_OK) {
2878 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2879 MessageDialog msg (_("Session Archiving failed."));
2885 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2889 struct tm local_time;
2892 localtime_r (&n, &local_time);
2893 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2894 if (switch_to_it && _session->dirty ()) {
2895 save_state_canfail ("");
2898 save_state (timebuf, switch_to_it);
2903 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2907 prompter.get_result (snapname);
2909 bool do_save = (snapname.length() != 0);
2912 char illegal = Session::session_name_is_legal(snapname);
2914 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2915 "snapshot names may not contain a '%1' character"), illegal));
2921 vector<std::string> p;
2922 get_state_files_in_directory (_session->session_directory().root_path(), p);
2923 vector<string> n = get_file_names_no_extension (p);
2925 if (find (n.begin(), n.end(), snapname) != n.end()) {
2927 do_save = overwrite_file_dialog (prompter,
2928 _("Confirm Snapshot Overwrite"),
2929 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2933 save_state (snapname, switch_to_it);
2943 /** Ask the user for the name of a new snapshot and then take it.
2947 ARDOUR_UI::snapshot_session (bool switch_to_it)
2949 if (switch_to_it && _session->dirty()) {
2950 vector<string> actions;
2951 actions.push_back (_("Abort saving snapshot"));
2952 actions.push_back (_("Don't save now, just snapshot"));
2953 actions.push_back (_("Save it first"));
2954 switch (ask_about_saving_session(actions)) {
2959 if (save_state_canfail ("")) {
2960 MessageDialog msg (_main_window,
2961 string_compose (_("\
2962 %1 was unable to save your session.\n\n\
2963 If you still wish to proceeed, please use the\n\n\
2964 \"Don't save now\" option."), PROGRAM_NAME));
2965 pop_back_splash(msg);
2971 _session->remove_pending_capture_state ();
2976 Prompter prompter (true);
2977 prompter.set_name ("Prompter");
2978 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2980 prompter.set_title (_("Snapshot and switch"));
2981 prompter.set_prompt (_("New session name"));
2983 prompter.set_title (_("Take Snapshot"));
2984 prompter.set_prompt (_("Name of new snapshot"));
2988 prompter.set_initial_text (_session->snap_name());
2990 Glib::DateTime tm (g_date_time_new_now_local ());
2991 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2994 bool finished = false;
2996 switch (prompter.run()) {
2997 case RESPONSE_ACCEPT:
2999 finished = process_snapshot_session_prompter (prompter, switch_to_it);
3010 /** Ask the user for a new session name and then rename the session to it.
3014 ARDOUR_UI::rename_session ()
3020 Prompter prompter (true);
3023 prompter.set_name ("Prompter");
3024 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3025 prompter.set_title (_("Rename Session"));
3026 prompter.set_prompt (_("New session name"));
3029 switch (prompter.run()) {
3030 case RESPONSE_ACCEPT:
3032 prompter.get_result (name);
3034 bool do_rename = (name.length() != 0);
3037 char illegal = Session::session_name_is_legal (name);
3040 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3041 "session names may not contain a '%1' character"), illegal));
3046 switch (_session->rename (name)) {
3048 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3049 msg.set_position (WIN_POS_MOUSE);
3057 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3058 msg.set_position (WIN_POS_MOUSE);
3074 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3076 if (!_session || _session->deletion_in_progress()) {
3080 XMLNode* node = new XMLNode (X_("UI"));
3082 WM::Manager::instance().add_state (*node);
3084 node->add_child_nocopy (gui_object_state->get_state());
3086 _session->add_extra_xml (*node);
3088 if (export_video_dialog) {
3089 _session->add_extra_xml (export_video_dialog->get_state());
3092 save_state_canfail (name, switch_to_it);
3096 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3101 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3106 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3111 ARDOUR_UI::primary_clock_value_changed ()
3114 _session->request_locate (primary_clock->current_time ());
3119 ARDOUR_UI::big_clock_value_changed ()
3122 _session->request_locate (big_clock->current_time ());
3127 ARDOUR_UI::secondary_clock_value_changed ()
3130 _session->request_locate (secondary_clock->current_time ());
3135 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3137 if (_session == 0) {
3141 if (_session->step_editing()) {
3145 Session::RecordState const r = _session->record_status ();
3146 bool const h = _session->have_rec_enabled_track ();
3148 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3150 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3152 rec_button.set_active_state (Gtkmm2ext::Off);
3154 } else if (r == Session::Recording && h) {
3155 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3157 rec_button.unset_active_state ();
3162 ARDOUR_UI::process_save_template_prompter (Prompter& prompter)
3166 prompter.get_result (name);
3168 if (name.length()) {
3169 int failed = _session->save_template (name);
3171 if (failed == -2) { /* file already exists. */
3172 bool overwrite = overwrite_file_dialog (prompter,
3173 _("Confirm Template Overwrite"),
3174 _("A template already exists with that name. Do you want to overwrite it?"));
3177 _session->save_template (name, true);
3189 ARDOUR_UI::save_template ()
3191 Prompter prompter (true);
3193 if (!check_audioengine (_main_window)) {
3197 prompter.set_name (X_("Prompter"));
3198 prompter.set_title (_("Save Template"));
3199 prompter.set_prompt (_("Name for template:"));
3200 prompter.set_initial_text(_session->name() + _("-template"));
3201 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3203 bool finished = false;
3205 switch (prompter.run()) {
3206 case RESPONSE_ACCEPT:
3207 finished = process_save_template_prompter (prompter);
3217 void ARDOUR_UI::manage_templates ()
3224 ARDOUR_UI::edit_metadata ()
3226 SessionMetadataEditor dialog;
3227 dialog.set_session (_session);
3228 dialog.grab_focus ();
3233 ARDOUR_UI::import_metadata ()
3235 SessionMetadataImporter dialog;
3236 dialog.set_session (_session);
3241 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3243 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3245 MessageDialog msg (str,
3247 Gtk::MESSAGE_WARNING,
3248 Gtk::BUTTONS_YES_NO,
3252 msg.set_name (X_("OpenExistingDialog"));
3253 msg.set_title (_("Open Existing Session"));
3254 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3255 msg.set_position (Gtk::WIN_POS_CENTER);
3256 pop_back_splash (msg);
3258 switch (msg.run()) {
3267 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3269 BusProfile bus_profile;
3272 bus_profile.master_out_channels = 2;
3274 /* get settings from advanced section of NSD */
3275 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3278 // NULL profile: no master, no monitor
3279 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3287 ARDOUR_UI::load_from_application_api (const std::string& path)
3289 /* OS X El Capitan (and probably later) now somehow passes the command
3290 line arguments to an app via the openFile delegate protocol. Ardour
3291 already does its own command line processing, and having both
3292 pathways active causes crashes. So, if the command line was already
3293 set, do nothing here.
3296 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3300 ARDOUR_COMMAND_LINE::session_name = path;
3302 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3304 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3306 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3307 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3308 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3309 * -> SessionDialog is not displayed
3312 if (_session_dialog) {
3313 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3314 std::string session_path = path;
3315 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3316 session_path = Glib::path_get_dirname (session_path);
3318 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3319 _session_dialog->set_provided_session (session_name, session_path);
3320 _session_dialog->response (RESPONSE_NONE);
3321 _session_dialog->hide();
3326 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3327 /* /path/to/foo => /path/to/foo, foo */
3328 rv = load_session (path, basename_nosuffix (path));
3330 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3331 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3334 // if load_session fails -> pop up SessionDialog.
3336 ARDOUR_COMMAND_LINE::session_name = "";
3338 if (get_session_parameters (true, false)) {
3344 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3346 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3348 string session_name;
3349 string session_path;
3350 string template_name;
3352 bool likely_new = false;
3353 bool cancel_not_quit;
3355 /* deal with any existing DIRTY session now, rather than later. don't
3356 * treat a non-dirty session this way, so that it stays visible
3357 * as we bring up the new session dialog.
3360 if (_session && ARDOUR_UI::instance()->video_timeline) {
3361 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3364 /* if there is already a session, relabel the button
3365 on the SessionDialog so that we don't Quit directly
3367 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3369 if (_session && _session->dirty()) {
3370 if (unload_session (false)) {
3371 /* unload cancelled by user */
3374 ARDOUR_COMMAND_LINE::session_name = "";
3377 if (!load_template.empty()) {
3378 should_be_new = true;
3379 template_name = load_template;
3382 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3383 session_path = ARDOUR_COMMAND_LINE::session_name;
3385 if (!session_path.empty()) {
3386 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3387 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3388 /* session/snapshot file, change path to be dir */
3389 session_path = Glib::path_get_dirname (session_path);
3394 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3396 _session_dialog = &session_dialog;
3399 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3401 /* if they named a specific statefile, use it, otherwise they are
3402 just giving a session folder, and we want to use it as is
3403 to find the session.
3406 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3408 if (suffix != string::npos) {
3409 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3410 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3411 session_name = Glib::path_get_basename (session_name);
3413 session_path = ARDOUR_COMMAND_LINE::session_name;
3414 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3419 session_dialog.clear_given ();
3422 if (should_be_new || session_name.empty()) {
3423 /* need the dialog to get info from user */
3425 cerr << "run dialog\n";
3427 switch (session_dialog.run()) {
3428 case RESPONSE_ACCEPT:
3431 /* this is used for async * app->ShouldLoad(). */
3432 continue; // while loop
3435 if (quit_on_cancel) {
3436 ARDOUR_UI::finish ();
3437 Gtkmm2ext::Application::instance()->cleanup();
3439 pthread_cancel_all ();
3440 return -1; // caller is responsible to call exit()
3446 session_dialog.hide ();
3449 /* if we run the startup dialog again, offer more than just "new session" */
3451 should_be_new = false;
3453 session_name = session_dialog.session_name (likely_new);
3454 session_path = session_dialog.session_folder ();
3461 int rv = ARDOUR::inflate_session (session_name,
3462 Config->get_default_session_parent_dir(), session_path, session_name);
3464 MessageDialog msg (session_dialog,
3465 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3470 session_dialog.set_provided_session (session_name, session_path);
3474 // XXX check archive, inflate
3475 string::size_type suffix = session_name.find (statefile_suffix);
3477 if (suffix != string::npos) {
3478 session_name = session_name.substr (0, suffix);
3481 /* this shouldn't happen, but we catch it just in case it does */
3483 if (session_name.empty()) {
3487 if (session_dialog.use_session_template()) {
3488 template_name = session_dialog.session_template_name();
3489 _session_is_new = true;
3492 if (session_name[0] == G_DIR_SEPARATOR ||
3493 #ifdef PLATFORM_WINDOWS
3494 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3496 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3497 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3502 /* absolute path or cwd-relative path specified for session name: infer session folder
3503 from what was given.
3506 session_path = Glib::path_get_dirname (session_name);
3507 session_name = Glib::path_get_basename (session_name);
3511 session_path = session_dialog.session_folder();
3513 char illegal = Session::session_name_is_legal (session_name);
3516 MessageDialog msg (session_dialog,
3517 string_compose (_("To ensure compatibility with various systems\n"
3518 "session names may not contain a '%1' character"),
3521 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3526 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3529 if (likely_new && !nsm) {
3531 std::string existing = Glib::build_filename (session_path, session_name);
3533 if (!ask_about_loading_existing_session (existing)) {
3534 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3539 _session_is_new = false;
3544 pop_back_splash (session_dialog);
3545 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3547 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3551 char illegal = Session::session_name_is_legal(session_name);
3554 pop_back_splash (session_dialog);
3555 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3556 "session names may not contain a '%1' character"), illegal));
3558 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3562 _session_is_new = true;
3565 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3567 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3568 meta_session_setup (template_name.substr (11));
3570 } else if (likely_new && template_name.empty()) {
3572 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3576 ret = load_session (session_path, session_name, template_name);
3579 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3583 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3584 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3588 /* clear this to avoid endless attempts to load the
3592 ARDOUR_COMMAND_LINE::session_name = "";
3596 _session_dialog = NULL;
3602 ARDOUR_UI::close_session()
3604 if (!check_audioengine (_main_window)) {
3608 if (unload_session (true)) {
3612 ARDOUR_COMMAND_LINE::session_name = "";
3614 if (get_session_parameters (true, false)) {
3619 /** @param snap_name Snapshot name (without .ardour suffix).
3620 * @return -2 if the load failed because we are not connected to the AudioEngine.
3623 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3625 /* load_session calls flush_pending() which allows
3626 * GUI interaction and potentially loading another session
3627 * (that was easy via snapshot sidebar).
3628 * Recursing into load_session() from load_session() and recusive
3629 * event loops causes all kind of crashes.
3631 assert (!session_load_in_progress);
3632 if (session_load_in_progress) {
3635 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3637 Session *new_session;
3642 unload_status = unload_session ();
3644 if (unload_status < 0) {
3646 } else if (unload_status > 0) {
3652 session_loaded = false;
3654 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3657 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3660 /* this one is special */
3662 catch (AudioEngine::PortRegistrationFailure& err) {
3664 MessageDialog msg (err.what(),
3667 Gtk::BUTTONS_CLOSE);
3669 msg.set_title (_("Port Registration Error"));
3670 msg.set_secondary_text (_("Click the Close button to try again."));
3671 msg.set_position (Gtk::WIN_POS_CENTER);
3672 pop_back_splash (msg);
3675 int response = msg.run ();
3680 case RESPONSE_CANCEL:
3687 catch (SessionException e) {
3688 MessageDialog msg (string_compose(
3689 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3690 path, snap_name, e.what()),
3695 msg.set_title (_("Loading Error"));
3696 msg.set_position (Gtk::WIN_POS_CENTER);
3697 pop_back_splash (msg);
3709 MessageDialog msg (string_compose(
3710 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3716 msg.set_title (_("Loading Error"));
3717 msg.set_position (Gtk::WIN_POS_CENTER);
3718 pop_back_splash (msg);
3730 list<string> const u = new_session->unknown_processors ();
3732 MissingPluginDialog d (_session, u);
3737 if (!new_session->writable()) {
3738 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3743 msg.set_title (_("Read-only Session"));
3744 msg.set_position (Gtk::WIN_POS_CENTER);
3745 pop_back_splash (msg);
3752 /* Now the session been created, add the transport controls */
3753 new_session->add_controllable(roll_controllable);
3754 new_session->add_controllable(stop_controllable);
3755 new_session->add_controllable(goto_start_controllable);
3756 new_session->add_controllable(goto_end_controllable);
3757 new_session->add_controllable(auto_loop_controllable);
3758 new_session->add_controllable(play_selection_controllable);
3759 new_session->add_controllable(rec_controllable);
3761 set_session (new_session);
3763 session_loaded = true;
3766 _session->set_clean ();
3769 #ifdef WINDOWS_VST_SUPPORT
3770 fst_stop_threading();
3774 Timers::TimerSuspender t;
3778 #ifdef WINDOWS_VST_SUPPORT
3779 fst_start_threading();
3783 if (!mix_template.empty ()) {
3784 /* if mix_template is given, assume this is a new session */
3785 string metascript = Glib::build_filename (mix_template, "template.lua");
3786 meta_session_setup (metascript);
3791 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3792 * which is queued by set_session().
3793 * If session-loading fails we hide it explicitly.
3794 * This covers both cases in a central place.
3803 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3805 Session *new_session;
3808 session_loaded = false;
3809 x = unload_session ();
3817 _session_is_new = true;
3820 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3823 catch (SessionException e) {
3824 cerr << "Here are the errors associated with this failed session:\n";
3826 cerr << "---------\n";
3827 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3828 msg.set_title (_("Loading Error"));
3829 msg.set_position (Gtk::WIN_POS_CENTER);
3830 pop_back_splash (msg);
3835 cerr << "Here are the errors associated with this failed session:\n";
3837 cerr << "---------\n";
3838 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3839 msg.set_title (_("Loading Error"));
3840 msg.set_position (Gtk::WIN_POS_CENTER);
3841 pop_back_splash (msg);
3846 /* Give the new session the default GUI state, if such things exist */
3849 n = Config->instant_xml (X_("Editor"));
3851 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3852 new_session->add_instant_xml (*n, false);
3854 n = Config->instant_xml (X_("Mixer"));
3856 new_session->add_instant_xml (*n, false);
3859 n = Config->instant_xml (X_("Preferences"));
3861 new_session->add_instant_xml (*n, false);
3864 /* Put the playhead at 0 and scroll fully left */
3865 n = new_session->instant_xml (X_("Editor"));
3867 n->set_property (X_("playhead"), X_("0"));
3868 n->set_property (X_("left-frame"), X_("0"));
3871 set_session (new_session);
3873 session_loaded = true;
3875 new_session->save_state(new_session->name());
3881 static void _lua_print (std::string s) {
3883 std::cout << "LuaInstance: " << s << "\n";
3885 PBD::info << "LuaInstance: " << s << endmsg;
3888 std::map<std::string, std::string>
3889 ARDOUR_UI::route_setup_info (const std::string& script_path)
3891 std::map<std::string, std::string> rv;
3893 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3898 lua.Print.connect (&_lua_print);
3901 lua_State* L = lua.getState();
3902 LuaInstance::register_classes (L);
3903 LuaBindings::set_session (L, _session);
3904 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3905 lua_setglobal (L, "Editor");
3907 lua.do_command ("function ardour () end");
3908 lua.do_file (script_path);
3911 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3912 if (!fn.isFunction ()) {
3915 luabridge::LuaRef rs = fn ();
3916 if (!rs.isTable ()) {
3919 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3920 if (!i.key().isString()) {
3923 std::string key = i.key().tostring();
3924 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3925 rv[key] = i.value().tostring();
3928 } catch (luabridge::LuaException const& e) {
3929 cerr << "LuaException:" << e.what () << endl;
3936 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3938 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3941 assert (add_route_dialog);
3944 if ((count = add_route_dialog->count()) <= 0) {
3949 lua.Print.connect (&_lua_print);
3952 lua_State* L = lua.getState();
3953 LuaInstance::register_classes (L);
3954 LuaBindings::set_session (L, _session);
3955 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3956 lua_setglobal (L, "Editor");
3958 lua.do_command ("function ardour () end");
3959 lua.do_file (script_path);
3961 luabridge::LuaRef args (luabridge::newTable (L));
3963 args["name"] = add_route_dialog->name_template ();
3964 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3965 args["group"] = add_route_dialog->route_group ();
3966 args["strict_io"] = add_route_dialog->use_strict_io ();
3967 args["instrument"] = add_route_dialog->requested_instrument ();
3968 args["track_mode"] = add_route_dialog->mode ();
3969 args["channels"] = add_route_dialog->channel_count ();
3970 args["how_many"] = count;
3973 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3974 if (fn.isFunction()) {
3977 } catch (luabridge::LuaException const& e) {
3978 cerr << "LuaException:" << e.what () << endl;
3983 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3985 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3990 lua.Print.connect (&_lua_print);
3993 lua_State* L = lua.getState();
3994 LuaInstance::register_classes (L);
3995 LuaBindings::set_session (L, _session);
3996 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3997 lua_setglobal (L, "Editor");
3999 lua.do_command ("function ardour () end");
4000 lua.do_file (script_path);
4003 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
4004 if (fn.isFunction()) {
4007 } catch (luabridge::LuaException const& e) {
4008 cerr << "LuaException:" << e.what () << endl;
4013 ARDOUR_UI::launch_chat ()
4015 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
4017 dialog.set_title (_("About the Chat"));
4018 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."));
4020 switch (dialog.run()) {
4023 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
4024 #elif defined PLATFORM_WINDOWS
4025 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
4027 open_uri("http://webchat.freenode.net/?channels=ardour");
4036 ARDOUR_UI::launch_manual ()
4038 PBD::open_uri (Config->get_tutorial_manual_url());
4042 ARDOUR_UI::launch_reference ()
4044 PBD::open_uri (Config->get_reference_manual_url());
4048 ARDOUR_UI::launch_tracker ()
4050 PBD::open_uri ("http://tracker.ardour.org");
4054 ARDOUR_UI::launch_subscribe ()
4056 PBD::open_uri ("https://community.ardour.org/s/subscribe");
4060 ARDOUR_UI::launch_cheat_sheet ()
4063 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
4065 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
4070 ARDOUR_UI::launch_website ()
4072 PBD::open_uri ("http://ardour.org");
4076 ARDOUR_UI::launch_website_dev ()
4078 PBD::open_uri ("http://ardour.org/development.html");
4082 ARDOUR_UI::launch_forums ()
4084 PBD::open_uri ("https://community.ardour.org/forums");
4088 ARDOUR_UI::launch_howto_report ()
4090 PBD::open_uri ("http://ardour.org/reporting_bugs");
4094 ARDOUR_UI::loading_message (const std::string& msg)
4096 if (ARDOUR_COMMAND_LINE::no_splash) {
4104 splash->message (msg);
4108 ARDOUR_UI::show_splash ()
4112 splash = new Splash;
4122 ARDOUR_UI::hide_splash ()
4129 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4133 removed = rep.paths.size();
4136 MessageDialog msgd (_main_window,
4137 _("No files were ready for clean-up"),
4141 msgd.set_title (_("Clean-up"));
4142 msgd.set_secondary_text (_("If this seems surprising, \n\
4143 check for any existing snapshots.\n\
4144 These may still include regions that\n\
4145 require some unused files to continue to exist."));
4151 ArdourDialog results (_("Clean-up"), true, false);
4153 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4154 CleanupResultsModelColumns() {
4158 Gtk::TreeModelColumn<std::string> visible_name;
4159 Gtk::TreeModelColumn<std::string> fullpath;
4163 CleanupResultsModelColumns results_columns;
4164 Glib::RefPtr<Gtk::ListStore> results_model;
4165 Gtk::TreeView results_display;
4167 results_model = ListStore::create (results_columns);
4168 results_display.set_model (results_model);
4169 results_display.append_column (list_title, results_columns.visible_name);
4171 results_display.set_name ("CleanupResultsList");
4172 results_display.set_headers_visible (true);
4173 results_display.set_headers_clickable (false);
4174 results_display.set_reorderable (false);
4176 Gtk::ScrolledWindow list_scroller;
4179 Gtk::HBox dhbox; // the hbox for the image and text
4180 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4181 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4183 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4185 const string dead_directory = _session->session_directory().dead_path();
4188 %1 - number of files removed
4189 %2 - location of "dead"
4190 %3 - size of files affected
4191 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4194 const char* bprefix;
4195 double space_adjusted = 0;
4197 if (rep.space < 1000) {
4199 space_adjusted = rep.space;
4200 } else if (rep.space < 1000000) {
4201 bprefix = _("kilo");
4202 space_adjusted = floorf((float)rep.space / 1000.0);
4203 } else if (rep.space < 1000000 * 1000) {
4204 bprefix = _("mega");
4205 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4207 bprefix = _("giga");
4208 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4212 txt.set_markup (string_compose (P_("\
4213 The following file was deleted from %2,\n\
4214 releasing %3 %4bytes of disk space", "\
4215 The following %1 files were deleted from %2,\n\
4216 releasing %3 %4bytes of disk space", removed),
4217 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4219 txt.set_markup (string_compose (P_("\
4220 The following file was not in use and \n\
4221 has been moved to: %2\n\n\
4222 After a restart of %5\n\n\
4223 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4224 will release an additional %3 %4bytes of disk space.\n", "\
4225 The following %1 files were not in use and \n\
4226 have been moved to: %2\n\n\
4227 After a restart of %5\n\n\
4228 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4229 will release an additional %3 %4bytes of disk space.\n", removed),
4230 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4233 dhbox.pack_start (*dimage, true, false, 5);
4234 dhbox.pack_start (txt, true, false, 5);
4236 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4237 TreeModel::Row row = *(results_model->append());
4238 row[results_columns.visible_name] = *i;
4239 row[results_columns.fullpath] = *i;
4242 list_scroller.add (results_display);
4243 list_scroller.set_size_request (-1, 150);
4244 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4246 dvbox.pack_start (dhbox, true, false, 5);
4247 dvbox.pack_start (list_scroller, true, false, 5);
4248 ddhbox.pack_start (dvbox, true, false, 5);
4250 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4251 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4252 results.set_default_response (RESPONSE_CLOSE);
4253 results.set_position (Gtk::WIN_POS_MOUSE);
4255 results_display.show();
4256 list_scroller.show();
4263 //results.get_vbox()->show();
4264 results.set_resizable (false);
4271 ARDOUR_UI::cleanup ()
4273 if (_session == 0) {
4274 /* shouldn't happen: menu item is insensitive */
4279 MessageDialog checker (_("Are you sure you want to clean-up?"),
4281 Gtk::MESSAGE_QUESTION,
4284 checker.set_title (_("Clean-up"));
4286 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4287 ALL undo/redo information will be lost if you clean-up.\n\
4288 Clean-up will move all unused files to a \"dead\" location."));
4290 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4291 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4292 checker.set_default_response (RESPONSE_CANCEL);
4294 checker.set_name (_("CleanupDialog"));
4295 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4296 checker.set_position (Gtk::WIN_POS_MOUSE);
4298 switch (checker.run()) {
4299 case RESPONSE_ACCEPT:
4305 ARDOUR::CleanupReport rep;
4307 editor->prepare_for_cleanup ();
4309 /* do not allow flush until a session is reloaded */
4311 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4313 act->set_sensitive (false);
4316 if (_session->cleanup_sources (rep)) {
4317 editor->finish_cleanup ();
4321 editor->finish_cleanup ();
4324 display_cleanup_results (rep, _("Cleaned Files"), false);
4328 ARDOUR_UI::flush_trash ()
4330 if (_session == 0) {
4331 /* shouldn't happen: menu item is insensitive */
4335 ARDOUR::CleanupReport rep;
4337 if (_session->cleanup_trash_sources (rep)) {
4341 display_cleanup_results (rep, _("deleted file"), true);
4345 ARDOUR_UI::cleanup_peakfiles ()
4347 if (_session == 0) {
4348 /* shouldn't happen: menu item is insensitive */
4352 if (! _session->can_cleanup_peakfiles ()) {
4356 // get all region-views in this session
4358 TrackViewList empty;
4360 editor->get_regions_after(rs, (framepos_t) 0, empty);
4361 std::list<RegionView*> views = rs.by_layer();
4363 // remove displayed audio-region-views waveforms
4364 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4365 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4366 if (!arv) { continue ; }
4367 arv->delete_waves();
4370 // cleanup peak files:
4371 // - stop pending peakfile threads
4372 // - close peakfiles if any
4373 // - remove peak dir in session
4374 // - setup peakfiles (background thread)
4375 _session->cleanup_peakfiles ();
4377 // re-add waves to ARV
4378 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4379 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4380 if (!arv) { continue ; }
4381 arv->create_waves();
4385 PresentationInfo::order_t
4386 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4388 if (editor->get_selection().tracks.empty()) {
4389 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4392 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4395 we want the new routes to have their order keys set starting from
4396 the highest order key in the selection + 1 (if available).
4399 if (place == RouteDialogs::AfterSelection) {
4400 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4402 order_hint = rtav->route()->presentation_info().order();
4405 } else if (place == RouteDialogs::BeforeSelection) {
4406 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4408 order_hint = rtav->route()->presentation_info().order();
4410 } else if (place == RouteDialogs::First) {
4413 /* leave order_hint at max_order */
4420 ARDOUR_UI::start_duplicate_routes ()
4422 if (!duplicate_routes_dialog) {
4423 duplicate_routes_dialog = new DuplicateRouteDialog;
4426 if (duplicate_routes_dialog->restart (_session)) {
4430 duplicate_routes_dialog->present ();
4434 ARDOUR_UI::add_route ()
4436 if (!add_route_dialog.get (false)) {
4437 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4444 if (add_route_dialog->is_visible()) {
4445 /* we're already doing this */
4449 add_route_dialog->set_position (WIN_POS_MOUSE);
4450 add_route_dialog->present();
4454 ARDOUR_UI::add_route_dialog_response (int r)
4457 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4464 case AddRouteDialog::Add:
4466 case AddRouteDialog::AddAndClose:
4467 add_route_dialog->ArdourDialog::on_response (r);
4470 add_route_dialog->ArdourDialog::on_response (r);
4474 std::string template_path = add_route_dialog->get_template_path();
4475 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4476 meta_route_setup (template_path.substr (11));
4480 if ((count = add_route_dialog->count()) <= 0) {
4484 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4485 const string name_template = add_route_dialog->name_template ();
4486 DisplaySuspender ds;
4488 if (!template_path.empty ()) {
4489 if (add_route_dialog->name_template_is_default ()) {
4490 _session->new_route_from_template (count, order, template_path, string ());
4492 _session->new_route_from_template (count, order, template_path, name_template);
4497 ChanCount input_chan= add_route_dialog->channels ();
4498 ChanCount output_chan;
4499 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4500 RouteGroup* route_group = add_route_dialog->route_group ();
4501 AutoConnectOption oac = Config->get_output_auto_connect();
4502 bool strict_io = add_route_dialog->use_strict_io ();
4504 if (oac & AutoConnectMaster) {
4505 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4506 output_chan.set (DataType::MIDI, 0);
4508 output_chan = input_chan;
4511 /* XXX do something with name template */
4513 Session::ProcessorChangeBlocker pcb (_session);
4515 switch (add_route_dialog->type_wanted()) {
4516 case AddRouteDialog::AudioTrack:
4517 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);
4519 case AddRouteDialog::MidiTrack:
4520 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4522 case AddRouteDialog::MixedTrack:
4523 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4525 case AddRouteDialog::AudioBus:
4526 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4528 case AddRouteDialog::MidiBus:
4529 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4531 case AddRouteDialog::VCAMaster:
4532 _session->vca_manager().create_vca (count, name_template);
4538 ARDOUR_UI::stop_video_server (bool ask_confirm)
4540 if (!video_server_process && ask_confirm) {
4541 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4543 if (video_server_process) {
4545 ArdourDialog confirm (_("Stop Video-Server"), true);
4546 Label m (_("Do you really want to stop the Video Server?"));
4547 confirm.get_vbox()->pack_start (m, true, true);
4548 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4549 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4550 confirm.show_all ();
4551 if (confirm.run() == RESPONSE_CANCEL) {
4555 delete video_server_process;
4556 video_server_process =0;
4561 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4563 ARDOUR_UI::start_video_server( float_window, true);
4567 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4573 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4574 if (video_server_process) {
4575 popup_error(_("The Video Server is already started."));
4577 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4583 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4585 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4587 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4589 video_server_dialog->set_transient_for (*float_window);
4592 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4593 video_server_dialog->hide();
4595 ResponseType r = (ResponseType) video_server_dialog->run ();
4596 video_server_dialog->hide();
4597 if (r != RESPONSE_ACCEPT) { return false; }
4598 if (video_server_dialog->show_again()) {
4599 Config->set_show_video_server_dialog(false);
4603 std::string icsd_exec = video_server_dialog->get_exec_path();
4604 std::string icsd_docroot = video_server_dialog->get_docroot();
4605 #ifndef PLATFORM_WINDOWS
4606 if (icsd_docroot.empty()) {
4607 icsd_docroot = VideoUtils::video_get_docroot (Config);
4612 #ifdef PLATFORM_WINDOWS
4613 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4614 /* OK, allow all drive letters */
4617 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4618 warning << _("Specified docroot is not an existing directory.") << endmsg;
4621 #ifndef PLATFORM_WINDOWS
4622 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4623 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4624 warning << _("Given Video Server is not an executable file.") << endmsg;
4628 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4629 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4630 warning << _("Given Video Server is not an executable file.") << endmsg;
4636 argp=(char**) calloc(9,sizeof(char*));
4637 argp[0] = strdup(icsd_exec.c_str());
4638 argp[1] = strdup("-P");
4639 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4640 argp[3] = strdup("-p");
4641 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4642 argp[5] = strdup("-C");
4643 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4644 argp[7] = strdup(icsd_docroot.c_str());
4646 stop_video_server();
4648 #ifdef PLATFORM_WINDOWS
4649 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4650 /* OK, allow all drive letters */
4653 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4654 Config->set_video_advanced_setup(false);
4656 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4657 Config->set_video_server_url(url_str);
4658 Config->set_video_server_docroot(icsd_docroot);
4659 Config->set_video_advanced_setup(true);
4662 if (video_server_process) {
4663 delete video_server_process;
4666 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4667 if (video_server_process->start()) {
4668 warning << _("Cannot launch the video-server") << endmsg;
4671 int timeout = 120; // 6 sec
4672 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4673 Glib::usleep (50000);
4675 if (--timeout <= 0 || !video_server_process->is_running()) break;
4678 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4680 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4681 delete video_server_process;
4682 video_server_process = 0;
4690 ARDOUR_UI::add_video (Gtk::Window* float_window)
4696 if (!start_video_server(float_window, false)) {
4697 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4702 add_video_dialog->set_transient_for (*float_window);
4705 if (add_video_dialog->is_visible()) {
4706 /* we're already doing this */
4710 ResponseType r = (ResponseType) add_video_dialog->run ();
4711 add_video_dialog->hide();
4712 if (r != RESPONSE_ACCEPT) { return; }
4714 bool local_file, orig_local_file;
4715 std::string path = add_video_dialog->file_name(local_file);
4717 std::string orig_path = path;
4718 orig_local_file = local_file;
4720 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4722 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4723 warning << string_compose(_("could not open %1"), path) << endmsg;
4726 if (!local_file && path.length() == 0) {
4727 warning << _("no video-file selected") << endmsg;
4731 std::string audio_from_video;
4732 bool detect_ltc = false;
4734 switch (add_video_dialog->import_option()) {
4735 case VTL_IMPORT_TRANSCODE:
4737 TranscodeVideoDialog *transcode_video_dialog;
4738 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4739 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4740 transcode_video_dialog->hide();
4741 if (r != RESPONSE_ACCEPT) {
4742 delete transcode_video_dialog;
4746 audio_from_video = transcode_video_dialog->get_audiofile();
4748 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4751 else if (!audio_from_video.empty()) {
4752 editor->embed_audio_from_video(
4754 video_timeline->get_offset(),
4755 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4758 switch (transcode_video_dialog->import_option()) {
4759 case VTL_IMPORT_TRANSCODED:
4760 path = transcode_video_dialog->get_filename();
4763 case VTL_IMPORT_REFERENCE:
4766 delete transcode_video_dialog;
4769 delete transcode_video_dialog;
4773 case VTL_IMPORT_NONE:
4777 /* strip _session->session_directory().video_path() from video file if possible */
4778 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4779 path=path.substr(_session->session_directory().video_path().size());
4780 if (path.at(0) == G_DIR_SEPARATOR) {
4781 path=path.substr(1);
4785 video_timeline->set_update_session_fps(auto_set_session_fps);
4787 if (video_timeline->video_file_info(path, local_file)) {
4788 XMLNode* node = new XMLNode(X_("Videotimeline"));
4789 node->set_property (X_("Filename"), path);
4790 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4791 node->set_property (X_("LocalFile"), local_file);
4792 if (orig_local_file) {
4793 node->set_property (X_("OriginalVideoFile"), orig_path);
4795 node->remove_property (X_("OriginalVideoFile"));
4797 _session->add_extra_xml (*node);
4798 _session->set_dirty ();
4800 if (!audio_from_video.empty() && detect_ltc) {
4801 std::vector<LTCFileReader::LTCMap> ltc_seq;
4804 /* TODO ask user about TV standard (LTC alignment if any) */
4805 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4806 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4808 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4810 /* TODO seek near end of file, and read LTC until end.
4811 * if it fails to find any LTC frames, scan complete file
4813 * calculate drift of LTC compared to video-duration,
4814 * ask user for reference (timecode from start/mid/end)
4817 // LTCFileReader will have written error messages
4820 ::g_unlink(audio_from_video.c_str());
4822 if (ltc_seq.size() == 0) {
4823 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4825 /* the very first TC in the file is somteimes not aligned properly */
4826 int i = ltc_seq.size() -1;
4827 ARDOUR::frameoffset_t video_start_offset =
4828 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4829 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4830 video_timeline->set_offset(video_start_offset);
4834 _session->maybe_update_session_range(
4835 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4836 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4839 if (add_video_dialog->launch_xjadeo() && local_file) {
4840 editor->set_xjadeo_sensitive(true);
4841 editor->toggle_xjadeo_proc(1);
4843 editor->toggle_xjadeo_proc(0);
4845 editor->toggle_ruler_video(true);
4850 ARDOUR_UI::remove_video ()
4852 video_timeline->close_session();
4853 editor->toggle_ruler_video(false);
4856 video_timeline->set_offset_locked(false);
4857 video_timeline->set_offset(0);
4859 /* delete session state */
4860 XMLNode* node = new XMLNode(X_("Videotimeline"));
4861 _session->add_extra_xml(*node);
4862 node = new XMLNode(X_("Videomonitor"));
4863 _session->add_extra_xml(*node);
4864 node = new XMLNode(X_("Videoexport"));
4865 _session->add_extra_xml(*node);
4866 stop_video_server();
4870 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4872 if (localcacheonly) {
4873 video_timeline->vmon_update();
4875 video_timeline->flush_cache();
4877 editor->queue_visual_videotimeline_update();
4881 ARDOUR_UI::export_video (bool range)
4883 if (ARDOUR::Config->get_show_video_export_info()) {
4884 ExportVideoInfobox infobox (_session);
4885 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4886 if (infobox.show_again()) {
4887 ARDOUR::Config->set_show_video_export_info(false);
4890 case GTK_RESPONSE_YES:
4891 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4897 export_video_dialog->set_session (_session);
4898 export_video_dialog->apply_state(editor->get_selection().time, range);
4899 export_video_dialog->run ();
4900 export_video_dialog->hide ();
4904 ARDOUR_UI::preferences_settings () const
4909 node = _session->instant_xml(X_("Preferences"));
4911 node = Config->instant_xml(X_("Preferences"));
4915 node = new XMLNode (X_("Preferences"));
4922 ARDOUR_UI::mixer_settings () const
4927 node = _session->instant_xml(X_("Mixer"));
4929 node = Config->instant_xml(X_("Mixer"));
4933 node = new XMLNode (X_("Mixer"));
4940 ARDOUR_UI::main_window_settings () const
4945 node = _session->instant_xml(X_("Main"));
4947 node = Config->instant_xml(X_("Main"));
4951 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4952 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4957 node = new XMLNode (X_("Main"));
4964 ARDOUR_UI::editor_settings () const
4969 node = _session->instant_xml(X_("Editor"));
4971 node = Config->instant_xml(X_("Editor"));
4975 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4976 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4981 node = new XMLNode (X_("Editor"));
4988 ARDOUR_UI::keyboard_settings () const
4992 node = Config->extra_xml(X_("Keyboard"));
4995 node = new XMLNode (X_("Keyboard"));
5002 ARDOUR_UI::create_xrun_marker (framepos_t where)
5005 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
5006 _session->locations()->add (location);
5011 ARDOUR_UI::halt_on_xrun_message ()
5013 cerr << "HALT on xrun\n";
5014 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
5019 ARDOUR_UI::xrun_handler (framepos_t where)
5025 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
5027 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
5028 create_xrun_marker(where);
5031 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
5032 halt_on_xrun_message ();
5037 ARDOUR_UI::disk_overrun_handler ()
5039 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
5041 if (!have_disk_speed_dialog_displayed) {
5042 have_disk_speed_dialog_displayed = true;
5043 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
5044 The disk system on your computer\n\
5045 was not able to keep up with %1.\n\
5047 Specifically, it failed to write data to disk\n\
5048 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
5049 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5055 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
5056 static MessageDialog *scan_dlg = NULL;
5057 static ProgressBar *scan_pbar = NULL;
5058 static HBox *scan_tbox = NULL;
5059 static Gtk::Button *scan_timeout_button;
5062 ARDOUR_UI::cancel_plugin_scan ()
5064 PluginManager::instance().cancel_plugin_scan();
5068 ARDOUR_UI::cancel_plugin_timeout ()
5070 PluginManager::instance().cancel_plugin_timeout();
5071 scan_timeout_button->set_sensitive (false);
5075 ARDOUR_UI::plugin_scan_timeout (int timeout)
5077 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5081 scan_pbar->set_sensitive (false);
5082 scan_timeout_button->set_sensitive (true);
5083 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5086 scan_pbar->set_sensitive (false);
5087 scan_timeout_button->set_sensitive (false);
5093 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5095 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5099 const bool cancelled = PluginManager::instance().cancelled();
5100 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5101 if (cancelled && scan_dlg->is_mapped()) {
5106 if (cancelled || !can_cancel) {
5111 static Gtk::Button *cancel_button;
5113 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5114 VBox* vbox = scan_dlg->get_vbox();
5115 vbox->set_size_request(400,-1);
5116 scan_dlg->set_title (_("Scanning for plugins"));
5118 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5119 cancel_button->set_name ("EditorGTKButton");
5120 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5121 cancel_button->show();
5123 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5125 scan_tbox = manage( new HBox() );
5127 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5128 scan_timeout_button->set_name ("EditorGTKButton");
5129 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5130 scan_timeout_button->show();
5132 scan_pbar = manage(new ProgressBar());
5133 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5134 scan_pbar->set_text(_("Scan Timeout"));
5137 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5138 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5140 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5143 assert(scan_dlg && scan_tbox && cancel_button);
5145 if (type == X_("closeme")) {
5149 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5152 if (!can_cancel || !cancelled) {
5153 scan_timeout_button->set_sensitive(false);
5155 cancel_button->set_sensitive(can_cancel && !cancelled);
5161 ARDOUR_UI::gui_idle_handler ()
5164 /* due to idle calls, gtk_events_pending() may always return true */
5165 while (gtk_events_pending() && --timeout) {
5166 gtk_main_iteration ();
5171 ARDOUR_UI::disk_underrun_handler ()
5173 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5175 if (!have_disk_speed_dialog_displayed) {
5176 have_disk_speed_dialog_displayed = true;
5177 MessageDialog* msg = new MessageDialog (
5178 _main_window, string_compose (_("The disk system on your computer\n\
5179 was not able to keep up with %1.\n\
5181 Specifically, it failed to read data from disk\n\
5182 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5183 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5189 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5191 have_disk_speed_dialog_displayed = false;
5196 ARDOUR_UI::session_dialog (std::string msg)
5198 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5202 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5209 ARDOUR_UI::pending_state_dialog ()
5211 HBox* hbox = manage (new HBox());
5212 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5213 ArdourDialog dialog (_("Crash Recovery"), true);
5214 Label message (string_compose (_("\
5215 This session appears to have been in the\n\
5216 middle of recording when %1 or\n\
5217 the computer was shutdown.\n\
5219 %1 can recover any captured audio for\n\
5220 you, or it can ignore it. Please decide\n\
5221 what you would like to do.\n"), PROGRAM_NAME));
5222 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5223 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5224 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5225 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5226 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5227 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5228 dialog.set_default_response (RESPONSE_ACCEPT);
5229 dialog.set_position (WIN_POS_CENTER);
5234 switch (dialog.run ()) {
5235 case RESPONSE_ACCEPT:
5243 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5245 HBox* hbox = new HBox();
5246 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5247 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5248 Label message (string_compose (_("\
5249 This session was created with a sample rate of %1 Hz, but\n\
5250 %2 is currently running at %3 Hz. If you load this session,\n\
5251 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5253 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5254 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5255 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5256 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5257 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5258 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5259 dialog.set_default_response (RESPONSE_ACCEPT);
5260 dialog.set_position (WIN_POS_CENTER);
5265 switch (dialog.run()) {
5266 case RESPONSE_ACCEPT:
5276 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5278 MessageDialog msg (string_compose (_("\
5279 This session was created with a sample rate of %1 Hz, but\n\
5280 %2 is currently running at %3 Hz.\n\
5281 Audio will be recorded and played at the wrong sample rate.\n\
5282 Re-Configure the Audio Engine in\n\
5283 Menu > Window > Audio/Midi Setup"),
5284 desired, PROGRAM_NAME, actual),
5286 Gtk::MESSAGE_WARNING);
5291 ARDOUR_UI::use_config ()
5293 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5295 set_transport_controllable_state (*node);
5300 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5302 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5303 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5305 primary_clock->set (pos);
5308 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5309 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5311 secondary_clock->set (pos);
5314 if (big_clock_window) {
5315 big_clock->set (pos);
5317 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5321 ARDOUR_UI::step_edit_status_change (bool yn)
5323 // XXX should really store pre-step edit status of things
5324 // we make insensitive
5327 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5328 rec_button.set_sensitive (false);
5330 rec_button.unset_active_state ();;
5331 rec_button.set_sensitive (true);
5336 ARDOUR_UI::record_state_changed ()
5338 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5341 /* why bother - the clock isn't visible */
5345 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5347 if (big_clock_window) {
5348 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5349 big_clock->set_active (true);
5351 big_clock->set_active (false);
5358 ARDOUR_UI::first_idle ()
5361 _session->allow_auto_play (true);
5365 editor->first_idle();
5368 /* in 1 second, hide the splash screen
5370 * Consider hiding it *now*. If a user opens opens a dialog
5371 * during that one second while the splash is still visible,
5372 * the dialog will push-back the splash.
5373 * Closing the dialog later will pop it back.
5375 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5377 Keyboard::set_can_save_keybindings (true);
5382 ARDOUR_UI::store_clock_modes ()
5384 XMLNode* node = new XMLNode(X_("ClockModes"));
5386 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5387 XMLNode* child = new XMLNode (X_("Clock"));
5389 child->set_property (X_("name"), (*x)->name());
5390 child->set_property (X_("mode"), (*x)->mode());
5391 child->set_property (X_("on"), (*x)->on());
5393 node->add_child_nocopy (*child);
5396 _session->add_extra_xml (*node);
5397 _session->set_dirty ();
5400 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5401 : Controllable (name), ui (u), type(tp)
5407 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5410 /* do nothing: these are radio-style actions */
5414 const char *action = 0;
5418 action = X_("Roll");
5421 action = X_("Stop");
5424 action = X_("GotoStart");
5427 action = X_("GotoEnd");
5430 action = X_("Loop");
5433 action = X_("PlaySelection");
5436 action = X_("Record");
5446 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5454 ARDOUR_UI::TransportControllable::get_value (void) const
5481 ARDOUR_UI::setup_profile ()
5483 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5484 Profile->set_small_screen ();
5487 if (g_getenv ("TRX")) {
5488 Profile->set_trx ();
5491 if (g_getenv ("MIXBUS")) {
5492 Profile->set_mixbus ();
5497 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5499 MissingFileDialog dialog (s, str, type);
5504 int result = dialog.run ();
5511 return 1; // quit entire session load
5514 result = dialog.get_action ();
5520 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5522 AmbiguousFileDialog dialog (file, hits);
5529 return dialog.get_which ();
5532 /** Allocate our thread-local buffers */
5534 ARDOUR_UI::get_process_buffers ()
5536 _process_thread->get_buffers ();
5539 /** Drop our thread-local buffers */
5541 ARDOUR_UI::drop_process_buffers ()
5543 _process_thread->drop_buffers ();
5547 ARDOUR_UI::feedback_detected ()
5549 _feedback_exists = true;
5553 ARDOUR_UI::successful_graph_sort ()
5555 _feedback_exists = false;
5559 ARDOUR_UI::midi_panic ()
5562 _session->midi_panic();
5567 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5569 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5570 const char* end_big = "</span>";
5571 const char* start_mono = "<tt>";
5572 const char* end_mono = "</tt>";
5574 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5575 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5576 "From now on, use the backup copy with older versions of %3"),
5577 xml_path, backup_path, PROGRAM_NAME,
5579 start_mono, end_mono), true);
5585 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5587 using namespace Menu_Helpers;
5589 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5590 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5591 i->set_active (editor_meter->meter_type () == type);
5595 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5597 using namespace Gtk::Menu_Helpers;
5599 Gtk::Menu* m = manage (new Menu);
5600 MenuList& items = m->items ();
5602 RadioMenuItem::Group group;
5604 _suspend_editor_meter_callbacks = true;
5605 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5606 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5607 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5608 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5609 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5610 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5611 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5612 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5613 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5614 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5615 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5617 m->popup (ev->button, ev->time);
5618 _suspend_editor_meter_callbacks = false;
5622 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5624 if (ev->button == 3 && editor_meter) {
5625 popup_editor_meter_menu (ev);
5632 ARDOUR_UI::reset_peak_display ()
5634 if (!_session || !_session->master_out() || !editor_meter) return;
5635 editor_meter->clear_meters();
5636 editor_meter_max_peak = -INFINITY;
5637 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5641 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5643 if (!_session || !_session->master_out()) return;
5644 if (group == _session->master_out()->route_group()) {
5645 reset_peak_display ();
5650 ARDOUR_UI::reset_route_peak_display (Route* route)
5652 if (!_session || !_session->master_out()) return;
5653 if (_session->master_out().get() == route) {
5654 reset_peak_display ();
5659 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5661 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5662 audio_midi_setup->set_position (WIN_POS_CENTER);
5664 if (desired_sample_rate != 0) {
5665 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5666 audio_midi_setup->try_autostart ();
5667 if (ARDOUR::AudioEngine::instance()->running()) {
5674 int response = audio_midi_setup->run();
5676 case Gtk::RESPONSE_DELETE_EVENT:
5677 // after latency callibration engine may run,
5678 // Running() signal was emitted, but dialog will not
5679 // have emitted a response. The user needs to close
5680 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5681 if (!AudioEngine::instance()->running()) {
5686 if (!AudioEngine::instance()->running()) {
5689 audio_midi_setup->hide ();
5697 ARDOUR_UI::transport_numpad_timeout ()
5699 _numpad_locate_happening = false;
5700 if (_numpad_timeout_connection.connected() )
5701 _numpad_timeout_connection.disconnect();
5706 ARDOUR_UI::transport_numpad_decimal ()
5708 _numpad_timeout_connection.disconnect();
5710 if (_numpad_locate_happening) {
5711 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5712 _numpad_locate_happening = false;
5714 _pending_locate_num = 0;
5715 _numpad_locate_happening = true;
5716 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5721 ARDOUR_UI::transport_numpad_event (int num)
5723 if ( _numpad_locate_happening ) {
5724 _pending_locate_num = _pending_locate_num*10 + num;
5727 case 0: toggle_roll(false, false); break;
5728 case 1: transport_rewind(1); break;
5729 case 2: transport_forward(1); break;
5730 case 3: transport_record(true); break;
5731 case 4: toggle_session_auto_loop(); break;
5732 case 5: transport_record(false); toggle_session_auto_loop(); break;
5733 case 6: toggle_punch(); break;
5734 case 7: toggle_click(); break;
5735 case 8: toggle_auto_return(); break;
5736 case 9: toggle_follow_edits(); break;
5742 ARDOUR_UI::set_flat_buttons ()
5744 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5748 ARDOUR_UI::audioengine_became_silent ()
5750 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5752 Gtk::MESSAGE_WARNING,
5756 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5758 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5759 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5760 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5761 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5762 Gtk::HBox pay_button_box;
5763 Gtk::HBox subscribe_button_box;
5765 pay_button_box.pack_start (pay_button, true, false);
5766 subscribe_button_box.pack_start (subscribe_button, true, false);
5768 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 */
5770 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5771 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5773 msg.get_vbox()->pack_start (pay_label);
5774 msg.get_vbox()->pack_start (pay_button_box);
5775 msg.get_vbox()->pack_start (subscribe_label);
5776 msg.get_vbox()->pack_start (subscribe_button_box);
5778 msg.get_vbox()->show_all ();
5780 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5781 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5782 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5787 case Gtk::RESPONSE_YES:
5788 AudioEngine::instance()->reset_silence_countdown ();
5791 case Gtk::RESPONSE_NO:
5793 save_state_canfail ("");
5797 case Gtk::RESPONSE_CANCEL:
5799 /* don't reset, save session and exit */
5805 ARDOUR_UI::hide_application ()
5807 Application::instance ()-> hide ();
5811 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5813 /* icons, titles, WM stuff */
5815 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5817 if (window_icons.empty()) {
5818 Glib::RefPtr<Gdk::Pixbuf> icon;
5819 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5820 window_icons.push_back (icon);
5822 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5823 window_icons.push_back (icon);
5825 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5826 window_icons.push_back (icon);
5828 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5829 window_icons.push_back (icon);
5833 if (!window_icons.empty()) {
5834 window.set_default_icon_list (window_icons);
5837 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5839 if (!name.empty()) {
5843 window.set_title (title.get_string());
5844 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5846 window.set_flags (CAN_FOCUS);
5847 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5849 /* This is a hack to ensure that GTK-accelerators continue to
5850 * work. Once we switch over to entirely native bindings, this will be
5851 * unnecessary and should be removed
5853 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5855 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5856 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5857 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5858 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5862 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5864 Gtkmm2ext::Bindings* bindings = 0;
5865 Gtk::Window* window = 0;
5867 /* until we get ardour bindings working, we are not handling key
5871 if (ev->type != GDK_KEY_PRESS) {
5875 if (event_window == &_main_window) {
5877 window = event_window;
5879 /* find current tab contents */
5881 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5883 /* see if it uses the ardour binding system */
5886 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5889 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5893 window = event_window;
5895 /* see if window uses ardour binding system */
5897 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5900 /* An empty binding set is treated as if it doesn't exist */
5902 if (bindings && bindings->empty()) {
5906 return key_press_focus_accelerator_handler (*window, ev, bindings);
5909 static Gtkmm2ext::Bindings*
5910 get_bindings_from_widget_heirarchy (GtkWidget** w)
5915 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5918 *w = gtk_widget_get_parent (*w);
5921 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5925 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5927 GtkWindow* win = window.gobj();
5928 GtkWidget* focus = gtk_window_get_focus (win);
5929 GtkWidget* binding_widget = focus;
5930 bool special_handling_of_unmodified_accelerators = false;
5931 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5935 /* some widget has keyboard focus */
5937 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5939 /* A particular kind of focusable widget currently has keyboard
5940 * focus. All unmodified key events should go to that widget
5941 * first and not be used as an accelerator by default
5944 special_handling_of_unmodified_accelerators = true;
5948 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5949 if (focus_bindings) {
5950 bindings = focus_bindings;
5951 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5956 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",
5959 Gtkmm2ext::show_gdk_event_state (ev->state),
5960 special_handling_of_unmodified_accelerators,
5961 Keyboard::some_magic_widget_has_focus(),
5963 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5964 ((ev->state & mask) ? "yes" : "no"),
5965 window.get_title()));
5967 /* This exists to allow us to override the way GTK handles
5968 key events. The normal sequence is:
5970 a) event is delivered to a GtkWindow
5971 b) accelerators/mnemonics are activated
5972 c) if (b) didn't handle the event, propagate to
5973 the focus widget and/or focus chain
5975 The problem with this is that if the accelerators include
5976 keys without modifiers, such as the space bar or the
5977 letter "e", then pressing the key while typing into
5978 a text entry widget results in the accelerator being
5979 activated, instead of the desired letter appearing
5982 There is no good way of fixing this, but this
5983 represents a compromise. The idea is that
5984 key events involving modifiers (not Shift)
5985 get routed into the activation pathway first, then
5986 get propagated to the focus widget if necessary.
5988 If the key event doesn't involve modifiers,
5989 we deliver to the focus widget first, thus allowing
5990 it to get "normal text" without interference
5993 Of course, this can also be problematic: if there
5994 is a widget with focus, then it will swallow
5995 all "normal text" accelerators.
5999 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
6001 /* no special handling or there are modifiers in effect: accelerate first */
6003 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
6004 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
6005 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
6007 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
6008 KeyboardKey k (ev->state, ev->keyval);
6012 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
6014 if (bindings->activate (k, Bindings::Press)) {
6015 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6019 if (binding_widget) {
6020 binding_widget = gtk_widget_get_parent (binding_widget);
6021 if (binding_widget) {
6022 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
6031 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
6033 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
6034 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6038 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
6040 if (gtk_window_propagate_key_event (win, ev)) {
6041 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
6047 /* no modifiers, propagate first */
6049 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
6051 if (gtk_window_propagate_key_event (win, ev)) {
6052 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
6056 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
6057 KeyboardKey k (ev->state, ev->keyval);
6061 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
6064 if (bindings->activate (k, Bindings::Press)) {
6065 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6069 if (binding_widget) {
6070 binding_widget = gtk_widget_get_parent (binding_widget);
6071 if (binding_widget) {
6072 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
6081 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
6083 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
6084 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6089 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
6094 ARDOUR_UI::load_bindings ()
6096 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
6097 error << _("Global keybindings are missing") << endmsg;
6102 ARDOUR_UI::cancel_solo ()
6105 _session->cancel_all_solo ();
6110 ARDOUR_UI::reset_focus (Gtk::Widget* w)
6112 /* this resets focus to the first focusable parent of the given widget,
6113 * or, if there is no focusable parent, cancels focus in the toplevel
6114 * window that the given widget is packed into (if there is one).
6121 Gtk::Widget* top = w->get_toplevel();
6123 if (!top || !top->is_toplevel()) {
6127 w = w->get_parent ();
6131 if (w->is_toplevel()) {
6132 /* Setting the focus widget to a Gtk::Window causes all
6133 * subsequent calls to ::has_focus() on the nominal
6134 * focus widget in that window to return
6135 * false. Workaround: never set focus to the toplevel
6141 if (w->get_can_focus ()) {
6142 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
6143 win->set_focus (*w);
6146 w = w->get_parent ();
6149 if (top == &_main_window) {
6153 /* no focusable parent found, cancel focus in top level window.
6154 C++ API cannot be used for this. Thanks, references.
6157 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);