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/disk_reader.h"
90 #include "ardour/disk_writer.h"
91 #include "ardour/filename_extensions.h"
92 #include "ardour/filesystem_paths.h"
93 #include "ardour/ltc_file_reader.h"
94 #include "ardour/midi_track.h"
95 #include "ardour/port.h"
96 #include "ardour/plugin_manager.h"
97 #include "ardour/process_thread.h"
98 #include "ardour/profile.h"
99 #include "ardour/recent_sessions.h"
100 #include "ardour/record_enable_control.h"
101 #include "ardour/revision.h"
102 #include "ardour/session_directory.h"
103 #include "ardour/session_route.h"
104 #include "ardour/session_state_utils.h"
105 #include "ardour/session_utils.h"
106 #include "ardour/source_factory.h"
107 #include "ardour/slave.h"
108 #include "ardour/system_exec.h"
109 #include "ardour/track.h"
110 #include "ardour/vca_manager.h"
111 #include "ardour/utils.h"
113 #include "LuaBridge/LuaBridge.h"
115 #ifdef WINDOWS_VST_SUPPORT
118 #ifdef AUDIOUNIT_SUPPORT
119 #include "ardour/audio_unit.h"
122 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
127 #include "timecode/time.h"
129 typedef uint64_t microseconds_t;
133 #include "enums_convert.h"
135 #include "add_route_dialog.h"
136 #include "ambiguous_file_dialog.h"
137 #include "ardour_ui.h"
138 #include "audio_clock.h"
139 #include "audio_region_view.h"
140 #include "big_clock_window.h"
141 #include "bundle_manager.h"
142 #include "duplicate_routes_dialog.h"
144 #include "engine_dialog.h"
145 #include "export_video_dialog.h"
146 #include "export_video_infobox.h"
147 #include "gain_meter.h"
148 #include "global_port_matrix.h"
149 #include "gui_object.h"
150 #include "gui_thread.h"
151 #include "idleometer.h"
152 #include "keyboard.h"
153 #include "keyeditor.h"
154 #include "location_ui.h"
155 #include "lua_script_manager.h"
156 #include "luawindow.h"
157 #include "main_clock.h"
158 #include "missing_file_dialog.h"
159 #include "missing_plugin_dialog.h"
160 #include "mixer_ui.h"
161 #include "meterbridge.h"
162 #include "meter_patterns.h"
163 #include "mouse_cursors.h"
166 #include "pingback.h"
167 #include "processor_box.h"
168 #include "public_editor.h"
169 #include "rc_option_editor.h"
170 #include "route_time_axis.h"
171 #include "route_params_ui.h"
172 #include "save_as_dialog.h"
173 #include "save_template_dialog.h"
174 #include "script_selector.h"
175 #include "session_archive_dialog.h"
176 #include "session_dialog.h"
177 #include "session_metadata_dialog.h"
178 #include "session_option_editor.h"
179 #include "speaker_dialog.h"
182 #include "template_dialog.h"
183 #include "time_axis_view_item.h"
184 #include "time_info_box.h"
187 #include "utils_videotl.h"
188 #include "video_server_dialog.h"
189 #include "add_video_dialog.h"
190 #include "transcode_video_dialog.h"
192 #include "pbd/i18n.h"
194 using namespace ARDOUR;
195 using namespace ARDOUR_UI_UTILS;
197 using namespace Gtkmm2ext;
198 using namespace ArdourWidgets;
201 using namespace Editing;
203 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
205 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
206 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
209 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
211 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
212 "Would you like these files to be copied and used for %1 %2.x?\n\n"
213 "(This will require you to restart %1.)"),
214 PROGRAM_NAME, PROGRAM_VERSION, version),
215 false, /* no markup */
218 true /* modal, though it hardly matters since it is the only window */
221 msg.set_default_response (Gtk::RESPONSE_YES);
224 return (msg.run() == Gtk::RESPONSE_YES);
228 libxml_generic_error_func (void* /* parsing_context*/,
236 vsnprintf (buf, sizeof (buf), msg, ap);
237 error << buf << endmsg;
242 libxml_structured_error_func (void* /* parsing_context*/,
250 replace_all (msg, "\n", "");
253 if (err->file && err->line) {
254 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
257 error << ':' << err->int2;
262 error << X_("XML error: ") << msg << endmsg;
268 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
269 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
270 , session_loaded (false)
271 , session_load_in_progress (false)
272 , gui_object_state (new GUIObjectState)
273 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
274 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
275 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
277 , global_actions (X_("global"))
278 , ignore_dual_punch (false)
279 , main_window_visibility (0)
284 , _mixer_on_top (false)
285 , _initial_verbose_plugin_scan (false)
286 , first_time_engine_run (true)
287 , secondary_clock_spacer (0)
288 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
289 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
290 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
291 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
292 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
293 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
294 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
295 , auto_input_button (ArdourButton::led_default_elements)
297 , auto_return_button (ArdourButton::led_default_elements)
298 , follow_edits_button (ArdourButton::led_default_elements)
299 , auditioning_alert_button (_("Audition"))
300 , solo_alert_button (_("Solo"))
301 , feedback_alert_button (_("Feedback"))
302 , error_alert_button ( ArdourButton::just_led_default_elements )
303 , editor_meter_peak_display()
305 , _suspend_editor_meter_callbacks (false)
306 , _numpad_locate_happening (false)
307 , _session_is_new (false)
308 , last_key_press_time (0)
312 , rc_option_editor (0)
313 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
314 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
315 , about (X_("about"), _("About"))
316 , location_ui (X_("locations"), S_("Ranges|Locations"))
317 , route_params (X_("inspector"), _("Tracks and Busses"))
318 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
319 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
320 , lua_script_window (X_("script-manager"), _("Script Manager"))
321 , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
322 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
323 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
324 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
325 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
326 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
327 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
328 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
329 , video_server_process (0)
331 , have_configure_timeout (false)
332 , last_configure_time (0)
334 , have_disk_speed_dialog_displayed (false)
335 , _status_bar_visibility (X_("status-bar"))
336 , _feedback_exists (false)
337 , _log_not_acknowledged (LogLevelNone)
338 , duplicate_routes_dialog (0)
339 , editor_visibility_button (S_("Window|Editor"))
340 , mixer_visibility_button (S_("Window|Mixer"))
341 , prefs_visibility_button (S_("Window|Preferences"))
343 Gtkmm2ext::init (localedir);
345 UIConfiguration::instance().post_gui_init ();
347 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
349 /* "touch" the been-here-before path now that config has been migrated */
350 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
352 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
354 /* configuration was modified, exit immediately */
359 if (string (VERSIONSTRING).find (".pre") != string::npos) {
360 /* check this is not being run from ./ardev etc. */
361 if (!running_from_source_tree ()) {
362 pre_release_dialog ();
366 if (theArdourUI == 0) {
370 /* track main window visibility */
372 main_window_visibility = new VisibilityTracker (_main_window);
374 /* stop libxml from spewing to stdout/stderr */
376 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
377 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
379 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
380 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
381 UIConfiguration::instance().map_parameters (pc);
383 roll_button.set_controllable (roll_controllable);
384 stop_button.set_controllable (stop_controllable);
385 goto_start_button.set_controllable (goto_start_controllable);
386 goto_end_button.set_controllable (goto_end_controllable);
387 auto_loop_button.set_controllable (auto_loop_controllable);
388 play_selection_button.set_controllable (play_selection_controllable);
389 rec_button.set_controllable (rec_controllable);
391 roll_button.set_name ("transport button");
392 stop_button.set_name ("transport button");
393 goto_start_button.set_name ("transport button");
394 goto_end_button.set_name ("transport button");
395 auto_loop_button.set_name ("transport button");
396 play_selection_button.set_name ("transport button");
397 rec_button.set_name ("transport recenable button");
398 midi_panic_button.set_name ("transport button");
400 ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
401 ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
403 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
405 /* handle dialog requests */
407 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
409 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
411 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
413 /* handle Audio/MIDI setup when session requires it */
415 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
417 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
419 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
421 /* handle sr mismatch with a dialog - cross-thread from engine */
422 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
424 /* handle requests to quit (coming from JACK session) */
426 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
428 /* tell the user about feedback */
430 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
431 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
433 /* handle requests to deal with missing files */
435 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
437 /* and ambiguous files */
439 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
441 /* also plugin scan messages */
442 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
443 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
445 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
447 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
450 /* lets get this party started */
452 setup_gtk_ardour_enums ();
455 SessionEvent::create_per_thread_pool ("GUI", 4096);
457 /* we like keyboards */
459 keyboard = new ArdourKeyboard(*this);
461 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
463 keyboard->set_state (*node, Stateful::loading_state_version);
466 UIConfiguration::instance().reset_dpi ();
468 TimeAxisViewItem::set_constant_heights ();
470 /* Set this up so that our window proxies can register actions */
472 ActionManager::init ();
474 /* The following must happen after ARDOUR::init() so that Config is set up */
476 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
479 key_editor.set_state (*ui_xml, 0);
480 session_option_editor.set_state (*ui_xml, 0);
481 speaker_config_window.set_state (*ui_xml, 0);
482 about.set_state (*ui_xml, 0);
483 add_route_dialog.set_state (*ui_xml, 0);
484 add_video_dialog.set_state (*ui_xml, 0);
485 route_params.set_state (*ui_xml, 0);
486 bundle_manager.set_state (*ui_xml, 0);
487 location_ui.set_state (*ui_xml, 0);
488 big_clock_window.set_state (*ui_xml, 0);
489 audio_port_matrix.set_state (*ui_xml, 0);
490 midi_port_matrix.set_state (*ui_xml, 0);
491 export_video_dialog.set_state (*ui_xml, 0);
492 lua_script_window.set_state (*ui_xml, 0);
493 idleometer.set_state (*ui_xml, 0);
496 /* Separate windows */
498 WM::Manager::instance().register_window (&key_editor);
499 WM::Manager::instance().register_window (&session_option_editor);
500 WM::Manager::instance().register_window (&speaker_config_window);
501 WM::Manager::instance().register_window (&about);
502 WM::Manager::instance().register_window (&add_route_dialog);
503 WM::Manager::instance().register_window (&add_video_dialog);
504 WM::Manager::instance().register_window (&route_params);
505 WM::Manager::instance().register_window (&audio_midi_setup);
506 WM::Manager::instance().register_window (&export_video_dialog);
507 WM::Manager::instance().register_window (&lua_script_window);
508 WM::Manager::instance().register_window (&bundle_manager);
509 WM::Manager::instance().register_window (&location_ui);
510 WM::Manager::instance().register_window (&big_clock_window);
511 WM::Manager::instance().register_window (&audio_port_matrix);
512 WM::Manager::instance().register_window (&midi_port_matrix);
513 WM::Manager::instance().register_window (&idleometer);
515 /* do not retain position for add route dialog */
516 add_route_dialog.set_state_mask (WindowProxy::Size);
518 /* Trigger setting up the color scheme and loading the GTK RC file */
520 UIConfiguration::instance().load_rc_file (false);
522 _process_thread = new ProcessThread ();
523 _process_thread->init ();
525 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
531 ARDOUR_UI::pre_release_dialog ()
533 ArdourDialog d (_("Pre-Release Warning"), true, false);
534 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
536 Label* label = manage (new Label);
537 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
538 There are still several issues and bugs to be worked on,\n\
539 as well as general workflow improvements, before this can be considered\n\
540 release software. So, a few guidelines:\n\
542 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
543 though it may be so, depending on your workflow.\n\
544 2) Please wait for a helpful writeup of new features.\n\
545 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
546 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
547 making sure to note the product version number as 5.0-pre.\n\
548 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
549 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
550 can get there directly from within the program via the Help->Chat menu option.\n\
552 Full information on all the above can be found on the support page at\n\
554 http://ardour.org/support\n\
555 "), PROGRAM_NAME, VERSIONSTRING));
557 d.get_vbox()->set_border_width (12);
558 d.get_vbox()->pack_start (*label, false, false, 12);
559 d.get_vbox()->show_all ();
564 GlobalPortMatrixWindow*
565 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
570 return new GlobalPortMatrixWindow (_session, type);
574 ARDOUR_UI::attach_to_engine ()
576 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
577 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
581 ARDOUR_UI::engine_stopped ()
583 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
584 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
585 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
586 update_sample_rate (0);
591 ARDOUR_UI::engine_running ()
593 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
594 if (first_time_engine_run) {
596 first_time_engine_run = false;
600 _session->reset_xrun_count ();
602 update_disk_space ();
604 update_xrun_count ();
605 update_sample_rate (AudioEngine::instance()->sample_rate());
606 update_timecode_format ();
607 update_peak_thread_work ();
608 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
609 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
613 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
615 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
616 /* we can't rely on the original string continuing to exist when we are called
617 again in the GUI thread, so make a copy and note that we need to
620 char *copy = strdup (reason);
621 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
625 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
626 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
628 update_sample_rate (0);
632 /* if the reason is a non-empty string, it means that the backend was shutdown
633 rather than just Ardour.
636 if (strlen (reason)) {
637 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
639 msgstr = string_compose (_("\
640 The audio backend has either been shutdown or it\n\
641 disconnected %1 because %1\n\
642 was not fast enough. Try to restart\n\
643 the audio backend and save the session."), PROGRAM_NAME);
646 MessageDialog msg (_main_window, msgstr);
647 pop_back_splash (msg);
651 free (const_cast<char*> (reason));
656 ARDOUR_UI::post_engine ()
658 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
660 #ifdef AUDIOUNIT_SUPPORT
662 if (AUPluginInfo::au_get_crashlog(au_msg)) {
663 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
664 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
665 info << au_msg << endmsg;
669 ARDOUR::init_post_engine ();
671 /* connect to important signals */
673 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
674 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
675 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
676 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
677 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
679 if (setup_windows ()) {
680 throw failed_constructor ();
683 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
684 XMLNode* n = Config->extra_xml (X_("UI"));
686 _status_bar_visibility.set_state (*n);
689 check_memory_locking();
691 /* this is the first point at which all the possible actions are
692 * available, because some of the available actions are dependent on
693 * aspects of the engine/backend.
696 if (ARDOUR_COMMAND_LINE::show_key_actions) {
698 Bindings::save_all_bindings_as_html (sstr);
700 if (sstr.str().empty()) {
707 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
709 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
715 #ifdef PLATFORM_WINDOWS
721 if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
722 #ifndef PLATFORM_WINDOWS
725 g_unlink (file_name);
727 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
733 #ifndef PLATFORM_WINDOWS
737 PBD::open_uri (string_compose ("file:///%1", file_name));
739 halt_connection.disconnect ();
740 AudioEngine::instance()->stop ();
745 if (ARDOUR_COMMAND_LINE::show_actions) {
748 vector<string> paths;
749 vector<string> labels;
750 vector<string> tooltips;
752 vector<Glib::RefPtr<Gtk::Action> > actions;
753 string ver_in = revision;
754 string ver = ver_in.substr(0, ver_in.find("-"));
757 output << "\n<h2>Menu actions</h2>" << endl;
758 output << "<p>\n Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
759 output << " surfaces or scripts.\n</p>\n" << endl;
760 output << "<p>\n The list below shows all available values of <em>action-name</em> as of" << endl;
761 output << " " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
762 output << " time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
763 output << "<table class=\"dl\">\n <thead>" << endl;
764 output << " <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
765 output << " </thead>\n <tbody>" << endl;
767 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
769 vector<string>::iterator p;
770 vector<string>::iterator l;
772 for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
773 output << " <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
774 output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
776 output << " </tbody>\n </table>" << endl;
778 // output this mess to a browser for easiest X-platform use
779 // it is not pretty HTML, but it works and it's main purpose
780 // is to create raw html to fit in Ardour's manual with no editing
785 if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
787 error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
793 #ifdef PLATFORM_WINDOWS
799 if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
800 #ifndef PLATFORM_WINDOWS
803 g_unlink (file_name);
805 error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
811 #ifndef PLATFORM_WINDOWS
815 PBD::open_uri (string_compose ("file:///%1", file_name));
817 halt_connection.disconnect ();
818 AudioEngine::instance()->stop ();
822 /* this being a GUI and all, we want peakfiles */
824 AudioFileSource::set_build_peakfiles (true);
825 AudioFileSource::set_build_missing_peakfiles (true);
827 /* set default clock modes */
829 primary_clock->set_mode (AudioClock::Timecode);
830 secondary_clock->set_mode (AudioClock::BBT);
832 /* start the time-of-day-clock */
835 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
836 update_wall_clock ();
837 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
842 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
843 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
844 Config->map_parameters (pc);
846 UIConfiguration::instance().map_parameters (pc);
850 ARDOUR_UI::~ARDOUR_UI ()
852 UIConfiguration::instance().save_state();
856 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
857 // don't bother at 'real' exit. the OS cleans up for us.
858 delete big_clock; big_clock = 0;
859 delete primary_clock; primary_clock = 0;
860 delete secondary_clock; secondary_clock = 0;
861 delete _process_thread; _process_thread = 0;
862 delete time_info_box; time_info_box = 0;
863 delete meterbridge; meterbridge = 0;
864 delete luawindow; luawindow = 0;
865 delete editor; editor = 0;
866 delete mixer; mixer = 0;
867 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
869 delete gui_object_state; gui_object_state = 0;
870 delete main_window_visibility;
871 FastMeter::flush_pattern_cache ();
872 ArdourFader::flush_pattern_cache ();
876 /* Small trick to flush main-thread event pool.
877 * Other thread-pools are destroyed at pthread_exit(),
878 * but tmain thread termination is too late to trigger Pool::~Pool()
880 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.
881 delete ev->event_pool();
886 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
888 if (Splash::instance()) {
889 Splash::instance()->pop_back_for (win);
894 ARDOUR_UI::configure_timeout ()
896 if (last_configure_time == 0) {
897 /* no configure events yet */
901 /* force a gap of 0.5 seconds since the last configure event
904 if (get_microseconds() - last_configure_time < 500000) {
907 have_configure_timeout = false;
908 save_ardour_state ();
914 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
916 if (have_configure_timeout) {
917 last_configure_time = get_microseconds();
919 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
920 have_configure_timeout = true;
927 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
931 if (node.get_property ("roll", str)){
932 roll_controllable->set_id (str);
934 if (node.get_property ("stop", str)) {
935 stop_controllable->set_id (str);
937 if (node.get_property ("goto-start", str)) {
938 goto_start_controllable->set_id (str);
940 if (node.get_property ("goto-end", str)) {
941 goto_end_controllable->set_id (str);
943 if (node.get_property ("auto-loop", str)) {
944 auto_loop_controllable->set_id (str);
946 if (node.get_property ("play-selection", str)) {
947 play_selection_controllable->set_id (str);
949 if (node.get_property ("rec", str)) {
950 rec_controllable->set_id (str);
952 if (node.get_property ("shuttle", str)) {
953 shuttle_box.controllable()->set_id (str);
958 ARDOUR_UI::get_transport_controllable_state ()
960 XMLNode* node = new XMLNode(X_("TransportControllables"));
962 node->set_property (X_("roll"), roll_controllable->id());
963 node->set_property (X_("stop"), stop_controllable->id());
964 node->set_property (X_("goto-start"), goto_start_controllable->id());
965 node->set_property (X_("goto-end"), goto_end_controllable->id());
966 node->set_property (X_("auto-loop"), auto_loop_controllable->id());
967 node->set_property (X_("play-selection"), play_selection_controllable->id());
968 node->set_property (X_("rec"), rec_controllable->id());
969 node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
975 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
978 _session->save_state (snapshot_name);
983 ARDOUR_UI::autosave_session ()
985 if (g_main_depth() > 1) {
986 /* inside a recursive main loop,
987 give up because we may not be able to
993 if (!Config->get_periodic_safety_backups()) {
998 _session->maybe_write_autosave();
1005 ARDOUR_UI::session_dirty_changed ()
1012 ARDOUR_UI::update_autosave ()
1014 if (_session && _session->dirty()) {
1015 if (_autosave_connection.connected()) {
1016 _autosave_connection.disconnect();
1019 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
1020 Config->get_periodic_safety_backup_interval() * 1000);
1023 if (_autosave_connection.connected()) {
1024 _autosave_connection.disconnect();
1030 ARDOUR_UI::check_announcements ()
1033 string _annc_filename;
1036 _annc_filename = PROGRAM_NAME "_announcements_osx_";
1037 #elif defined PLATFORM_WINDOWS
1038 _annc_filename = PROGRAM_NAME "_announcements_windows_";
1040 _annc_filename = PROGRAM_NAME "_announcements_linux_";
1042 _annc_filename.append (VERSIONSTRING);
1044 _announce_string = "";
1046 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
1047 FILE* fin = g_fopen (path.c_str(), "rb");
1049 while (!feof (fin)) {
1052 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
1055 _announce_string.append (tmp, len);
1060 pingback (VERSIONSTRING, path);
1065 _hide_splash (gpointer arg)
1067 ((ARDOUR_UI*)arg)->hide_splash();
1072 ARDOUR_UI::starting ()
1074 Application* app = Application::instance ();
1075 const char *nsm_url;
1076 bool brand_new_user = ArdourStartup::required ();
1078 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
1079 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
1081 if (ARDOUR_COMMAND_LINE::check_announcements) {
1082 check_announcements ();
1087 /* we need to create this early because it may need to set the
1088 * audio backend end up.
1092 audio_midi_setup.get (true);
1094 std::cerr << "audio-midi engine setup failed."<< std::endl;
1098 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
1099 nsm = new NSM_Client;
1100 if (!nsm->init (nsm_url)) {
1101 /* the ardour executable may have different names:
1103 * waf's obj.target for distro versions: eg ardour4, ardourvst4
1104 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
1105 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
1107 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1109 const char *process_name = g_getenv ("ARDOUR_SELF");
1110 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1113 // wait for announce reply from nsm server
1114 for ( i = 0; i < 5000; ++i) {
1118 if (nsm->is_active()) {
1123 error << _("NSM server did not announce itself") << endmsg;
1126 // wait for open command from nsm server
1127 for ( i = 0; i < 5000; ++i) {
1129 Glib::usleep (1000);
1130 if (nsm->client_id ()) {
1136 error << _("NSM: no client ID provided") << endmsg;
1140 if (_session && nsm) {
1141 _session->set_nsm_state( nsm->is_active() );
1143 error << _("NSM: no session created") << endmsg;
1147 // nsm requires these actions disabled
1148 vector<string> action_names;
1149 action_names.push_back("SaveAs");
1150 action_names.push_back("Rename");
1151 action_names.push_back("New");
1152 action_names.push_back("Open");
1153 action_names.push_back("Recent");
1154 action_names.push_back("Close");
1156 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1157 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1159 act->set_sensitive (false);
1166 error << _("NSM: initialization failed") << endmsg;
1172 if (brand_new_user) {
1173 _initial_verbose_plugin_scan = true;
1178 _initial_verbose_plugin_scan = false;
1179 switch (s.response ()) {
1180 case Gtk::RESPONSE_OK:
1187 // TODO: maybe IFF brand_new_user
1188 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1189 std::string dspd (Config->get_default_session_parent_dir());
1190 Searchpath ds (ARDOUR::ardour_data_search_path());
1191 ds.add_subdirectory_to_paths ("sessions");
1192 vector<string> demos;
1193 find_files_matching_pattern (demos, ds, "*.tar.xz");
1195 ARDOUR::RecentSessions rs;
1196 ARDOUR::read_recent_sessions (rs);
1198 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1199 /* "demo-session" must be inside "demo-session.tar.xz"
1202 std::string name = basename_nosuffix (basename_nosuffix (*i));
1203 std::string path = Glib::build_filename (dspd, name);
1204 /* skip if session-dir already exists */
1205 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1208 /* skip sessions that are already in 'recent'.
1209 * eg. a new user changed <session-default-dir> shorly after installation
1211 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1212 if ((*r).first == name) {
1217 PBD::FileArchive ar (*i);
1218 if (0 == ar.inflate (dspd)) {
1219 store_recent_sessions (name, path);
1220 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1226 #ifdef NO_PLUGIN_STATE
1228 ARDOUR::RecentSessions rs;
1229 ARDOUR::read_recent_sessions (rs);
1231 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1233 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1235 /* already used Ardour, have sessions ... warn about plugin state */
1237 ArdourDialog d (_("Free/Demo Version Warning"), true);
1239 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1240 CheckButton c (_("Don't warn me about this again"));
1242 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"),
1243 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1244 _("It will not restore OR save any plugin settings"),
1245 _("If you load an existing session with plugin settings\n"
1246 "they will not be used and will be lost."),
1247 _("To get full access to updates without this limitation\n"
1248 "consider becoming a subscriber for a low cost every month.")));
1249 l.set_justify (JUSTIFY_CENTER);
1251 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1253 d.get_vbox()->pack_start (l, true, true);
1254 d.get_vbox()->pack_start (b, false, false, 12);
1255 d.get_vbox()->pack_start (c, false, false, 12);
1257 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1258 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1262 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1264 if (d.run () != RESPONSE_OK) {
1270 /* go get a session */
1272 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1274 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1275 std::cerr << "Cannot get session parameters."<< std::endl;
1282 WM::Manager::instance().show_visible ();
1284 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1285 * editor window, and we may want stuff to be hidden.
1287 _status_bar_visibility.update ();
1289 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1291 /* all other dialogs are created conditionally */
1297 ARDOUR_UI::check_memory_locking ()
1299 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1300 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1304 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1306 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1308 struct rlimit limits;
1310 long pages, page_size;
1312 size_t pages_len=sizeof(pages);
1313 if ((page_size = getpagesize()) < 0 ||
1314 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1316 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1321 ram = (int64_t) pages * (int64_t) page_size;
1324 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1328 if (limits.rlim_cur != RLIM_INFINITY) {
1330 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1334 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1335 "This might cause %1 to run out of memory before your system "
1336 "runs out of memory. \n\n"
1337 "You can view the memory limit with 'ulimit -l', "
1338 "and it is normally controlled by %2"),
1341 X_("/etc/login.conf")
1343 X_(" /etc/security/limits.conf")
1347 msg.set_default_response (RESPONSE_OK);
1349 VBox* vbox = msg.get_vbox();
1351 CheckButton cb (_("Do not show this window again"));
1352 hbox.pack_start (cb, true, false);
1353 vbox->pack_start (hbox);
1358 pop_back_splash (msg);
1362 if (cb.get_active()) {
1363 XMLNode node (X_("no-memory-warning"));
1364 Config->add_instant_xml (node);
1369 #endif // !__APPLE__
1374 ARDOUR_UI::queue_finish ()
1376 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1380 ARDOUR_UI::idle_finish ()
1383 return false; /* do not call again */
1390 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1392 if (_session->dirty()) {
1393 vector<string> actions;
1394 actions.push_back (_("Don't quit"));
1395 actions.push_back (_("Just quit"));
1396 actions.push_back (_("Save and quit"));
1397 switch (ask_about_saving_session(actions)) {
1402 /* use the default name */
1403 if (save_state_canfail ("")) {
1404 /* failed - don't quit */
1405 MessageDialog msg (_main_window,
1406 string_compose (_("\
1407 %1 was unable to save your session.\n\n\
1408 If you still wish to quit, please use the\n\n\
1409 \"Just quit\" option."), PROGRAM_NAME));
1410 pop_back_splash(msg);
1420 second_connection.disconnect ();
1421 point_one_second_connection.disconnect ();
1422 point_zero_something_second_connection.disconnect();
1423 fps_connection.disconnect();
1426 delete ARDOUR_UI::instance()->video_timeline;
1427 ARDOUR_UI::instance()->video_timeline = NULL;
1428 stop_video_server();
1430 /* Save state before deleting the session, as that causes some
1431 windows to be destroyed before their visible state can be
1434 save_ardour_state ();
1436 if (key_editor.get (false)) {
1437 key_editor->disconnect ();
1440 close_all_dialogs ();
1443 _session->set_clean ();
1444 _session->remove_pending_capture_state ();
1449 halt_connection.disconnect ();
1450 AudioEngine::instance()->stop ();
1451 #ifdef WINDOWS_VST_SUPPORT
1452 fst_stop_threading();
1458 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1460 ArdourDialog window (_("Unsaved Session"));
1461 Gtk::HBox dhbox; // the hbox for the image and text
1462 Gtk::Label prompt_label;
1463 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1467 assert (actions.size() >= 3);
1469 window.add_button (actions[0], RESPONSE_REJECT);
1470 window.add_button (actions[1], RESPONSE_APPLY);
1471 window.add_button (actions[2], RESPONSE_ACCEPT);
1473 window.set_default_response (RESPONSE_ACCEPT);
1475 Gtk::Button noquit_button (msg);
1476 noquit_button.set_name ("EditorGTKButton");
1480 if (_session->snap_name() == _session->name()) {
1481 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?"),
1482 _session->snap_name());
1484 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?"),
1485 _session->snap_name());
1488 prompt_label.set_text (prompt);
1489 prompt_label.set_name (X_("PrompterLabel"));
1490 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1492 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1493 dhbox.set_homogeneous (false);
1494 dhbox.pack_start (*dimage, false, false, 5);
1495 dhbox.pack_start (prompt_label, true, false, 5);
1496 window.get_vbox()->pack_start (dhbox);
1498 window.set_name (_("Prompter"));
1499 window.set_modal (true);
1500 window.set_resizable (false);
1503 prompt_label.show();
1508 ResponseType r = (ResponseType) window.run();
1513 case RESPONSE_ACCEPT: // save and get out of here
1515 case RESPONSE_APPLY: // get out of here
1526 ARDOUR_UI::every_second ()
1529 update_xrun_count ();
1530 update_buffer_load ();
1531 update_disk_space ();
1532 update_timecode_format ();
1533 update_peak_thread_work ();
1535 if (nsm && nsm->is_active ()) {
1538 if (!_was_dirty && _session->dirty ()) {
1542 else if (_was_dirty && !_session->dirty ()){
1550 ARDOUR_UI::every_point_one_seconds ()
1552 // TODO get rid of this..
1553 // ShuttleControl is updated directly via TransportStateChange signal
1557 ARDOUR_UI::every_point_zero_something_seconds ()
1559 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1561 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1562 float mpeak = editor_meter->update_meters();
1563 if (mpeak > editor_meter_max_peak) {
1564 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1565 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1572 ARDOUR_UI::set_fps_timeout_connection ()
1574 unsigned int interval = 40;
1575 if (!_session) return;
1576 if (_session->timecode_frames_per_second() != 0) {
1577 /* ideally we'll use a select() to sleep and not accumulate
1578 * idle time to provide a regular periodic signal.
1579 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1580 * However, that'll require a dedicated thread and cross-thread
1581 * signals to the GUI Thread..
1583 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1584 * _session->frame_rate() / _session->nominal_frame_rate()
1585 / _session->timecode_frames_per_second()
1587 #ifdef PLATFORM_WINDOWS
1588 // the smallest windows scheduler time-slice is ~15ms.
1589 // periodic GUI timeouts shorter than that will cause
1590 // WaitForSingleObject to spinlock (100% of one CPU Core)
1591 // and gtk never enters idle mode.
1592 // also changing timeBeginPeriod(1) does not affect that in
1593 // any beneficial way, so we just limit the max rate for now.
1594 interval = std::max(30u, interval); // at most ~33Hz.
1596 interval = std::max(8u, interval); // at most 120Hz.
1599 fps_connection.disconnect();
1600 Timers::set_fps_interval (interval);
1604 ARDOUR_UI::update_sample_rate (framecnt_t)
1608 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1610 if (!AudioEngine::instance()->connected()) {
1612 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1616 framecnt_t rate = AudioEngine::instance()->sample_rate();
1619 /* no sample rate available */
1620 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1623 if (fmod (rate, 1000.0) != 0.0) {
1624 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1625 (float) rate / 1000.0f,
1626 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1628 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1630 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1634 sample_rate_label.set_markup (buf);
1638 ARDOUR_UI::update_format ()
1641 format_label.set_text ("");
1646 s << _("File:") << X_(" <span foreground=\"green\">");
1648 switch (_session->config.get_native_file_header_format ()) {
1680 switch (_session->config.get_native_file_data_format ()) {
1694 format_label.set_markup (s.str ());
1698 ARDOUR_UI::update_xrun_count ()
1702 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1703 should also be changed.
1707 const unsigned int x = _session->get_xrun_count ();
1709 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1711 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1714 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1716 xrun_label.set_markup (buf);
1717 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1721 ARDOUR_UI::update_cpu_load ()
1725 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1726 should also be changed.
1729 double const c = AudioEngine::instance()->get_dsp_load ();
1730 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1731 cpu_load_label.set_markup (buf);
1735 ARDOUR_UI::update_peak_thread_work ()
1738 const int c = SourceFactory::peak_work_queue_length ();
1740 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1741 peak_thread_work_label.set_markup (buf);
1743 peak_thread_work_label.set_markup (X_(""));
1748 ARDOUR_UI::update_buffer_load ()
1752 uint32_t const playback = _session ? _session->playback_load () : 100;
1753 uint32_t const capture = _session ? _session->capture_load () : 100;
1755 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1756 should also be changed.
1762 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1763 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1764 playback <= 5 ? X_("red") : X_("green"),
1766 capture <= 5 ? X_("red") : X_("green"),
1770 buffer_load_label.set_markup (buf);
1772 buffer_load_label.set_text ("");
1777 ARDOUR_UI::count_recenabled_streams (Route& route)
1779 Track* track = dynamic_cast<Track*>(&route);
1780 if (track && track->rec_enable_control()->get_value()) {
1781 rec_enabled_streams += track->n_inputs().n_total();
1786 ARDOUR_UI::update_disk_space()
1788 if (_session == 0) {
1792 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1794 framecnt_t fr = _session->frame_rate();
1797 /* skip update - no SR available */
1802 /* Available space is unknown */
1803 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1804 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1805 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1807 rec_enabled_streams = 0;
1808 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1810 framecnt_t frames = opt_frames.get_value_or (0);
1812 if (rec_enabled_streams) {
1813 frames /= rec_enabled_streams;
1820 hrs = frames / (fr * 3600);
1823 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1825 frames -= hrs * fr * 3600;
1826 mins = frames / (fr * 60);
1827 frames -= mins * fr * 60;
1830 bool const low = (hrs == 0 && mins <= 30);
1834 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1835 low ? X_("red") : X_("green"),
1841 disk_space_label.set_markup (buf);
1845 ARDOUR_UI::update_timecode_format ()
1851 TimecodeSlave* tcslave;
1852 SyncSource sync_src = Config->get_sync_source();
1854 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1855 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1860 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1861 matching ? X_("green") : X_("red"),
1862 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1864 snprintf (buf, sizeof (buf), "TC: n/a");
1867 timecode_format_label.set_markup (buf);
1871 ARDOUR_UI::update_wall_clock ()
1875 static int last_min = -1;
1878 tm_now = localtime (&now);
1879 if (last_min != tm_now->tm_min) {
1881 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1882 wall_clock_label.set_text (buf);
1883 last_min = tm_now->tm_min;
1890 ARDOUR_UI::open_recent_session ()
1892 bool can_return = (_session != 0);
1894 SessionDialog recent_session_dialog;
1898 ResponseType r = (ResponseType) recent_session_dialog.run ();
1901 case RESPONSE_ACCEPT:
1905 recent_session_dialog.hide();
1912 recent_session_dialog.hide();
1916 std::string path = recent_session_dialog.session_folder();
1917 std::string state = recent_session_dialog.session_name (should_be_new);
1919 if (should_be_new == true) {
1923 _session_is_new = false;
1925 if (load_session (path, state) == 0) {
1934 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1936 if (!AudioEngine::instance()->connected()) {
1937 MessageDialog msg (parent, string_compose (
1938 _("%1 is not connected to any audio backend.\n"
1939 "You cannot open or close sessions in this condition"),
1941 pop_back_splash (msg);
1949 ARDOUR_UI::open_session ()
1951 if (!check_audioengine (_main_window)) {
1955 /* ardour sessions are folders */
1956 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1957 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1958 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1959 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1962 string session_parent_dir = Glib::path_get_dirname(_session->path());
1963 open_session_selector.set_current_folder(session_parent_dir);
1965 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1968 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1970 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1971 string default_session_folder = Config->get_default_session_parent_dir();
1972 open_session_selector.add_shortcut_folder (default_session_folder);
1974 catch (Glib::Error & e) {
1975 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1978 FileFilter session_filter;
1979 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1980 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1981 open_session_selector.add_filter (session_filter);
1983 FileFilter archive_filter;
1984 archive_filter.add_pattern (X_("*.tar.xz"));
1985 archive_filter.set_name (_("Session Archives"));
1987 open_session_selector.add_filter (archive_filter);
1989 open_session_selector.set_filter (session_filter);
1991 int response = open_session_selector.run();
1992 open_session_selector.hide ();
1994 if (response == Gtk::RESPONSE_CANCEL) {
1998 string session_path = open_session_selector.get_filename();
2002 if (session_path.length() > 0) {
2003 int rv = ARDOUR::inflate_session (session_path,
2004 Config->get_default_session_parent_dir(), path, name);
2006 _session_is_new = false;
2007 load_session (path, name);
2010 MessageDialog msg (_main_window,
2011 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
2014 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
2015 _session_is_new = isnew;
2016 load_session (path, name);
2022 ARDOUR_UI::session_add_mixed_track (
2023 const ChanCount& input,
2024 const ChanCount& output,
2025 RouteGroup* route_group,
2027 const string& name_template,
2029 PluginInfoPtr instrument,
2030 Plugin::PresetRecord* pset,
2031 ARDOUR::PresentationInfo::order_t order)
2035 if (Profile->get_mixbus ()) {
2040 list<boost::shared_ptr<MidiTrack> > tracks;
2041 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
2043 if (tracks.size() != how_many) {
2044 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
2049 display_insufficient_ports_message ();
2055 ARDOUR_UI::session_add_midi_bus (
2056 RouteGroup* route_group,
2058 const string& name_template,
2060 PluginInfoPtr instrument,
2061 Plugin::PresetRecord* pset,
2062 ARDOUR::PresentationInfo::order_t order)
2064 if (_session == 0) {
2065 warning << _("You cannot add a track without a session already loaded.") << endmsg;
2069 if (Profile->get_mixbus ()) {
2075 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
2076 if (routes.size() != how_many) {
2077 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
2082 display_insufficient_ports_message ();
2088 ARDOUR_UI::session_add_midi_route (
2090 RouteGroup* route_group,
2092 const string& name_template,
2094 PluginInfoPtr instrument,
2095 Plugin::PresetRecord* pset,
2096 ARDOUR::PresentationInfo::order_t order)
2098 ChanCount one_midi_channel;
2099 one_midi_channel.set (DataType::MIDI, 1);
2102 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2104 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2109 ARDOUR_UI::session_add_audio_route (
2111 int32_t input_channels,
2112 int32_t output_channels,
2113 ARDOUR::TrackMode mode,
2114 RouteGroup* route_group,
2116 string const & name_template,
2118 ARDOUR::PresentationInfo::order_t order)
2120 list<boost::shared_ptr<AudioTrack> > tracks;
2127 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2129 if (tracks.size() != how_many) {
2130 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2136 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2138 if (routes.size() != how_many) {
2139 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2146 display_insufficient_ports_message ();
2151 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2152 (*i)->set_strict_io (true);
2154 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2155 (*i)->set_strict_io (true);
2161 ARDOUR_UI::display_insufficient_ports_message ()
2163 MessageDialog msg (_main_window,
2164 string_compose (_("There are insufficient ports available\n\
2165 to create a new track or bus.\n\
2166 You should save %1, exit and\n\
2167 restart with more ports."), PROGRAM_NAME));
2168 pop_back_splash (msg);
2173 ARDOUR_UI::transport_goto_start ()
2176 _session->goto_start();
2178 /* force displayed area in editor to start no matter
2179 what "follow playhead" setting is.
2183 editor->center_screen (_session->current_start_frame ());
2189 ARDOUR_UI::transport_goto_zero ()
2192 _session->request_locate (0);
2194 /* force displayed area in editor to start no matter
2195 what "follow playhead" setting is.
2199 editor->reset_x_origin (0);
2205 ARDOUR_UI::transport_goto_wallclock ()
2207 if (_session && editor) {
2214 localtime_r (&now, &tmnow);
2216 framecnt_t frame_rate = _session->frame_rate();
2218 if (frame_rate == 0) {
2219 /* no frame rate available */
2223 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2224 frames += tmnow.tm_min * (60 * frame_rate);
2225 frames += tmnow.tm_sec * frame_rate;
2227 _session->request_locate (frames, _session->transport_rolling ());
2229 /* force displayed area in editor to start no matter
2230 what "follow playhead" setting is.
2234 editor->center_screen (frames);
2240 ARDOUR_UI::transport_goto_end ()
2243 framepos_t const frame = _session->current_end_frame();
2244 _session->request_locate (frame);
2246 /* force displayed area in editor to start no matter
2247 what "follow playhead" setting is.
2251 editor->center_screen (frame);
2257 ARDOUR_UI::transport_stop ()
2263 if (_session->is_auditioning()) {
2264 _session->cancel_audition ();
2268 _session->request_stop (false, true);
2271 /** Check if any tracks are record enabled. If none are, record enable all of them.
2272 * @return true if track record-enabled status was changed, false otherwise.
2275 ARDOUR_UI::trx_record_enable_all_tracks ()
2281 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2282 bool none_record_enabled = true;
2284 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2285 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2288 if (t->rec_enable_control()->get_value()) {
2289 none_record_enabled = false;
2294 if (none_record_enabled) {
2295 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2298 return none_record_enabled;
2302 ARDOUR_UI::transport_record (bool roll)
2305 switch (_session->record_status()) {
2306 case Session::Disabled:
2307 if (_session->ntracks() == 0) {
2308 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."));
2312 if (Profile->get_trx()) {
2313 roll = trx_record_enable_all_tracks ();
2315 _session->maybe_enable_record ();
2320 case Session::Recording:
2322 _session->request_stop();
2324 _session->disable_record (false, true);
2328 case Session::Enabled:
2329 _session->disable_record (false, true);
2335 ARDOUR_UI::transport_roll ()
2341 if (_session->is_auditioning()) {
2346 if (_session->config.get_external_sync()) {
2347 switch (Config->get_sync_source()) {
2351 /* transport controlled by the master */
2357 bool rolling = _session->transport_rolling();
2359 if (_session->get_play_loop()) {
2361 /* If loop playback is not a mode, then we should cancel
2362 it when this action is requested. If it is a mode
2363 we just leave it in place.
2366 if (!Config->get_loop_is_mode()) {
2367 /* XXX it is not possible to just leave seamless loop and keep
2368 playing at present (nov 4th 2009)
2370 if (!Config->get_seamless_loop()) {
2371 /* stop loop playback and stop rolling */
2372 _session->request_play_loop (false, true);
2373 } else if (rolling) {
2374 /* stop loop playback but keep rolling */
2375 _session->request_play_loop (false, false);
2379 } else if (_session->get_play_range () ) {
2380 /* stop playing a range if we currently are */
2381 _session->request_play_range (0, true);
2385 _session->request_transport_speed (1.0f);
2390 ARDOUR_UI::get_smart_mode() const
2392 return ( editor->get_smart_mode() );
2397 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2403 if (_session->is_auditioning()) {
2404 _session->cancel_audition ();
2408 if (_session->config.get_external_sync()) {
2409 switch (Config->get_sync_source()) {
2413 /* transport controlled by the master */
2418 bool rolling = _session->transport_rolling();
2419 bool affect_transport = true;
2421 if (rolling && roll_out_of_bounded_mode) {
2422 /* drop out of loop/range playback but leave transport rolling */
2423 if (_session->get_play_loop()) {
2424 if (_session->actively_recording()) {
2426 /* just stop using the loop, then actually stop
2429 _session->request_play_loop (false, affect_transport);
2432 if (Config->get_seamless_loop()) {
2433 /* the disk buffers contain copies of the loop - we can't
2434 just keep playing, so stop the transport. the user
2435 can restart as they wish.
2437 affect_transport = true;
2439 /* disk buffers are normal, so we can keep playing */
2440 affect_transport = false;
2442 _session->request_play_loop (false, affect_transport);
2444 } else if (_session->get_play_range ()) {
2445 affect_transport = false;
2446 _session->request_play_range (0, true);
2450 if (affect_transport) {
2452 _session->request_stop (with_abort, true);
2454 } else if (!with_abort) { /* with_abort == true means the
2455 * command was intended to stop
2456 * transport, not start.
2459 /* the only external sync condition we can be in here
2460 * would be Engine (JACK) sync, in which case we still
2464 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
2465 _session->request_play_range (&editor->get_selection().time, true);
2466 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2468 _session->request_transport_speed (1.0f);
2474 ARDOUR_UI::toggle_session_auto_loop ()
2480 Location * looploc = _session->locations()->auto_loop_location();
2486 if (_session->get_play_loop()) {
2488 /* looping enabled, our job is to disable it */
2490 _session->request_play_loop (false);
2494 /* looping not enabled, our job is to enable it.
2496 loop-is-NOT-mode: this action always starts the transport rolling.
2497 loop-IS-mode: this action simply sets the loop play mechanism, but
2498 does not start transport.
2500 if (Config->get_loop_is_mode()) {
2501 _session->request_play_loop (true, false);
2503 _session->request_play_loop (true, true);
2507 //show the loop markers
2508 looploc->set_hidden (false, this);
2512 ARDOUR_UI::transport_play_selection ()
2518 editor->play_selection ();
2522 ARDOUR_UI::transport_play_preroll ()
2527 editor->play_with_preroll ();
2531 ARDOUR_UI::transport_rec_preroll ()
2536 editor->rec_with_preroll ();
2540 ARDOUR_UI::transport_rec_count_in ()
2545 editor->rec_with_count_in ();
2549 ARDOUR_UI::transport_rewind (int option)
2551 float current_transport_speed;
2554 current_transport_speed = _session->transport_speed();
2556 if (current_transport_speed >= 0.0f) {
2559 _session->request_transport_speed (-1.0f);
2562 _session->request_transport_speed (-4.0f);
2565 _session->request_transport_speed (-0.5f);
2570 _session->request_transport_speed (current_transport_speed * 1.5f);
2576 ARDOUR_UI::transport_forward (int option)
2582 float current_transport_speed = _session->transport_speed();
2584 if (current_transport_speed <= 0.0f) {
2587 _session->request_transport_speed (1.0f);
2590 _session->request_transport_speed (4.0f);
2593 _session->request_transport_speed (0.5f);
2598 _session->request_transport_speed (current_transport_speed * 1.5f);
2603 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2609 boost::shared_ptr<Route> r;
2611 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2613 boost::shared_ptr<Track> t;
2615 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2616 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2622 ARDOUR_UI::map_transport_state ()
2625 auto_loop_button.unset_active_state ();
2626 play_selection_button.unset_active_state ();
2627 roll_button.unset_active_state ();
2628 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2629 layered_button.set_sensitive (false);
2633 shuttle_box.map_transport_state ();
2635 float sp = _session->transport_speed();
2641 if (_session->get_play_range()) {
2643 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2644 roll_button.unset_active_state ();
2645 auto_loop_button.unset_active_state ();
2647 } else if (_session->get_play_loop ()) {
2649 auto_loop_button.set_active (true);
2650 play_selection_button.set_active (false);
2651 if (Config->get_loop_is_mode()) {
2652 roll_button.set_active (true);
2654 roll_button.set_active (false);
2659 roll_button.set_active (true);
2660 play_selection_button.set_active (false);
2661 auto_loop_button.set_active (false);
2664 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2665 /* light up both roll and play-selection if they are joined */
2666 roll_button.set_active (true);
2667 play_selection_button.set_active (true);
2669 layered_button.set_sensitive (!_session->actively_recording ());
2671 stop_button.set_active (false);
2675 layered_button.set_sensitive (true);
2676 stop_button.set_active (true);
2677 roll_button.set_active (false);
2678 play_selection_button.set_active (false);
2679 if (Config->get_loop_is_mode ()) {
2680 auto_loop_button.set_active (_session->get_play_loop());
2682 auto_loop_button.set_active (false);
2684 update_disk_space ();
2689 ARDOUR_UI::blink_handler (bool blink_on)
2691 transport_rec_enable_blink (blink_on);
2692 sync_blink (blink_on);
2694 if (!UIConfiguration::instance().get_blink_alert_indicators()) {
2697 error_blink (blink_on);
2698 solo_blink (blink_on);
2699 audition_blink (blink_on);
2700 feedback_blink (blink_on);
2704 ARDOUR_UI::update_clocks ()
2706 if (!_session) return;
2708 if (editor && !editor->dragging_playhead()) {
2709 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2714 ARDOUR_UI::start_clocking ()
2716 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2717 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2719 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2724 ARDOUR_UI::stop_clocking ()
2726 clock_signal_connection.disconnect ();
2730 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2734 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2736 label->set_text (buf);
2737 bar->set_fraction (fraction);
2739 /* process events, redraws, etc. */
2741 while (gtk_events_pending()) {
2742 gtk_main_iteration ();
2745 return true; /* continue with save-as */
2749 ARDOUR_UI::save_session_as ()
2755 if (_session->dirty()) {
2756 vector<string> actions;
2757 actions.push_back (_("Abort save-as"));
2758 actions.push_back (_("Don't save now, just save-as"));
2759 actions.push_back (_("Save it first"));
2760 switch (ask_about_saving_session(actions)) {
2765 if (save_state_canfail ("")) {
2766 MessageDialog msg (_main_window,
2767 string_compose (_("\
2768 %1 was unable to save your session.\n\n\
2769 If you still wish to proceeed, please use the\n\n\
2770 \"Don't save now\" option."), PROGRAM_NAME));
2771 pop_back_splash(msg);
2777 _session->remove_pending_capture_state ();
2782 if (!save_as_dialog) {
2783 save_as_dialog = new SaveAsDialog;
2786 save_as_dialog->set_name (_session->name());
2788 int response = save_as_dialog->run ();
2790 save_as_dialog->hide ();
2793 case Gtk::RESPONSE_OK:
2802 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2803 sa.new_name = save_as_dialog->new_name ();
2804 sa.switch_to = save_as_dialog->switch_to();
2805 sa.copy_media = save_as_dialog->copy_media();
2806 sa.copy_external = save_as_dialog->copy_external();
2807 sa.include_media = save_as_dialog->include_media ();
2809 /* Only bother with a progress dialog if we're going to copy
2810 media into the save-as target. Without that choice, this
2811 will be very fast because we're only talking about a few kB's to
2812 perhaps a couple of MB's of data.
2815 ArdourDialog progress_dialog (_("Save As"), true);
2818 if (sa.include_media && sa.copy_media) {
2820 Gtk::Label* label = manage (new Gtk::Label());
2821 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
2823 progress_dialog.get_vbox()->pack_start (*label);
2824 progress_dialog.get_vbox()->pack_start (*progress_bar);
2826 progress_bar->show ();
2828 /* this signal will be emitted from within this, the calling thread,
2829 * after every file is copied. It provides information on percentage
2830 * complete (in terms of total data to copy), the number of files
2831 * copied so far, and the total number to copy.
2834 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
2836 progress_dialog.show_all ();
2837 progress_dialog.present ();
2840 if (_session->save_as (sa)) {
2842 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2846 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2847 * the trick is this: if the new session was copy with media included,
2848 * then Session::save_as() will have already done a neat trick to avoid
2849 * us having to unload and load the new state. But if the media was not
2850 * included, then this is required (it avoids us having to otherwise
2851 * drop all references to media (sources).
2854 if (!sa.include_media && sa.switch_to) {
2855 unload_session (false);
2856 load_session (sa.final_session_folder_name, sa.new_name);
2861 ARDOUR_UI::archive_session ()
2869 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2871 SessionArchiveDialog sad;
2872 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2873 int response = sad.run ();
2875 if (response != Gtk::RESPONSE_OK) {
2880 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2881 MessageDialog msg (_("Session Archiving failed."));
2887 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2891 struct tm local_time;
2894 localtime_r (&n, &local_time);
2895 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2896 if (switch_to_it && _session->dirty ()) {
2897 save_state_canfail ("");
2900 save_state (timebuf, switch_to_it);
2905 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
2909 prompter.get_result (snapname);
2911 bool do_save = (snapname.length() != 0);
2914 char illegal = Session::session_name_is_legal(snapname);
2916 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2917 "snapshot names may not contain a '%1' character"), illegal));
2923 vector<std::string> p;
2924 get_state_files_in_directory (_session->session_directory().root_path(), p);
2925 vector<string> n = get_file_names_no_extension (p);
2927 if (find (n.begin(), n.end(), snapname) != n.end()) {
2929 do_save = overwrite_file_dialog (prompter,
2930 _("Confirm Snapshot Overwrite"),
2931 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2935 save_state (snapname, switch_to_it);
2945 /** Ask the user for the name of a new snapshot and then take it.
2949 ARDOUR_UI::snapshot_session (bool switch_to_it)
2951 if (switch_to_it && _session->dirty()) {
2952 vector<string> actions;
2953 actions.push_back (_("Abort saving snapshot"));
2954 actions.push_back (_("Don't save now, just snapshot"));
2955 actions.push_back (_("Save it first"));
2956 switch (ask_about_saving_session(actions)) {
2961 if (save_state_canfail ("")) {
2962 MessageDialog msg (_main_window,
2963 string_compose (_("\
2964 %1 was unable to save your session.\n\n\
2965 If you still wish to proceeed, please use the\n\n\
2966 \"Don't save now\" option."), PROGRAM_NAME));
2967 pop_back_splash(msg);
2973 _session->remove_pending_capture_state ();
2978 Prompter prompter (true);
2979 prompter.set_name ("Prompter");
2980 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2982 prompter.set_title (_("Snapshot and switch"));
2983 prompter.set_prompt (_("New session name"));
2985 prompter.set_title (_("Take Snapshot"));
2986 prompter.set_prompt (_("Name of new snapshot"));
2990 prompter.set_initial_text (_session->snap_name());
2992 Glib::DateTime tm (g_date_time_new_now_local ());
2993 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2996 bool finished = false;
2998 switch (prompter.run()) {
2999 case RESPONSE_ACCEPT:
3001 finished = process_snapshot_session_prompter (prompter, switch_to_it);
3012 /** Ask the user for a new session name and then rename the session to it.
3016 ARDOUR_UI::rename_session ()
3022 Prompter prompter (true);
3025 prompter.set_name ("Prompter");
3026 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3027 prompter.set_title (_("Rename Session"));
3028 prompter.set_prompt (_("New session name"));
3031 switch (prompter.run()) {
3032 case RESPONSE_ACCEPT:
3034 prompter.get_result (name);
3036 bool do_rename = (name.length() != 0);
3039 char illegal = Session::session_name_is_legal (name);
3042 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
3043 "session names may not contain a '%1' character"), illegal));
3048 switch (_session->rename (name)) {
3050 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
3051 msg.set_position (WIN_POS_MOUSE);
3059 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
3060 msg.set_position (WIN_POS_MOUSE);
3076 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
3078 if (!_session || _session->deletion_in_progress()) {
3082 XMLNode* node = new XMLNode (X_("UI"));
3084 WM::Manager::instance().add_state (*node);
3086 node->add_child_nocopy (gui_object_state->get_state());
3088 _session->add_extra_xml (*node);
3090 if (export_video_dialog) {
3091 _session->add_extra_xml (export_video_dialog->get_state());
3094 save_state_canfail (name, switch_to_it);
3098 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
3103 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
3108 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
3113 ARDOUR_UI::primary_clock_value_changed ()
3116 _session->request_locate (primary_clock->current_time ());
3121 ARDOUR_UI::big_clock_value_changed ()
3124 _session->request_locate (big_clock->current_time ());
3129 ARDOUR_UI::secondary_clock_value_changed ()
3132 _session->request_locate (secondary_clock->current_time ());
3137 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
3139 if (_session == 0) {
3143 if (_session->step_editing()) {
3147 Session::RecordState const r = _session->record_status ();
3148 bool const h = _session->have_rec_enabled_track ();
3150 if (r == Session::Enabled || (r == Session::Recording && !h)) {
3152 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3154 rec_button.set_active_state (Gtkmm2ext::Off);
3156 } else if (r == Session::Recording && h) {
3157 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3159 rec_button.unset_active_state ();
3164 ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
3166 if (response == RESPONSE_ACCEPT) {
3167 const string name = d->get_template_name ();
3168 const string desc = d->get_description ();
3170 int failed = _session->save_template (name, desc);
3172 if (failed == -2) { /* file already exists. */
3173 bool overwrite = overwrite_file_dialog (*d,
3174 _("Confirm Template Overwrite"),
3175 _("A template already exists with that name. Do you want to overwrite it?"));
3178 _session->save_template (name, desc, true);
3190 ARDOUR_UI::save_template ()
3192 if (!check_audioengine (_main_window)) {
3196 const std::string desc = SessionMetadata::Metadata()->description ();
3197 SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc);
3198 d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d));
3202 void ARDOUR_UI::manage_templates ()
3209 ARDOUR_UI::edit_metadata ()
3211 SessionMetadataEditor dialog;
3212 dialog.set_session (_session);
3213 dialog.grab_focus ();
3218 ARDOUR_UI::import_metadata ()
3220 SessionMetadataImporter dialog;
3221 dialog.set_session (_session);
3226 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3228 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3230 MessageDialog msg (str,
3232 Gtk::MESSAGE_WARNING,
3233 Gtk::BUTTONS_YES_NO,
3237 msg.set_name (X_("OpenExistingDialog"));
3238 msg.set_title (_("Open Existing Session"));
3239 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3240 msg.set_position (Gtk::WIN_POS_CENTER);
3241 pop_back_splash (msg);
3243 switch (msg.run()) {
3252 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3254 BusProfile bus_profile;
3257 bus_profile.master_out_channels = 2;
3259 /* get settings from advanced section of NSD */
3260 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3263 // NULL profile: no master, no monitor
3264 if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) {
3272 ARDOUR_UI::load_from_application_api (const std::string& path)
3274 /* OS X El Capitan (and probably later) now somehow passes the command
3275 line arguments to an app via the openFile delegate protocol. Ardour
3276 already does its own command line processing, and having both
3277 pathways active causes crashes. So, if the command line was already
3278 set, do nothing here.
3281 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3285 ARDOUR_COMMAND_LINE::session_name = path;
3287 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3289 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3291 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3292 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3293 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3294 * -> SessionDialog is not displayed
3297 if (_session_dialog) {
3298 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3299 std::string session_path = path;
3300 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3301 session_path = Glib::path_get_dirname (session_path);
3303 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3304 _session_dialog->set_provided_session (session_name, session_path);
3305 _session_dialog->response (RESPONSE_NONE);
3306 _session_dialog->hide();
3311 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3312 /* /path/to/foo => /path/to/foo, foo */
3313 rv = load_session (path, basename_nosuffix (path));
3315 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3316 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3319 // if load_session fails -> pop up SessionDialog.
3321 ARDOUR_COMMAND_LINE::session_name = "";
3323 if (get_session_parameters (true, false)) {
3329 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3331 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3333 string session_name;
3334 string session_path;
3335 string template_name;
3337 bool likely_new = false;
3338 bool cancel_not_quit;
3340 /* deal with any existing DIRTY session now, rather than later. don't
3341 * treat a non-dirty session this way, so that it stays visible
3342 * as we bring up the new session dialog.
3345 if (_session && ARDOUR_UI::instance()->video_timeline) {
3346 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3349 /* if there is already a session, relabel the button
3350 on the SessionDialog so that we don't Quit directly
3352 cancel_not_quit = (_session != 0) && !quit_on_cancel;
3354 if (_session && _session->dirty()) {
3355 if (unload_session (false)) {
3356 /* unload cancelled by user */
3359 ARDOUR_COMMAND_LINE::session_name = "";
3362 if (!load_template.empty()) {
3363 should_be_new = true;
3364 template_name = load_template;
3367 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3368 session_path = ARDOUR_COMMAND_LINE::session_name;
3370 if (!session_path.empty()) {
3371 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3372 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3373 /* session/snapshot file, change path to be dir */
3374 session_path = Glib::path_get_dirname (session_path);
3379 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3381 _session_dialog = &session_dialog;
3384 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3386 /* if they named a specific statefile, use it, otherwise they are
3387 just giving a session folder, and we want to use it as is
3388 to find the session.
3391 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3393 if (suffix != string::npos) {
3394 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3395 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3396 session_name = Glib::path_get_basename (session_name);
3398 session_path = ARDOUR_COMMAND_LINE::session_name;
3399 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3404 session_dialog.clear_given ();
3407 if (should_be_new || session_name.empty()) {
3408 /* need the dialog to get info from user */
3410 cerr << "run dialog\n";
3412 switch (session_dialog.run()) {
3413 case RESPONSE_ACCEPT:
3416 /* this is used for async * app->ShouldLoad(). */
3417 continue; // while loop
3420 if (quit_on_cancel) {
3421 ARDOUR_UI::finish ();
3422 Gtkmm2ext::Application::instance()->cleanup();
3424 pthread_cancel_all ();
3425 return -1; // caller is responsible to call exit()
3431 session_dialog.hide ();
3434 /* if we run the startup dialog again, offer more than just "new session" */
3436 should_be_new = false;
3438 session_name = session_dialog.session_name (likely_new);
3439 session_path = session_dialog.session_folder ();
3446 int rv = ARDOUR::inflate_session (session_name,
3447 Config->get_default_session_parent_dir(), session_path, session_name);
3449 MessageDialog msg (session_dialog,
3450 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3455 session_dialog.set_provided_session (session_name, session_path);
3459 // XXX check archive, inflate
3460 string::size_type suffix = session_name.find (statefile_suffix);
3462 if (suffix != string::npos) {
3463 session_name = session_name.substr (0, suffix);
3466 /* this shouldn't happen, but we catch it just in case it does */
3468 if (session_name.empty()) {
3472 if (session_dialog.use_session_template()) {
3473 template_name = session_dialog.session_template_name();
3474 _session_is_new = true;
3477 if (session_name[0] == G_DIR_SEPARATOR ||
3478 #ifdef PLATFORM_WINDOWS
3479 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3481 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3482 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3487 /* absolute path or cwd-relative path specified for session name: infer session folder
3488 from what was given.
3491 session_path = Glib::path_get_dirname (session_name);
3492 session_name = Glib::path_get_basename (session_name);
3496 session_path = session_dialog.session_folder();
3498 char illegal = Session::session_name_is_legal (session_name);
3501 MessageDialog msg (session_dialog,
3502 string_compose (_("To ensure compatibility with various systems\n"
3503 "session names may not contain a '%1' character"),
3506 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3511 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3514 if (likely_new && !nsm) {
3516 std::string existing = Glib::build_filename (session_path, session_name);
3518 if (!ask_about_loading_existing_session (existing)) {
3519 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3524 _session_is_new = false;
3529 pop_back_splash (session_dialog);
3530 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3532 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3536 char illegal = Session::session_name_is_legal(session_name);
3539 pop_back_splash (session_dialog);
3540 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3541 "session names may not contain a '%1' character"), illegal));
3543 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3547 _session_is_new = true;
3550 if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") {
3552 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3553 meta_session_setup (template_name.substr (11));
3555 } else if (likely_new && template_name.empty()) {
3557 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3561 ret = load_session (session_path, session_name, template_name);
3564 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3568 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3569 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3573 /* clear this to avoid endless attempts to load the
3577 ARDOUR_COMMAND_LINE::session_name = "";
3581 _session_dialog = NULL;
3587 ARDOUR_UI::close_session()
3589 if (!check_audioengine (_main_window)) {
3593 if (unload_session (true)) {
3597 ARDOUR_COMMAND_LINE::session_name = "";
3599 if (get_session_parameters (true, false)) {
3604 /** @param snap_name Snapshot name (without .ardour suffix).
3605 * @return -2 if the load failed because we are not connected to the AudioEngine.
3608 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3610 /* load_session calls flush_pending() which allows
3611 * GUI interaction and potentially loading another session
3612 * (that was easy via snapshot sidebar).
3613 * Recursing into load_session() from load_session() and recusive
3614 * event loops causes all kind of crashes.
3616 assert (!session_load_in_progress);
3617 if (session_load_in_progress) {
3620 PBD::Unwinder<bool> lsu (session_load_in_progress, true);
3622 Session *new_session;
3627 unload_status = unload_session ();
3629 if (unload_status < 0) {
3631 } else if (unload_status > 0) {
3637 session_loaded = false;
3639 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3642 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3645 /* this one is special */
3647 catch (AudioEngine::PortRegistrationFailure& err) {
3649 MessageDialog msg (err.what(),
3652 Gtk::BUTTONS_CLOSE);
3654 msg.set_title (_("Port Registration Error"));
3655 msg.set_secondary_text (_("Click the Close button to try again."));
3656 msg.set_position (Gtk::WIN_POS_CENTER);
3657 pop_back_splash (msg);
3660 int response = msg.run ();
3665 case RESPONSE_CANCEL:
3672 catch (SessionException e) {
3673 MessageDialog msg (string_compose(
3674 _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
3675 path, snap_name, e.what()),
3680 msg.set_title (_("Loading Error"));
3681 msg.set_position (Gtk::WIN_POS_CENTER);
3682 pop_back_splash (msg);
3694 MessageDialog msg (string_compose(
3695 _("Session \"%1 (snapshot %2)\" did not load successfully."),
3701 msg.set_title (_("Loading Error"));
3702 msg.set_position (Gtk::WIN_POS_CENTER);
3703 pop_back_splash (msg);
3715 list<string> const u = new_session->unknown_processors ();
3717 MissingPluginDialog d (_session, u);
3722 if (!new_session->writable()) {
3723 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3728 msg.set_title (_("Read-only Session"));
3729 msg.set_position (Gtk::WIN_POS_CENTER);
3730 pop_back_splash (msg);
3737 /* Now the session been created, add the transport controls */
3738 new_session->add_controllable(roll_controllable);
3739 new_session->add_controllable(stop_controllable);
3740 new_session->add_controllable(goto_start_controllable);
3741 new_session->add_controllable(goto_end_controllable);
3742 new_session->add_controllable(auto_loop_controllable);
3743 new_session->add_controllable(play_selection_controllable);
3744 new_session->add_controllable(rec_controllable);
3746 set_session (new_session);
3748 session_loaded = true;
3751 _session->set_clean ();
3754 #ifdef WINDOWS_VST_SUPPORT
3755 fst_stop_threading();
3759 Timers::TimerSuspender t;
3763 #ifdef WINDOWS_VST_SUPPORT
3764 fst_start_threading();
3768 if (!mix_template.empty ()) {
3769 /* if mix_template is given, assume this is a new session */
3770 string metascript = Glib::build_filename (mix_template, "template.lua");
3771 meta_session_setup (metascript);
3776 /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
3777 * which is queued by set_session().
3778 * If session-loading fails we hide it explicitly.
3779 * This covers both cases in a central place.
3788 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile)
3790 Session *new_session;
3793 session_loaded = false;
3794 x = unload_session ();
3802 _session_is_new = true;
3805 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile);
3808 catch (SessionException e) {
3809 cerr << "Here are the errors associated with this failed session:\n";
3811 cerr << "---------\n";
3812 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3813 msg.set_title (_("Loading Error"));
3814 msg.set_position (Gtk::WIN_POS_CENTER);
3815 pop_back_splash (msg);
3820 cerr << "Here are the errors associated with this failed session:\n";
3822 cerr << "---------\n";
3823 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3824 msg.set_title (_("Loading Error"));
3825 msg.set_position (Gtk::WIN_POS_CENTER);
3826 pop_back_splash (msg);
3831 /* Give the new session the default GUI state, if such things exist */
3834 n = Config->instant_xml (X_("Editor"));
3836 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3837 new_session->add_instant_xml (*n, false);
3839 n = Config->instant_xml (X_("Mixer"));
3841 new_session->add_instant_xml (*n, false);
3844 n = Config->instant_xml (X_("Preferences"));
3846 new_session->add_instant_xml (*n, false);
3849 /* Put the playhead at 0 and scroll fully left */
3850 n = new_session->instant_xml (X_("Editor"));
3852 n->set_property (X_("playhead"), X_("0"));
3853 n->set_property (X_("left-frame"), X_("0"));
3856 set_session (new_session);
3858 session_loaded = true;
3860 new_session->save_state(new_session->name());
3866 static void _lua_print (std::string s) {
3868 std::cout << "LuaInstance: " << s << "\n";
3870 PBD::info << "LuaInstance: " << s << endmsg;
3873 std::map<std::string, std::string>
3874 ARDOUR_UI::route_setup_info (const std::string& script_path)
3876 std::map<std::string, std::string> rv;
3878 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3883 lua.Print.connect (&_lua_print);
3886 lua_State* L = lua.getState();
3887 LuaInstance::register_classes (L);
3888 LuaBindings::set_session (L, _session);
3889 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3890 lua_setglobal (L, "Editor");
3892 lua.do_command ("function ardour () end");
3893 lua.do_file (script_path);
3896 luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup");
3897 if (!fn.isFunction ()) {
3900 luabridge::LuaRef rs = fn ();
3901 if (!rs.isTable ()) {
3904 for (luabridge::Iterator i(rs); !i.isNil (); ++i) {
3905 if (!i.key().isString()) {
3908 std::string key = i.key().tostring();
3909 if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) {
3910 rv[key] = i.value().tostring();
3913 } catch (luabridge::LuaException const& e) {
3914 cerr << "LuaException:" << e.what () << endl;
3920 ARDOUR_UI::meta_route_setup (const std::string& script_path)
3922 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3925 assert (add_route_dialog);
3928 if ((count = add_route_dialog->count()) <= 0) {
3933 lua.Print.connect (&_lua_print);
3936 lua_State* L = lua.getState();
3937 LuaInstance::register_classes (L);
3938 LuaBindings::set_session (L, _session);
3939 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3940 lua_setglobal (L, "Editor");
3942 lua.do_command ("function ardour () end");
3943 lua.do_file (script_path);
3945 luabridge::LuaRef args (luabridge::newTable (L));
3947 args["name"] = add_route_dialog->name_template ();
3948 args["insert_at"] = translate_order (add_route_dialog->insert_at());
3949 args["group"] = add_route_dialog->route_group ();
3950 args["strict_io"] = add_route_dialog->use_strict_io ();
3951 args["instrument"] = add_route_dialog->requested_instrument ();
3952 args["track_mode"] = add_route_dialog->mode ();
3953 args["channels"] = add_route_dialog->channel_count ();
3954 args["how_many"] = count;
3957 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3958 if (fn.isFunction()) {
3961 } catch (luabridge::LuaException const& e) {
3962 cerr << "LuaException:" << e.what () << endl;
3964 display_insufficient_ports_message ();
3969 ARDOUR_UI::meta_session_setup (const std::string& script_path)
3971 if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) {
3976 lua.Print.connect (&_lua_print);
3979 lua_State* L = lua.getState();
3980 LuaInstance::register_classes (L);
3981 LuaBindings::set_session (L, _session);
3982 luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
3983 lua_setglobal (L, "Editor");
3985 lua.do_command ("function ardour () end");
3986 lua.do_file (script_path);
3989 luabridge::LuaRef fn = luabridge::getGlobal (L, "factory");
3990 if (fn.isFunction()) {
3993 } catch (luabridge::LuaException const& e) {
3994 cerr << "LuaException:" << e.what () << endl;
3996 display_insufficient_ports_message ();
4001 ARDOUR_UI::launch_chat ()
4003 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
4005 dialog.set_title (_("About the Chat"));
4006 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."));
4008 switch (dialog.run()) {
4011 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
4012 #elif defined PLATFORM_WINDOWS
4013 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
4015 open_uri("http://webchat.freenode.net/?channels=ardour");
4024 ARDOUR_UI::launch_manual ()
4026 PBD::open_uri (Config->get_tutorial_manual_url());
4030 ARDOUR_UI::launch_reference ()
4032 PBD::open_uri (Config->get_reference_manual_url());
4036 ARDOUR_UI::launch_tracker ()
4038 PBD::open_uri ("http://tracker.ardour.org");
4042 ARDOUR_UI::launch_subscribe ()
4044 PBD::open_uri ("https://community.ardour.org/s/subscribe");
4048 ARDOUR_UI::launch_cheat_sheet ()
4051 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
4053 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
4058 ARDOUR_UI::launch_website ()
4060 PBD::open_uri ("http://ardour.org");
4064 ARDOUR_UI::launch_website_dev ()
4066 PBD::open_uri ("http://ardour.org/development.html");
4070 ARDOUR_UI::launch_forums ()
4072 PBD::open_uri ("https://community.ardour.org/forums");
4076 ARDOUR_UI::launch_howto_report ()
4078 PBD::open_uri ("http://ardour.org/reporting_bugs");
4082 ARDOUR_UI::loading_message (const std::string& msg)
4084 if (ARDOUR_COMMAND_LINE::no_splash) {
4092 splash->message (msg);
4096 ARDOUR_UI::show_splash ()
4100 splash = new Splash;
4110 ARDOUR_UI::hide_splash ()
4117 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
4121 removed = rep.paths.size();
4124 MessageDialog msgd (_main_window,
4125 _("No files were ready for clean-up"),
4129 msgd.set_title (_("Clean-up"));
4130 msgd.set_secondary_text (_("If this seems surprising, \n\
4131 check for any existing snapshots.\n\
4132 These may still include regions that\n\
4133 require some unused files to continue to exist."));
4139 ArdourDialog results (_("Clean-up"), true, false);
4141 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
4142 CleanupResultsModelColumns() {
4146 Gtk::TreeModelColumn<std::string> visible_name;
4147 Gtk::TreeModelColumn<std::string> fullpath;
4151 CleanupResultsModelColumns results_columns;
4152 Glib::RefPtr<Gtk::ListStore> results_model;
4153 Gtk::TreeView results_display;
4155 results_model = ListStore::create (results_columns);
4156 results_display.set_model (results_model);
4157 results_display.append_column (list_title, results_columns.visible_name);
4159 results_display.set_name ("CleanupResultsList");
4160 results_display.set_headers_visible (true);
4161 results_display.set_headers_clickable (false);
4162 results_display.set_reorderable (false);
4164 Gtk::ScrolledWindow list_scroller;
4167 Gtk::HBox dhbox; // the hbox for the image and text
4168 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
4169 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
4171 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
4173 const string dead_directory = _session->session_directory().dead_path();
4176 %1 - number of files removed
4177 %2 - location of "dead"
4178 %3 - size of files affected
4179 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
4182 const char* bprefix;
4183 double space_adjusted = 0;
4185 if (rep.space < 1000) {
4187 space_adjusted = rep.space;
4188 } else if (rep.space < 1000000) {
4189 bprefix = _("kilo");
4190 space_adjusted = floorf((float)rep.space / 1000.0);
4191 } else if (rep.space < 1000000 * 1000) {
4192 bprefix = _("mega");
4193 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
4195 bprefix = _("giga");
4196 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
4200 txt.set_markup (string_compose (P_("\
4201 The following file was deleted from %2,\n\
4202 releasing %3 %4bytes of disk space", "\
4203 The following %1 files were deleted from %2,\n\
4204 releasing %3 %4bytes of disk space", removed),
4205 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4207 txt.set_markup (string_compose (P_("\
4208 The following file was not in use and \n\
4209 has been moved to: %2\n\n\
4210 After a restart of %5\n\n\
4211 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4212 will release an additional %3 %4bytes of disk space.\n", "\
4213 The following %1 files were not in use and \n\
4214 have been moved to: %2\n\n\
4215 After a restart of %5\n\n\
4216 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
4217 will release an additional %3 %4bytes of disk space.\n", removed),
4218 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
4221 dhbox.pack_start (*dimage, true, false, 5);
4222 dhbox.pack_start (txt, true, false, 5);
4224 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
4225 TreeModel::Row row = *(results_model->append());
4226 row[results_columns.visible_name] = *i;
4227 row[results_columns.fullpath] = *i;
4230 list_scroller.add (results_display);
4231 list_scroller.set_size_request (-1, 150);
4232 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
4234 dvbox.pack_start (dhbox, true, false, 5);
4235 dvbox.pack_start (list_scroller, true, false, 5);
4236 ddhbox.pack_start (dvbox, true, false, 5);
4238 results.get_vbox()->pack_start (ddhbox, true, false, 5);
4239 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
4240 results.set_default_response (RESPONSE_CLOSE);
4241 results.set_position (Gtk::WIN_POS_MOUSE);
4243 results_display.show();
4244 list_scroller.show();
4251 //results.get_vbox()->show();
4252 results.set_resizable (false);
4259 ARDOUR_UI::cleanup ()
4261 if (_session == 0) {
4262 /* shouldn't happen: menu item is insensitive */
4267 MessageDialog checker (_("Are you sure you want to clean-up?"),
4269 Gtk::MESSAGE_QUESTION,
4272 checker.set_title (_("Clean-up"));
4274 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4275 ALL undo/redo information will be lost if you clean-up.\n\
4276 Clean-up will move all unused files to a \"dead\" location."));
4278 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4279 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4280 checker.set_default_response (RESPONSE_CANCEL);
4282 checker.set_name (_("CleanupDialog"));
4283 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4284 checker.set_position (Gtk::WIN_POS_MOUSE);
4286 switch (checker.run()) {
4287 case RESPONSE_ACCEPT:
4293 ARDOUR::CleanupReport rep;
4295 editor->prepare_for_cleanup ();
4297 /* do not allow flush until a session is reloaded */
4299 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4301 act->set_sensitive (false);
4304 if (_session->cleanup_sources (rep)) {
4305 editor->finish_cleanup ();
4309 editor->finish_cleanup ();
4312 display_cleanup_results (rep, _("Cleaned Files"), false);
4316 ARDOUR_UI::flush_trash ()
4318 if (_session == 0) {
4319 /* shouldn't happen: menu item is insensitive */
4323 ARDOUR::CleanupReport rep;
4325 if (_session->cleanup_trash_sources (rep)) {
4329 display_cleanup_results (rep, _("deleted file"), true);
4333 ARDOUR_UI::cleanup_peakfiles ()
4335 if (_session == 0) {
4336 /* shouldn't happen: menu item is insensitive */
4340 if (! _session->can_cleanup_peakfiles ()) {
4344 // get all region-views in this session
4346 TrackViewList empty;
4348 editor->get_regions_after(rs, (framepos_t) 0, empty);
4349 std::list<RegionView*> views = rs.by_layer();
4351 // remove displayed audio-region-views waveforms
4352 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4353 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4354 if (!arv) { continue ; }
4355 arv->delete_waves();
4358 // cleanup peak files:
4359 // - stop pending peakfile threads
4360 // - close peakfiles if any
4361 // - remove peak dir in session
4362 // - setup peakfiles (background thread)
4363 _session->cleanup_peakfiles ();
4365 // re-add waves to ARV
4366 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4367 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4368 if (!arv) { continue ; }
4369 arv->create_waves();
4373 PresentationInfo::order_t
4374 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4376 if (editor->get_selection().tracks.empty()) {
4377 return place == RouteDialogs::First ? 0 : PresentationInfo::max_order;
4380 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4383 we want the new routes to have their order keys set starting from
4384 the highest order key in the selection + 1 (if available).
4387 if (place == RouteDialogs::AfterSelection) {
4388 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4390 order_hint = rtav->route()->presentation_info().order();
4393 } else if (place == RouteDialogs::BeforeSelection) {
4394 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4396 order_hint = rtav->route()->presentation_info().order();
4398 } else if (place == RouteDialogs::First) {
4401 /* leave order_hint at max_order */
4408 ARDOUR_UI::start_duplicate_routes ()
4410 if (!duplicate_routes_dialog) {
4411 duplicate_routes_dialog = new DuplicateRouteDialog;
4414 if (duplicate_routes_dialog->restart (_session)) {
4418 duplicate_routes_dialog->present ();
4422 ARDOUR_UI::add_route ()
4424 if (!add_route_dialog.get (false)) {
4425 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_response));
4432 if (add_route_dialog->is_visible()) {
4433 /* we're already doing this */
4437 add_route_dialog->set_position (WIN_POS_MOUSE);
4438 add_route_dialog->present();
4442 ARDOUR_UI::add_route_dialog_response (int r)
4445 warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg;
4452 case AddRouteDialog::Add:
4453 add_route_dialog->reset_name_edited ();
4455 case AddRouteDialog::AddAndClose:
4456 add_route_dialog->ArdourDialog::on_response (r);
4459 add_route_dialog->ArdourDialog::on_response (r);
4463 std::string template_path = add_route_dialog->get_template_path();
4464 if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") {
4465 meta_route_setup (template_path.substr (11));
4469 if ((count = add_route_dialog->count()) <= 0) {
4473 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4474 const string name_template = add_route_dialog->name_template ();
4475 DisplaySuspender ds;
4477 if (!template_path.empty ()) {
4478 if (add_route_dialog->name_template_is_default ()) {
4479 _session->new_route_from_template (count, order, template_path, string ());
4481 _session->new_route_from_template (count, order, template_path, name_template);
4486 ChanCount input_chan= add_route_dialog->channels ();
4487 ChanCount output_chan;
4488 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4489 RouteGroup* route_group = add_route_dialog->route_group ();
4490 AutoConnectOption oac = Config->get_output_auto_connect();
4491 bool strict_io = add_route_dialog->use_strict_io ();
4493 if (oac & AutoConnectMaster) {
4494 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4495 output_chan.set (DataType::MIDI, 0);
4497 output_chan = input_chan;
4500 /* XXX do something with name template */
4502 Session::ProcessorChangeBlocker pcb (_session);
4504 switch (add_route_dialog->type_wanted()) {
4505 case AddRouteDialog::AudioTrack:
4506 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);
4508 case AddRouteDialog::MidiTrack:
4509 session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order);
4511 case AddRouteDialog::MixedTrack:
4512 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4514 case AddRouteDialog::AudioBus:
4515 session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order);
4517 case AddRouteDialog::MidiBus:
4518 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4520 case AddRouteDialog::VCAMaster:
4521 _session->vca_manager().create_vca (count, name_template);
4527 ARDOUR_UI::stop_video_server (bool ask_confirm)
4529 if (!video_server_process && ask_confirm) {
4530 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4532 if (video_server_process) {
4534 ArdourDialog confirm (_("Stop Video-Server"), true);
4535 Label m (_("Do you really want to stop the Video Server?"));
4536 confirm.get_vbox()->pack_start (m, true, true);
4537 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4538 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4539 confirm.show_all ();
4540 if (confirm.run() == RESPONSE_CANCEL) {
4544 delete video_server_process;
4545 video_server_process =0;
4550 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4552 ARDOUR_UI::start_video_server( float_window, true);
4556 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4562 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4563 if (video_server_process) {
4564 popup_error(_("The Video Server is already started."));
4566 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4572 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4574 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4576 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4578 video_server_dialog->set_transient_for (*float_window);
4581 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4582 video_server_dialog->hide();
4584 ResponseType r = (ResponseType) video_server_dialog->run ();
4585 video_server_dialog->hide();
4586 if (r != RESPONSE_ACCEPT) { return false; }
4587 if (video_server_dialog->show_again()) {
4588 Config->set_show_video_server_dialog(false);
4592 std::string icsd_exec = video_server_dialog->get_exec_path();
4593 std::string icsd_docroot = video_server_dialog->get_docroot();
4594 #ifndef PLATFORM_WINDOWS
4595 if (icsd_docroot.empty()) {
4596 icsd_docroot = VideoUtils::video_get_docroot (Config);
4601 #ifdef PLATFORM_WINDOWS
4602 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4603 /* OK, allow all drive letters */
4606 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4607 warning << _("Specified docroot is not an existing directory.") << endmsg;
4610 #ifndef PLATFORM_WINDOWS
4611 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4612 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4613 warning << _("Given Video Server is not an executable file.") << endmsg;
4617 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4618 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4619 warning << _("Given Video Server is not an executable file.") << endmsg;
4625 argp=(char**) calloc(9,sizeof(char*));
4626 argp[0] = strdup(icsd_exec.c_str());
4627 argp[1] = strdup("-P");
4628 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4629 argp[3] = strdup("-p");
4630 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4631 argp[5] = strdup("-C");
4632 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4633 argp[7] = strdup(icsd_docroot.c_str());
4635 stop_video_server();
4637 #ifdef PLATFORM_WINDOWS
4638 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4639 /* OK, allow all drive letters */
4642 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4643 Config->set_video_advanced_setup(false);
4645 std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
4646 Config->set_video_server_url(url_str);
4647 Config->set_video_server_docroot(icsd_docroot);
4648 Config->set_video_advanced_setup(true);
4651 if (video_server_process) {
4652 delete video_server_process;
4655 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4656 if (video_server_process->start()) {
4657 warning << _("Cannot launch the video-server") << endmsg;
4660 int timeout = 120; // 6 sec
4661 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4662 Glib::usleep (50000);
4664 if (--timeout <= 0 || !video_server_process->is_running()) break;
4667 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4669 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4670 delete video_server_process;
4671 video_server_process = 0;
4679 ARDOUR_UI::add_video (Gtk::Window* float_window)
4685 if (!start_video_server(float_window, false)) {
4686 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4691 add_video_dialog->set_transient_for (*float_window);
4694 if (add_video_dialog->is_visible()) {
4695 /* we're already doing this */
4699 ResponseType r = (ResponseType) add_video_dialog->run ();
4700 add_video_dialog->hide();
4701 if (r != RESPONSE_ACCEPT) { return; }
4703 bool local_file, orig_local_file;
4704 std::string path = add_video_dialog->file_name(local_file);
4706 std::string orig_path = path;
4707 orig_local_file = local_file;
4709 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4711 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4712 warning << string_compose(_("could not open %1"), path) << endmsg;
4715 if (!local_file && path.length() == 0) {
4716 warning << _("no video-file selected") << endmsg;
4720 std::string audio_from_video;
4721 bool detect_ltc = false;
4723 switch (add_video_dialog->import_option()) {
4724 case VTL_IMPORT_TRANSCODE:
4726 TranscodeVideoDialog *transcode_video_dialog;
4727 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4728 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4729 transcode_video_dialog->hide();
4730 if (r != RESPONSE_ACCEPT) {
4731 delete transcode_video_dialog;
4735 audio_from_video = transcode_video_dialog->get_audiofile();
4737 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4740 else if (!audio_from_video.empty()) {
4741 editor->embed_audio_from_video(
4743 video_timeline->get_offset(),
4744 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4747 switch (transcode_video_dialog->import_option()) {
4748 case VTL_IMPORT_TRANSCODED:
4749 path = transcode_video_dialog->get_filename();
4752 case VTL_IMPORT_REFERENCE:
4755 delete transcode_video_dialog;
4758 delete transcode_video_dialog;
4762 case VTL_IMPORT_NONE:
4766 /* strip _session->session_directory().video_path() from video file if possible */
4767 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4768 path=path.substr(_session->session_directory().video_path().size());
4769 if (path.at(0) == G_DIR_SEPARATOR) {
4770 path=path.substr(1);
4774 video_timeline->set_update_session_fps(auto_set_session_fps);
4776 if (video_timeline->video_file_info(path, local_file)) {
4777 XMLNode* node = new XMLNode(X_("Videotimeline"));
4778 node->set_property (X_("Filename"), path);
4779 node->set_property (X_("AutoFPS"), auto_set_session_fps);
4780 node->set_property (X_("LocalFile"), local_file);
4781 if (orig_local_file) {
4782 node->set_property (X_("OriginalVideoFile"), orig_path);
4784 node->remove_property (X_("OriginalVideoFile"));
4786 _session->add_extra_xml (*node);
4787 _session->set_dirty ();
4789 if (!audio_from_video.empty() && detect_ltc) {
4790 std::vector<LTCFileReader::LTCMap> ltc_seq;
4793 /* TODO ask user about TV standard (LTC alignment if any) */
4794 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4795 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4797 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4799 /* TODO seek near end of file, and read LTC until end.
4800 * if it fails to find any LTC frames, scan complete file
4802 * calculate drift of LTC compared to video-duration,
4803 * ask user for reference (timecode from start/mid/end)
4806 // LTCFileReader will have written error messages
4809 ::g_unlink(audio_from_video.c_str());
4811 if (ltc_seq.size() == 0) {
4812 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4814 /* the very first TC in the file is somteimes not aligned properly */
4815 int i = ltc_seq.size() -1;
4816 ARDOUR::frameoffset_t video_start_offset =
4817 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4818 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4819 video_timeline->set_offset(video_start_offset);
4823 _session->maybe_update_session_range(
4824 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4825 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4828 if (add_video_dialog->launch_xjadeo() && local_file) {
4829 editor->set_xjadeo_sensitive(true);
4830 editor->toggle_xjadeo_proc(1);
4832 editor->toggle_xjadeo_proc(0);
4834 editor->toggle_ruler_video(true);
4839 ARDOUR_UI::remove_video ()
4841 video_timeline->close_session();
4842 editor->toggle_ruler_video(false);
4845 video_timeline->set_offset_locked(false);
4846 video_timeline->set_offset(0);
4848 /* delete session state */
4849 XMLNode* node = new XMLNode(X_("Videotimeline"));
4850 _session->add_extra_xml(*node);
4851 node = new XMLNode(X_("Videomonitor"));
4852 _session->add_extra_xml(*node);
4853 node = new XMLNode(X_("Videoexport"));
4854 _session->add_extra_xml(*node);
4855 stop_video_server();
4859 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4861 if (localcacheonly) {
4862 video_timeline->vmon_update();
4864 video_timeline->flush_cache();
4866 editor->queue_visual_videotimeline_update();
4870 ARDOUR_UI::export_video (bool range)
4872 if (ARDOUR::Config->get_show_video_export_info()) {
4873 ExportVideoInfobox infobox (_session);
4874 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4875 if (infobox.show_again()) {
4876 ARDOUR::Config->set_show_video_export_info(false);
4879 case GTK_RESPONSE_YES:
4880 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4886 export_video_dialog->set_session (_session);
4887 export_video_dialog->apply_state(editor->get_selection().time, range);
4888 export_video_dialog->run ();
4889 export_video_dialog->hide ();
4893 ARDOUR_UI::preferences_settings () const
4898 node = _session->instant_xml(X_("Preferences"));
4900 node = Config->instant_xml(X_("Preferences"));
4904 node = new XMLNode (X_("Preferences"));
4911 ARDOUR_UI::mixer_settings () const
4916 node = _session->instant_xml(X_("Mixer"));
4918 node = Config->instant_xml(X_("Mixer"));
4922 node = new XMLNode (X_("Mixer"));
4929 ARDOUR_UI::main_window_settings () const
4934 node = _session->instant_xml(X_("Main"));
4936 node = Config->instant_xml(X_("Main"));
4940 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4941 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4946 node = new XMLNode (X_("Main"));
4953 ARDOUR_UI::editor_settings () const
4958 node = _session->instant_xml(X_("Editor"));
4960 node = Config->instant_xml(X_("Editor"));
4964 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4965 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4970 node = new XMLNode (X_("Editor"));
4977 ARDOUR_UI::keyboard_settings () const
4981 node = Config->extra_xml(X_("Keyboard"));
4984 node = new XMLNode (X_("Keyboard"));
4991 ARDOUR_UI::create_xrun_marker (framepos_t where)
4994 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4995 _session->locations()->add (location);
5000 ARDOUR_UI::halt_on_xrun_message ()
5002 cerr << "HALT on xrun\n";
5003 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
5008 ARDOUR_UI::xrun_handler (framepos_t where)
5014 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
5016 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
5017 create_xrun_marker(where);
5020 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
5021 halt_on_xrun_message ();
5026 ARDOUR_UI::disk_overrun_handler ()
5028 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
5030 if (!have_disk_speed_dialog_displayed) {
5031 have_disk_speed_dialog_displayed = true;
5032 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
5033 The disk system on your computer\n\
5034 was not able to keep up with %1.\n\
5036 Specifically, it failed to write data to disk\n\
5037 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
5038 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5044 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
5045 static MessageDialog *scan_dlg = NULL;
5046 static ProgressBar *scan_pbar = NULL;
5047 static HBox *scan_tbox = NULL;
5048 static Gtk::Button *scan_timeout_button;
5051 ARDOUR_UI::cancel_plugin_scan ()
5053 PluginManager::instance().cancel_plugin_scan();
5057 ARDOUR_UI::cancel_plugin_timeout ()
5059 PluginManager::instance().cancel_plugin_timeout();
5060 scan_timeout_button->set_sensitive (false);
5064 ARDOUR_UI::plugin_scan_timeout (int timeout)
5066 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
5070 scan_pbar->set_sensitive (false);
5071 scan_timeout_button->set_sensitive (true);
5072 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
5075 scan_pbar->set_sensitive (false);
5076 scan_timeout_button->set_sensitive (false);
5082 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
5084 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
5088 const bool cancelled = PluginManager::instance().cancelled();
5089 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
5090 if (cancelled && scan_dlg->is_mapped()) {
5095 if (cancelled || !can_cancel) {
5100 static Gtk::Button *cancel_button;
5102 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
5103 VBox* vbox = scan_dlg->get_vbox();
5104 vbox->set_size_request(400,-1);
5105 scan_dlg->set_title (_("Scanning for plugins"));
5107 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
5108 cancel_button->set_name ("EditorGTKButton");
5109 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
5110 cancel_button->show();
5112 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
5114 scan_tbox = manage( new HBox() );
5116 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
5117 scan_timeout_button->set_name ("EditorGTKButton");
5118 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
5119 scan_timeout_button->show();
5121 scan_pbar = manage(new ProgressBar());
5122 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
5123 scan_pbar->set_text(_("Scan Timeout"));
5126 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
5127 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
5129 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
5132 assert(scan_dlg && scan_tbox && cancel_button);
5134 if (type == X_("closeme")) {
5138 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
5141 if (!can_cancel || !cancelled) {
5142 scan_timeout_button->set_sensitive(false);
5144 cancel_button->set_sensitive(can_cancel && !cancelled);
5150 ARDOUR_UI::gui_idle_handler ()
5153 /* due to idle calls, gtk_events_pending() may always return true */
5154 while (gtk_events_pending() && --timeout) {
5155 gtk_main_iteration ();
5160 ARDOUR_UI::disk_underrun_handler ()
5162 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
5164 if (!have_disk_speed_dialog_displayed) {
5165 have_disk_speed_dialog_displayed = true;
5166 MessageDialog* msg = new MessageDialog (
5167 _main_window, string_compose (_("The disk system on your computer\n\
5168 was not able to keep up with %1.\n\
5170 Specifically, it failed to read data from disk\n\
5171 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
5172 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
5178 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
5180 have_disk_speed_dialog_displayed = false;
5185 ARDOUR_UI::session_dialog (std::string msg)
5187 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
5191 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
5198 ARDOUR_UI::pending_state_dialog ()
5200 HBox* hbox = manage (new HBox());
5201 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5202 ArdourDialog dialog (_("Crash Recovery"), true);
5203 Label message (string_compose (_("\
5204 This session appears to have been in the\n\
5205 middle of recording when %1 or\n\
5206 the computer was shutdown.\n\
5208 %1 can recover any captured audio for\n\
5209 you, or it can ignore it. Please decide\n\
5210 what you would like to do.\n"), PROGRAM_NAME));
5211 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5212 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5213 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5214 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5215 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5216 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5217 dialog.set_default_response (RESPONSE_ACCEPT);
5218 dialog.set_position (WIN_POS_CENTER);
5223 switch (dialog.run ()) {
5224 case RESPONSE_ACCEPT:
5232 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5234 HBox* hbox = new HBox();
5235 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5236 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5237 Label message (string_compose (_("\
5238 This session was created with a sample rate of %1 Hz, but\n\
5239 %2 is currently running at %3 Hz. If you load this session,\n\
5240 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5242 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5243 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5244 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5245 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5246 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5247 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5248 dialog.set_default_response (RESPONSE_ACCEPT);
5249 dialog.set_position (WIN_POS_CENTER);
5254 switch (dialog.run()) {
5255 case RESPONSE_ACCEPT:
5265 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5267 MessageDialog msg (string_compose (_("\
5268 This session was created with a sample rate of %1 Hz, but\n\
5269 %2 is currently running at %3 Hz.\n\
5270 Audio will be recorded and played at the wrong sample rate.\n\
5271 Re-Configure the Audio Engine in\n\
5272 Menu > Window > Audio/Midi Setup"),
5273 desired, PROGRAM_NAME, actual),
5275 Gtk::MESSAGE_WARNING);
5280 ARDOUR_UI::use_config ()
5282 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5284 set_transport_controllable_state (*node);
5289 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5291 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5292 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5294 primary_clock->set (pos);
5297 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5298 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5300 secondary_clock->set (pos);
5303 if (big_clock_window) {
5304 big_clock->set (pos);
5306 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5310 ARDOUR_UI::step_edit_status_change (bool yn)
5312 // XXX should really store pre-step edit status of things
5313 // we make insensitive
5316 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5317 rec_button.set_sensitive (false);
5319 rec_button.unset_active_state ();;
5320 rec_button.set_sensitive (true);
5325 ARDOUR_UI::record_state_changed ()
5327 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5330 /* why bother - the clock isn't visible */
5334 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5336 if (big_clock_window) {
5337 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5338 big_clock->set_active (true);
5340 big_clock->set_active (false);
5347 ARDOUR_UI::first_idle ()
5350 _session->allow_auto_play (true);
5354 editor->first_idle();
5357 /* in 1 second, hide the splash screen
5359 * Consider hiding it *now*. If a user opens opens a dialog
5360 * during that one second while the splash is still visible,
5361 * the dialog will push-back the splash.
5362 * Closing the dialog later will pop it back.
5364 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
5366 Keyboard::set_can_save_keybindings (true);
5371 ARDOUR_UI::store_clock_modes ()
5373 XMLNode* node = new XMLNode(X_("ClockModes"));
5375 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5376 XMLNode* child = new XMLNode (X_("Clock"));
5378 child->set_property (X_("name"), (*x)->name());
5379 child->set_property (X_("mode"), (*x)->mode());
5380 child->set_property (X_("on"), (*x)->on());
5382 node->add_child_nocopy (*child);
5385 _session->add_extra_xml (*node);
5386 _session->set_dirty ();
5389 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5390 : Controllable (name), ui (u), type(tp)
5396 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5399 /* do nothing: these are radio-style actions */
5403 const char *action = 0;
5407 action = X_("Roll");
5410 action = X_("Stop");
5413 action = X_("GotoStart");
5416 action = X_("GotoEnd");
5419 action = X_("Loop");
5422 action = X_("PlaySelection");
5425 action = X_("Record");
5435 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5443 ARDOUR_UI::TransportControllable::get_value (void) const
5470 ARDOUR_UI::setup_profile ()
5472 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5473 Profile->set_small_screen ();
5476 if (g_getenv ("TRX")) {
5477 Profile->set_trx ();
5480 if (g_getenv ("MIXBUS")) {
5481 Profile->set_mixbus ();
5486 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5488 MissingFileDialog dialog (s, str, type);
5493 int result = dialog.run ();
5500 return 1; // quit entire session load
5503 result = dialog.get_action ();
5509 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5511 AmbiguousFileDialog dialog (file, hits);
5518 return dialog.get_which ();
5521 /** Allocate our thread-local buffers */
5523 ARDOUR_UI::get_process_buffers ()
5525 _process_thread->get_buffers ();
5528 /** Drop our thread-local buffers */
5530 ARDOUR_UI::drop_process_buffers ()
5532 _process_thread->drop_buffers ();
5536 ARDOUR_UI::feedback_detected ()
5538 _feedback_exists = true;
5542 ARDOUR_UI::successful_graph_sort ()
5544 _feedback_exists = false;
5548 ARDOUR_UI::midi_panic ()
5551 _session->midi_panic();
5556 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5558 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5559 const char* end_big = "</span>";
5560 const char* start_mono = "<tt>";
5561 const char* end_mono = "</tt>";
5563 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5564 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5565 "From now on, use the backup copy with older versions of %3"),
5566 xml_path, backup_path, PROGRAM_NAME,
5568 start_mono, end_mono), true);
5574 ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
5576 using namespace Menu_Helpers;
5578 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
5579 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
5580 i->set_active (editor_meter->meter_type () == type);
5584 ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
5586 using namespace Gtk::Menu_Helpers;
5588 Gtk::Menu* m = manage (new Menu);
5589 MenuList& items = m->items ();
5591 RadioMenuItem::Group group;
5593 _suspend_editor_meter_callbacks = true;
5594 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
5595 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
5596 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
5597 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
5598 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
5599 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
5600 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
5601 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
5602 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
5603 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
5604 add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
5606 m->popup (ev->button, ev->time);
5607 _suspend_editor_meter_callbacks = false;
5611 ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
5613 if (ev->button == 3 && editor_meter) {
5614 popup_editor_meter_menu (ev);
5621 ARDOUR_UI::reset_peak_display ()
5623 if (!_session || !_session->master_out() || !editor_meter) return;
5624 editor_meter->clear_meters();
5625 editor_meter_max_peak = -INFINITY;
5626 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5630 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5632 if (!_session || !_session->master_out()) return;
5633 if (group == _session->master_out()->route_group()) {
5634 reset_peak_display ();
5639 ARDOUR_UI::reset_route_peak_display (Route* route)
5641 if (!_session || !_session->master_out()) return;
5642 if (_session->master_out().get() == route) {
5643 reset_peak_display ();
5648 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5650 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5651 audio_midi_setup->set_position (WIN_POS_CENTER);
5653 if (desired_sample_rate != 0) {
5654 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5655 audio_midi_setup->try_autostart ();
5656 if (ARDOUR::AudioEngine::instance()->running()) {
5663 int response = audio_midi_setup->run();
5665 case Gtk::RESPONSE_DELETE_EVENT:
5666 // after latency callibration engine may run,
5667 // Running() signal was emitted, but dialog will not
5668 // have emitted a response. The user needs to close
5669 // the dialog -> Gtk::RESPONSE_DELETE_EVENT
5670 if (!AudioEngine::instance()->running()) {
5675 if (!AudioEngine::instance()->running()) {
5678 audio_midi_setup->hide ();
5686 ARDOUR_UI::transport_numpad_timeout ()
5688 _numpad_locate_happening = false;
5689 if (_numpad_timeout_connection.connected() )
5690 _numpad_timeout_connection.disconnect();
5695 ARDOUR_UI::transport_numpad_decimal ()
5697 _numpad_timeout_connection.disconnect();
5699 if (_numpad_locate_happening) {
5700 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5701 _numpad_locate_happening = false;
5703 _pending_locate_num = 0;
5704 _numpad_locate_happening = true;
5705 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5710 ARDOUR_UI::transport_numpad_event (int num)
5712 if ( _numpad_locate_happening ) {
5713 _pending_locate_num = _pending_locate_num*10 + num;
5716 case 0: toggle_roll(false, false); break;
5717 case 1: transport_rewind(1); break;
5718 case 2: transport_forward(1); break;
5719 case 3: transport_record(true); break;
5720 case 4: toggle_session_auto_loop(); break;
5721 case 5: transport_record(false); toggle_session_auto_loop(); break;
5722 case 6: toggle_punch(); break;
5723 case 7: toggle_click(); break;
5724 case 8: toggle_auto_return(); break;
5725 case 9: toggle_follow_edits(); break;
5731 ARDOUR_UI::set_flat_buttons ()
5733 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5737 ARDOUR_UI::audioengine_became_silent ()
5739 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5741 Gtk::MESSAGE_WARNING,
5745 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5747 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5748 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5749 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5750 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5751 Gtk::HBox pay_button_box;
5752 Gtk::HBox subscribe_button_box;
5754 pay_button_box.pack_start (pay_button, true, false);
5755 subscribe_button_box.pack_start (subscribe_button, true, false);
5757 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 */
5759 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5760 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5762 msg.get_vbox()->pack_start (pay_label);
5763 msg.get_vbox()->pack_start (pay_button_box);
5764 msg.get_vbox()->pack_start (subscribe_label);
5765 msg.get_vbox()->pack_start (subscribe_button_box);
5767 msg.get_vbox()->show_all ();
5769 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5770 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5771 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5776 case Gtk::RESPONSE_YES:
5777 AudioEngine::instance()->reset_silence_countdown ();
5780 case Gtk::RESPONSE_NO:
5782 save_state_canfail ("");
5786 case Gtk::RESPONSE_CANCEL:
5788 /* don't reset, save session and exit */
5794 ARDOUR_UI::hide_application ()
5796 Application::instance ()-> hide ();
5800 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5802 /* icons, titles, WM stuff */
5804 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5806 if (window_icons.empty()) {
5807 Glib::RefPtr<Gdk::Pixbuf> icon;
5808 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5809 window_icons.push_back (icon);
5811 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5812 window_icons.push_back (icon);
5814 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5815 window_icons.push_back (icon);
5817 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5818 window_icons.push_back (icon);
5822 if (!window_icons.empty()) {
5823 window.set_default_icon_list (window_icons);
5826 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5828 if (!name.empty()) {
5832 window.set_title (title.get_string());
5833 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5835 window.set_flags (CAN_FOCUS);
5836 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5838 /* This is a hack to ensure that GTK-accelerators continue to
5839 * work. Once we switch over to entirely native bindings, this will be
5840 * unnecessary and should be removed
5842 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5844 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5845 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5846 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5847 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5851 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5853 Gtkmm2ext::Bindings* bindings = 0;
5854 Gtk::Window* window = 0;
5856 /* until we get ardour bindings working, we are not handling key
5860 if (ev->type != GDK_KEY_PRESS) {
5864 if (event_window == &_main_window) {
5866 window = event_window;
5868 /* find current tab contents */
5870 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5872 /* see if it uses the ardour binding system */
5875 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5878 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5882 window = event_window;
5884 /* see if window uses ardour binding system */
5886 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5889 /* An empty binding set is treated as if it doesn't exist */
5891 if (bindings && bindings->empty()) {
5895 return key_press_focus_accelerator_handler (*window, ev, bindings);
5898 static Gtkmm2ext::Bindings*
5899 get_bindings_from_widget_heirarchy (GtkWidget** w)
5904 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5907 *w = gtk_widget_get_parent (*w);
5910 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5914 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5916 GtkWindow* win = window.gobj();
5917 GtkWidget* focus = gtk_window_get_focus (win);
5918 GtkWidget* binding_widget = focus;
5919 bool special_handling_of_unmodified_accelerators = false;
5920 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5924 /* some widget has keyboard focus */
5926 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5928 /* A particular kind of focusable widget currently has keyboard
5929 * focus. All unmodified key events should go to that widget
5930 * first and not be used as an accelerator by default
5933 special_handling_of_unmodified_accelerators = true;
5937 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5938 if (focus_bindings) {
5939 bindings = focus_bindings;
5940 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5945 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",
5948 Gtkmm2ext::show_gdk_event_state (ev->state),
5949 special_handling_of_unmodified_accelerators,
5950 Keyboard::some_magic_widget_has_focus(),
5952 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5953 ((ev->state & mask) ? "yes" : "no"),
5954 window.get_title()));
5956 /* This exists to allow us to override the way GTK handles
5957 key events. The normal sequence is:
5959 a) event is delivered to a GtkWindow
5960 b) accelerators/mnemonics are activated
5961 c) if (b) didn't handle the event, propagate to
5962 the focus widget and/or focus chain
5964 The problem with this is that if the accelerators include
5965 keys without modifiers, such as the space bar or the
5966 letter "e", then pressing the key while typing into
5967 a text entry widget results in the accelerator being
5968 activated, instead of the desired letter appearing
5971 There is no good way of fixing this, but this
5972 represents a compromise. The idea is that
5973 key events involving modifiers (not Shift)
5974 get routed into the activation pathway first, then
5975 get propagated to the focus widget if necessary.
5977 If the key event doesn't involve modifiers,
5978 we deliver to the focus widget first, thus allowing
5979 it to get "normal text" without interference
5982 Of course, this can also be problematic: if there
5983 is a widget with focus, then it will swallow
5984 all "normal text" accelerators.
5988 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5990 /* no special handling or there are modifiers in effect: accelerate first */
5992 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5993 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5994 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5996 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5997 KeyboardKey k (ev->state, ev->keyval);
6001 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
6003 if (bindings->activate (k, Bindings::Press)) {
6004 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6008 if (binding_widget) {
6009 binding_widget = gtk_widget_get_parent (binding_widget);
6010 if (binding_widget) {
6011 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
6020 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
6022 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
6023 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6027 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
6029 if (gtk_window_propagate_key_event (win, ev)) {
6030 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
6036 /* no modifiers, propagate first */
6038 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
6040 if (gtk_window_propagate_key_event (win, ev)) {
6041 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
6045 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
6046 KeyboardKey k (ev->state, ev->keyval);
6050 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
6053 if (bindings->activate (k, Bindings::Press)) {
6054 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6058 if (binding_widget) {
6059 binding_widget = gtk_widget_get_parent (binding_widget);
6060 if (binding_widget) {
6061 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
6070 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
6072 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
6073 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
6078 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
6083 ARDOUR_UI::load_bindings ()
6085 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
6086 error << _("Global keybindings are missing") << endmsg;
6091 ARDOUR_UI::cancel_solo ()
6094 _session->cancel_all_solo ();
6099 ARDOUR_UI::reset_focus (Gtk::Widget* w)
6101 /* this resets focus to the first focusable parent of the given widget,
6102 * or, if there is no focusable parent, cancels focus in the toplevel
6103 * window that the given widget is packed into (if there is one).
6110 Gtk::Widget* top = w->get_toplevel();
6112 if (!top || !top->is_toplevel()) {
6116 w = w->get_parent ();
6120 if (w->is_toplevel()) {
6121 /* Setting the focus widget to a Gtk::Window causes all
6122 * subsequent calls to ::has_focus() on the nominal
6123 * focus widget in that window to return
6124 * false. Workaround: never set focus to the toplevel
6130 if (w->get_can_focus ()) {
6131 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
6132 win->set_focus (*w);
6135 w = w->get_parent ();
6138 if (top == &_main_window) {
6142 /* no focusable parent found, cancel focus in top level window.
6143 C++ API cannot be used for this. Thanks, references.
6146 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);