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>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #ifdef WINDOWS_VST_SUPPORT
97 #ifdef AUDIOUNIT_SUPPORT
98 #include "ardour/audio_unit.h"
101 #include "timecode/time.h"
103 typedef uint64_t microseconds_t;
108 #include "add_route_dialog.h"
109 #include "ambiguous_file_dialog.h"
110 #include "ardour_ui.h"
111 #include "audio_clock.h"
112 #include "audio_region_view.h"
113 #include "big_clock_window.h"
114 #include "bundle_manager.h"
115 #include "duplicate_routes_dialog.h"
117 #include "engine_dialog.h"
118 #include "export_video_dialog.h"
119 #include "export_video_infobox.h"
120 #include "gain_meter.h"
121 #include "global_port_matrix.h"
122 #include "gui_object.h"
123 #include "gui_thread.h"
124 #include "keyboard.h"
125 #include "keyeditor.h"
126 #include "location_ui.h"
127 #include "main_clock.h"
128 #include "missing_file_dialog.h"
129 #include "missing_plugin_dialog.h"
130 #include "mixer_ui.h"
131 #include "meterbridge.h"
132 #include "mouse_cursors.h"
135 #include "pingback.h"
136 #include "processor_box.h"
137 #include "prompter.h"
138 #include "public_editor.h"
139 #include "rc_option_editor.h"
140 #include "route_time_axis.h"
141 #include "route_params_ui.h"
142 #include "save_as_dialog.h"
143 #include "session_dialog.h"
144 #include "session_metadata_dialog.h"
145 #include "session_option_editor.h"
146 #include "shuttle_control.h"
147 #include "speaker_dialog.h"
150 #include "theme_manager.h"
151 #include "time_axis_view_item.h"
154 #include "video_server_dialog.h"
155 #include "add_video_dialog.h"
156 #include "transcode_video_dialog.h"
160 using namespace ARDOUR;
161 using namespace ARDOUR_UI_UTILS;
163 using namespace Gtkmm2ext;
166 using namespace Editing;
168 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
170 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
171 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
174 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
176 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
177 "Would you like these files to be copied and used for %1 %2.x?\n\n"
178 "(This will require you to restart %1.)"),
179 PROGRAM_NAME, PROGRAM_VERSION, version),
180 false, /* no markup */
183 true /* modal, though it hardly matters since it is the only window */
186 msg.set_default_response (Gtk::RESPONSE_YES);
189 return (msg.run() == Gtk::RESPONSE_YES);
193 libxml_generic_error_func (void* /* parsing_context*/,
201 vsnprintf (buf, sizeof (buf), msg, ap);
202 error << buf << endmsg;
207 libxml_structured_error_func (void* /* parsing_context*/,
215 replace_all (msg, "\n", "");
217 if (err->file && err->line) {
218 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
221 error << ':' << err->int2;
228 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
229 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
230 , session_loaded (false)
231 , gui_object_state (new GUIObjectState)
232 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
233 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
234 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
236 , global_actions (X_("global"))
237 , ignore_dual_punch (false)
242 , _mixer_on_top (false)
243 , _initial_verbose_plugin_scan (false)
244 , first_time_engine_run (true)
245 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
246 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
247 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
248 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
249 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
250 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
251 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
252 , auto_return_button (ArdourButton::led_default_elements)
253 , follow_edits_button (ArdourButton::led_default_elements)
254 , auto_input_button (ArdourButton::led_default_elements)
255 , auditioning_alert_button (_("Audition"))
256 , solo_alert_button (_("Solo"))
257 , feedback_alert_button (_("Feedback"))
258 , error_alert_button ( ArdourButton::just_led_default_elements )
260 , editor_meter_peak_display()
261 , _numpad_locate_happening (false)
262 , _session_is_new (false)
263 , last_key_press_time (0)
266 , rc_option_editor (0)
267 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
268 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
269 , about (X_("about"), _("About"))
270 , location_ui (X_("locations"), _("Locations"))
271 , route_params (X_("inspector"), _("Tracks and Busses"))
272 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
273 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
274 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
275 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
276 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
277 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
278 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
279 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
280 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
281 , video_server_process (0)
283 , have_configure_timeout (false)
284 , last_configure_time (0)
286 , have_disk_speed_dialog_displayed (false)
287 , _status_bar_visibility (X_("status-bar"))
288 , _feedback_exists (false)
289 , _log_not_acknowledged (LogLevelNone)
290 , duplicate_routes_dialog (0)
291 , editor_visibility_button (S_("Window|Editor"))
292 , mixer_visibility_button (S_("Window|Mixer"))
293 , prefs_visibility_button (S_("Window|Preferences"))
295 Gtkmm2ext::init (localedir);
297 UIConfiguration::instance().post_gui_init ();
299 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
300 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
302 /* configuration was modified, exit immediately */
306 if (theArdourUI == 0) {
310 /* stop libxml from spewing to stdout/stderr */
312 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
313 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
315 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
316 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
317 UIConfiguration::instance().map_parameters (pc);
319 roll_button.set_controllable (roll_controllable);
320 stop_button.set_controllable (stop_controllable);
321 goto_start_button.set_controllable (goto_start_controllable);
322 goto_end_button.set_controllable (goto_end_controllable);
323 auto_loop_button.set_controllable (auto_loop_controllable);
324 play_selection_button.set_controllable (play_selection_controllable);
325 rec_button.set_controllable (rec_controllable);
327 roll_button.set_name ("transport button");
328 stop_button.set_name ("transport button");
329 goto_start_button.set_name ("transport button");
330 goto_end_button.set_name ("transport button");
331 auto_loop_button.set_name ("transport button");
332 play_selection_button.set_name ("transport button");
333 rec_button.set_name ("transport recenable button");
334 midi_panic_button.set_name ("transport button");
336 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
337 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
339 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
341 /* handle dialog requests */
343 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
345 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
347 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
349 /* handle Audio/MIDI setup when session requires it */
351 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
353 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
355 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
357 /* handle requests to quit (coming from JACK session) */
359 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
361 /* tell the user about feedback */
363 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
364 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
366 /* handle requests to deal with missing files */
368 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
370 /* and ambiguous files */
372 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
374 /* also plugin scan messages */
375 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
376 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
378 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
380 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
383 /* lets get this party started */
385 setup_gtk_ardour_enums ();
388 SessionEvent::create_per_thread_pool ("GUI", 4096);
390 /* we like keyboards */
392 keyboard = new ArdourKeyboard(*this);
394 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
396 keyboard->set_state (*node, Stateful::loading_state_version);
399 UIConfiguration::instance().reset_dpi ();
401 TimeAxisViewItem::set_constant_heights ();
403 /* Set this up so that our window proxies can register actions */
405 ActionManager::init ();
407 /* The following must happen after ARDOUR::init() so that Config is set up */
409 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
412 key_editor.set_state (*ui_xml, 0);
413 session_option_editor.set_state (*ui_xml, 0);
414 speaker_config_window.set_state (*ui_xml, 0);
415 about.set_state (*ui_xml, 0);
416 add_route_dialog.set_state (*ui_xml, 0);
417 add_video_dialog.set_state (*ui_xml, 0);
418 route_params.set_state (*ui_xml, 0);
419 bundle_manager.set_state (*ui_xml, 0);
420 location_ui.set_state (*ui_xml, 0);
421 big_clock_window.set_state (*ui_xml, 0);
422 audio_port_matrix.set_state (*ui_xml, 0);
423 midi_port_matrix.set_state (*ui_xml, 0);
424 export_video_dialog.set_state (*ui_xml, 0);
427 /* Separate windows */
429 WM::Manager::instance().register_window (&key_editor);
430 WM::Manager::instance().register_window (&session_option_editor);
431 WM::Manager::instance().register_window (&speaker_config_window);
432 WM::Manager::instance().register_window (&about);
433 WM::Manager::instance().register_window (&add_route_dialog);
434 WM::Manager::instance().register_window (&add_video_dialog);
435 WM::Manager::instance().register_window (&route_params);
436 WM::Manager::instance().register_window (&audio_midi_setup);
437 WM::Manager::instance().register_window (&export_video_dialog);
438 WM::Manager::instance().register_window (&bundle_manager);
439 WM::Manager::instance().register_window (&location_ui);
440 WM::Manager::instance().register_window (&big_clock_window);
441 WM::Manager::instance().register_window (&audio_port_matrix);
442 WM::Manager::instance().register_window (&midi_port_matrix);
444 /* Trigger setting up the color scheme and loading the GTK RC file */
446 UIConfiguration::instance().load_rc_file (false);
448 _process_thread = new ProcessThread ();
449 _process_thread->init ();
451 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
456 GlobalPortMatrixWindow*
457 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
462 return new GlobalPortMatrixWindow (_session, type);
466 ARDOUR_UI::attach_to_engine ()
468 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
469 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
473 ARDOUR_UI::engine_stopped ()
475 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
476 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
477 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
478 update_sample_rate (0);
483 ARDOUR_UI::engine_running ()
485 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
486 if (first_time_engine_run) {
488 first_time_engine_run = false;
492 _session->reset_xrun_count ();
494 update_disk_space ();
496 update_xrun_count ();
497 update_sample_rate (AudioEngine::instance()->sample_rate());
498 update_timecode_format ();
499 update_peak_thread_work ();
500 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
501 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
505 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
507 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
508 /* we can't rely on the original string continuing to exist when we are called
509 again in the GUI thread, so make a copy and note that we need to
512 char *copy = strdup (reason);
513 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
517 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
518 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
520 update_sample_rate (0);
524 /* if the reason is a non-empty string, it means that the backend was shutdown
525 rather than just Ardour.
528 if (strlen (reason)) {
529 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
531 msgstr = string_compose (_("\
532 The audio backend has either been shutdown or it\n\
533 disconnected %1 because %1\n\
534 was not fast enough. Try to restart\n\
535 the audio backend and save the session."), PROGRAM_NAME);
538 MessageDialog msg (_main_window, msgstr);
539 pop_back_splash (msg);
543 free (const_cast<char*> (reason));
548 ARDOUR_UI::post_engine ()
550 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
552 #ifdef AUDIOUNIT_SUPPORT
554 if (AUPluginInfo::au_get_crashlog(au_msg)) {
555 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
556 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
557 info << au_msg << endmsg;
561 ARDOUR::init_post_engine ();
563 /* connect to important signals */
565 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
566 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
567 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
568 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
569 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
571 if (setup_windows ()) {
572 throw failed_constructor ();
575 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
576 XMLNode* n = Config->extra_xml (X_("UI"));
578 _status_bar_visibility.set_state (*n);
581 check_memory_locking();
583 /* this is the first point at which all the possible actions are
584 * available, because some of the available actions are dependent on
585 * aspects of the engine/backend.
588 if (ARDOUR_COMMAND_LINE::show_key_actions) {
591 vector<string> paths;
592 vector<string> labels;
593 vector<string> tooltips;
595 vector<Glib::RefPtr<Gtk::Action> > actions;
597 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
599 vector<string>::iterator k;
600 vector<string>::iterator p;
602 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
607 cout << *p << " => " << *k << endl;
611 halt_connection.disconnect ();
612 AudioEngine::instance()->stop ();
616 /* this being a GUI and all, we want peakfiles */
618 AudioFileSource::set_build_peakfiles (true);
619 AudioFileSource::set_build_missing_peakfiles (true);
621 /* set default clock modes */
623 primary_clock->set_mode (AudioClock::Timecode);
624 secondary_clock->set_mode (AudioClock::BBT);
626 /* start the time-of-day-clock */
629 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
630 update_wall_clock ();
631 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
636 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
637 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
638 Config->map_parameters (pc);
640 UIConfiguration::instance().map_parameters (pc);
644 ARDOUR_UI::~ARDOUR_UI ()
646 UIConfiguration::instance().save_state();
650 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
651 // don't bother at 'real' exit. the OS cleans up for us.
653 delete primary_clock;
654 delete secondary_clock;
655 delete _process_thread;
660 delete gui_object_state;
661 FastMeter::flush_pattern_cache ();
662 PixFader::flush_pattern_cache ();
666 /* Small trick to flush main-thread event pool.
667 * Other thread-pools are destroyed at pthread_exit(),
668 * but tmain thread termination is too late to trigger Pool::~Pool()
670 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.
671 delete ev->event_pool();
676 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
678 if (Splash::instance()) {
679 Splash::instance()->pop_back_for (win);
684 ARDOUR_UI::configure_timeout ()
686 if (last_configure_time == 0) {
687 /* no configure events yet */
691 /* force a gap of 0.5 seconds since the last configure event
694 if (get_microseconds() - last_configure_time < 500000) {
697 have_configure_timeout = false;
698 save_ardour_state ();
704 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
706 if (have_configure_timeout) {
707 last_configure_time = get_microseconds();
709 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
710 have_configure_timeout = true;
717 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
719 const XMLProperty* prop;
721 if ((prop = node.property ("roll")) != 0) {
722 roll_controllable->set_id (prop->value());
724 if ((prop = node.property ("stop")) != 0) {
725 stop_controllable->set_id (prop->value());
727 if ((prop = node.property ("goto-start")) != 0) {
728 goto_start_controllable->set_id (prop->value());
730 if ((prop = node.property ("goto-end")) != 0) {
731 goto_end_controllable->set_id (prop->value());
733 if ((prop = node.property ("auto-loop")) != 0) {
734 auto_loop_controllable->set_id (prop->value());
736 if ((prop = node.property ("play-selection")) != 0) {
737 play_selection_controllable->set_id (prop->value());
739 if ((prop = node.property ("rec")) != 0) {
740 rec_controllable->set_id (prop->value());
742 if ((prop = node.property ("shuttle")) != 0) {
743 shuttle_box->controllable()->set_id (prop->value());
748 ARDOUR_UI::get_transport_controllable_state ()
750 XMLNode* node = new XMLNode(X_("TransportControllables"));
753 roll_controllable->id().print (buf, sizeof (buf));
754 node->add_property (X_("roll"), buf);
755 stop_controllable->id().print (buf, sizeof (buf));
756 node->add_property (X_("stop"), buf);
757 goto_start_controllable->id().print (buf, sizeof (buf));
758 node->add_property (X_("goto_start"), buf);
759 goto_end_controllable->id().print (buf, sizeof (buf));
760 node->add_property (X_("goto_end"), buf);
761 auto_loop_controllable->id().print (buf, sizeof (buf));
762 node->add_property (X_("auto_loop"), buf);
763 play_selection_controllable->id().print (buf, sizeof (buf));
764 node->add_property (X_("play_selection"), buf);
765 rec_controllable->id().print (buf, sizeof (buf));
766 node->add_property (X_("rec"), buf);
767 shuttle_box->controllable()->id().print (buf, sizeof (buf));
768 node->add_property (X_("shuttle"), buf);
774 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
777 _session->save_state (snapshot_name);
782 ARDOUR_UI::autosave_session ()
784 if (g_main_depth() > 1) {
785 /* inside a recursive main loop,
786 give up because we may not be able to
792 if (!Config->get_periodic_safety_backups()) {
797 _session->maybe_write_autosave();
804 ARDOUR_UI::session_dirty_changed ()
811 ARDOUR_UI::update_autosave ()
813 if (_session && _session->dirty()) {
814 if (_autosave_connection.connected()) {
815 _autosave_connection.disconnect();
818 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
819 Config->get_periodic_safety_backup_interval() * 1000);
822 if (_autosave_connection.connected()) {
823 _autosave_connection.disconnect();
829 ARDOUR_UI::check_announcements ()
832 string _annc_filename;
835 _annc_filename = PROGRAM_NAME "_announcements_osx_";
836 #elif defined PLATFORM_WINDOWS
837 _annc_filename = PROGRAM_NAME "_announcements_windows_";
839 _annc_filename = PROGRAM_NAME "_announcements_linux_";
841 _annc_filename.append (VERSIONSTRING);
843 _announce_string = "";
845 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
846 FILE* fin = g_fopen (path.c_str(), "rb");
848 while (!feof (fin)) {
851 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
854 _announce_string.append (tmp, len);
859 pingback (VERSIONSTRING, path);
864 _hide_splash (gpointer arg)
866 ((ARDOUR_UI*)arg)->hide_splash();
871 ARDOUR_UI::starting ()
873 Application* app = Application::instance ();
875 bool brand_new_user = ArdourStartup::required ();
877 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
878 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
880 if (ARDOUR_COMMAND_LINE::check_announcements) {
881 check_announcements ();
886 /* we need to create this early because it may need to set the
887 * audio backend end up.
891 audio_midi_setup.get (true);
893 std::cerr << "audio-midi engine setup failed."<< std::endl;
897 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
898 nsm = new NSM_Client;
899 if (!nsm->init (nsm_url)) {
900 /* the ardour executable may have different names:
902 * waf's obj.target for distro versions: eg ardour4, ardourvst4
903 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
904 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
906 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
908 const char *process_name = g_getenv ("ARDOUR_SELF");
909 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
912 // wait for announce reply from nsm server
913 for ( i = 0; i < 5000; ++i) {
917 if (nsm->is_active()) {
922 error << _("NSM server did not announce itself") << endmsg;
925 // wait for open command from nsm server
926 for ( i = 0; i < 5000; ++i) {
929 if (nsm->client_id ()) {
935 error << _("NSM: no client ID provided") << endmsg;
939 if (_session && nsm) {
940 _session->set_nsm_state( nsm->is_active() );
942 error << _("NSM: no session created") << endmsg;
946 // nsm requires these actions disabled
947 vector<string> action_names;
948 action_names.push_back("SaveAs");
949 action_names.push_back("Rename");
950 action_names.push_back("New");
951 action_names.push_back("Open");
952 action_names.push_back("Recent");
953 action_names.push_back("Close");
955 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
956 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
958 act->set_sensitive (false);
965 error << _("NSM: initialization failed") << endmsg;
971 if (brand_new_user) {
972 _initial_verbose_plugin_scan = true;
977 _initial_verbose_plugin_scan = false;
978 switch (s.response ()) {
979 case Gtk::RESPONSE_OK:
986 #ifdef NO_PLUGIN_STATE
988 ARDOUR::RecentSessions rs;
989 ARDOUR::read_recent_sessions (rs);
991 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
993 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
995 /* already used Ardour, have sessions ... warn about plugin state */
997 ArdourDialog d (_("Free/Demo Version Warning"), true);
999 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1000 CheckButton c (_("Don't warn me about this again"));
1002 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"),
1003 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1004 _("It will not restore OR save any plugin settings"),
1005 _("If you load an existing session with plugin settings\n"
1006 "they will not be used and will be lost."),
1007 _("To get full access to updates without this limitation\n"
1008 "consider becoming a subscriber for a low cost every month.")));
1009 l.set_justify (JUSTIFY_CENTER);
1011 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1013 d.get_vbox()->pack_start (l, true, true);
1014 d.get_vbox()->pack_start (b, false, false, 12);
1015 d.get_vbox()->pack_start (c, false, false, 12);
1017 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1018 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1022 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1024 if (d.run () != RESPONSE_OK) {
1030 /* go get a session */
1032 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1034 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1035 std::cerr << "Cannot get session parameters."<< std::endl;
1042 WM::Manager::instance().show_visible ();
1044 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1045 * editor window, and we may want stuff to be hidden.
1047 _status_bar_visibility.update ();
1049 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1051 if (splash && splash->is_visible()) {
1052 // in 1 second, hide the splash screen
1053 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1056 /* all other dialogs are created conditionally */
1062 ARDOUR_UI::check_memory_locking ()
1064 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1065 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1069 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1071 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1073 struct rlimit limits;
1075 long pages, page_size;
1077 size_t pages_len=sizeof(pages);
1078 if ((page_size = getpagesize()) < 0 ||
1079 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1081 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1086 ram = (int64_t) pages * (int64_t) page_size;
1089 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1093 if (limits.rlim_cur != RLIM_INFINITY) {
1095 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1099 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1100 "This might cause %1 to run out of memory before your system "
1101 "runs out of memory. \n\n"
1102 "You can view the memory limit with 'ulimit -l', "
1103 "and it is normally controlled by %2"),
1106 X_("/etc/login.conf")
1108 X_(" /etc/security/limits.conf")
1112 msg.set_default_response (RESPONSE_OK);
1114 VBox* vbox = msg.get_vbox();
1116 CheckButton cb (_("Do not show this window again"));
1117 hbox.pack_start (cb, true, false);
1118 vbox->pack_start (hbox);
1123 pop_back_splash (msg);
1127 if (cb.get_active()) {
1128 XMLNode node (X_("no-memory-warning"));
1129 Config->add_instant_xml (node);
1134 #endif // !__APPLE__
1139 ARDOUR_UI::queue_finish ()
1141 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1145 ARDOUR_UI::idle_finish ()
1148 return false; /* do not call again */
1155 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1157 if (_session->dirty()) {
1158 vector<string> actions;
1159 actions.push_back (_("Don't quit"));
1160 actions.push_back (_("Just quit"));
1161 actions.push_back (_("Save and quit"));
1162 switch (ask_about_saving_session(actions)) {
1167 /* use the default name */
1168 if (save_state_canfail ("")) {
1169 /* failed - don't quit */
1170 MessageDialog msg (_main_window,
1171 string_compose (_("\
1172 %1 was unable to save your session.\n\n\
1173 If you still wish to quit, please use the\n\n\
1174 \"Just quit\" option."), PROGRAM_NAME));
1175 pop_back_splash(msg);
1185 second_connection.disconnect ();
1186 point_one_second_connection.disconnect ();
1187 point_zero_something_second_connection.disconnect();
1188 fps_connection.disconnect();
1191 delete ARDOUR_UI::instance()->video_timeline;
1192 ARDOUR_UI::instance()->video_timeline = NULL;
1193 stop_video_server();
1195 /* Save state before deleting the session, as that causes some
1196 windows to be destroyed before their visible state can be
1199 save_ardour_state ();
1201 close_all_dialogs ();
1204 _session->set_clean ();
1205 _session->remove_pending_capture_state ();
1210 halt_connection.disconnect ();
1211 AudioEngine::instance()->stop ();
1212 #ifdef WINDOWS_VST_SUPPORT
1213 fst_stop_threading();
1219 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1221 ArdourDialog window (_("Unsaved Session"));
1222 Gtk::HBox dhbox; // the hbox for the image and text
1223 Gtk::Label prompt_label;
1224 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1228 assert (actions.size() >= 3);
1230 window.add_button (actions[0], RESPONSE_REJECT);
1231 window.add_button (actions[1], RESPONSE_APPLY);
1232 window.add_button (actions[2], RESPONSE_ACCEPT);
1234 window.set_default_response (RESPONSE_ACCEPT);
1236 Gtk::Button noquit_button (msg);
1237 noquit_button.set_name ("EditorGTKButton");
1241 if (_session->snap_name() == _session->name()) {
1242 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?"),
1243 _session->snap_name());
1245 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?"),
1246 _session->snap_name());
1249 prompt_label.set_text (prompt);
1250 prompt_label.set_name (X_("PrompterLabel"));
1251 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1253 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1254 dhbox.set_homogeneous (false);
1255 dhbox.pack_start (*dimage, false, false, 5);
1256 dhbox.pack_start (prompt_label, true, false, 5);
1257 window.get_vbox()->pack_start (dhbox);
1259 window.set_name (_("Prompter"));
1260 window.set_modal (true);
1261 window.set_resizable (false);
1264 prompt_label.show();
1269 ResponseType r = (ResponseType) window.run();
1274 case RESPONSE_ACCEPT: // save and get out of here
1276 case RESPONSE_APPLY: // get out of here
1287 ARDOUR_UI::every_second ()
1290 update_xrun_count ();
1291 update_buffer_load ();
1292 update_disk_space ();
1293 update_timecode_format ();
1294 update_peak_thread_work ();
1296 if (nsm && nsm->is_active ()) {
1299 if (!_was_dirty && _session->dirty ()) {
1303 else if (_was_dirty && !_session->dirty ()){
1311 ARDOUR_UI::every_point_one_seconds ()
1313 // TODO get rid of this..
1314 // ShuttleControl is updated directly via TransportStateChange signal
1318 ARDOUR_UI::every_point_zero_something_seconds ()
1320 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1322 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1323 float mpeak = editor_meter->update_meters();
1324 if (mpeak > editor_meter_max_peak) {
1325 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1326 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1333 ARDOUR_UI::set_fps_timeout_connection ()
1335 unsigned int interval = 40;
1336 if (!_session) return;
1337 if (_session->timecode_frames_per_second() != 0) {
1338 /* ideally we'll use a select() to sleep and not accumulate
1339 * idle time to provide a regular periodic signal.
1340 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1341 * However, that'll require a dedicated thread and cross-thread
1342 * signals to the GUI Thread..
1344 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1345 * _session->frame_rate() / _session->nominal_frame_rate()
1346 / _session->timecode_frames_per_second()
1348 #ifdef PLATFORM_WINDOWS
1349 // the smallest windows scheduler time-slice is ~15ms.
1350 // periodic GUI timeouts shorter than that will cause
1351 // WaitForSingleObject to spinlock (100% of one CPU Core)
1352 // and gtk never enters idle mode.
1353 // also changing timeBeginPeriod(1) does not affect that in
1354 // any beneficial way, so we just limit the max rate for now.
1355 interval = std::max(30u, interval); // at most ~33Hz.
1357 interval = std::max(8u, interval); // at most 120Hz.
1360 fps_connection.disconnect();
1361 Timers::set_fps_interval (interval);
1365 ARDOUR_UI::update_sample_rate (framecnt_t)
1369 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1371 if (!AudioEngine::instance()->connected()) {
1373 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1377 framecnt_t rate = AudioEngine::instance()->sample_rate();
1380 /* no sample rate available */
1381 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1384 if (fmod (rate, 1000.0) != 0.0) {
1385 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1386 (float) rate / 1000.0f,
1387 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1389 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1391 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1395 sample_rate_label.set_markup (buf);
1399 ARDOUR_UI::update_format ()
1402 format_label.set_text ("");
1407 s << _("File:") << X_(" <span foreground=\"green\">");
1409 switch (_session->config.get_native_file_header_format ()) {
1441 switch (_session->config.get_native_file_data_format ()) {
1455 format_label.set_markup (s.str ());
1459 ARDOUR_UI::update_xrun_count ()
1463 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1464 should also be changed.
1468 const unsigned int x = _session->get_xrun_count ();
1470 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1472 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1475 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1477 xrun_label.set_markup (buf);
1478 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1482 ARDOUR_UI::update_cpu_load ()
1486 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1487 should also be changed.
1490 double const c = AudioEngine::instance()->get_dsp_load ();
1491 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1492 cpu_load_label.set_markup (buf);
1496 ARDOUR_UI::update_peak_thread_work ()
1499 const int c = SourceFactory::peak_work_queue_length ();
1501 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1502 peak_thread_work_label.set_markup (buf);
1504 peak_thread_work_label.set_markup (X_(""));
1509 ARDOUR_UI::update_buffer_load ()
1513 uint32_t const playback = _session ? _session->playback_load () : 100;
1514 uint32_t const capture = _session ? _session->capture_load () : 100;
1516 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1517 should also be changed.
1523 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1524 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1525 playback <= 5 ? X_("red") : X_("green"),
1527 capture <= 5 ? X_("red") : X_("green"),
1531 buffer_load_label.set_markup (buf);
1533 buffer_load_label.set_text ("");
1538 ARDOUR_UI::count_recenabled_streams (Route& route)
1540 Track* track = dynamic_cast<Track*>(&route);
1541 if (track && track->record_enabled()) {
1542 rec_enabled_streams += track->n_inputs().n_total();
1547 ARDOUR_UI::update_disk_space()
1549 if (_session == 0) {
1553 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1555 framecnt_t fr = _session->frame_rate();
1558 /* skip update - no SR available */
1563 /* Available space is unknown */
1564 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1565 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1566 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1568 rec_enabled_streams = 0;
1569 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1571 framecnt_t frames = opt_frames.get_value_or (0);
1573 if (rec_enabled_streams) {
1574 frames /= rec_enabled_streams;
1581 hrs = frames / (fr * 3600);
1584 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1586 frames -= hrs * fr * 3600;
1587 mins = frames / (fr * 60);
1588 frames -= mins * fr * 60;
1591 bool const low = (hrs == 0 && mins <= 30);
1595 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1596 low ? X_("red") : X_("green"),
1602 disk_space_label.set_markup (buf);
1606 ARDOUR_UI::update_timecode_format ()
1612 TimecodeSlave* tcslave;
1613 SyncSource sync_src = Config->get_sync_source();
1615 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1616 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1621 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1622 matching ? X_("green") : X_("red"),
1623 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1625 snprintf (buf, sizeof (buf), "TC: n/a");
1628 timecode_format_label.set_markup (buf);
1632 ARDOUR_UI::update_wall_clock ()
1636 static int last_min = -1;
1639 tm_now = localtime (&now);
1640 if (last_min != tm_now->tm_min) {
1642 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1643 wall_clock_label.set_text (buf);
1644 last_min = tm_now->tm_min;
1651 ARDOUR_UI::open_recent_session ()
1653 bool can_return = (_session != 0);
1655 SessionDialog recent_session_dialog;
1659 ResponseType r = (ResponseType) recent_session_dialog.run ();
1662 case RESPONSE_ACCEPT:
1666 recent_session_dialog.hide();
1673 recent_session_dialog.hide();
1677 std::string path = recent_session_dialog.session_folder();
1678 std::string state = recent_session_dialog.session_name (should_be_new);
1680 if (should_be_new == true) {
1684 _session_is_new = false;
1686 if (load_session (path, state) == 0) {
1695 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1697 if (!AudioEngine::instance()->connected()) {
1698 MessageDialog msg (parent, string_compose (
1699 _("%1 is not connected to any audio backend.\n"
1700 "You cannot open or close sessions in this condition"),
1702 pop_back_splash (msg);
1710 ARDOUR_UI::open_session ()
1712 if (!check_audioengine (_main_window)) {
1716 /* ardour sessions are folders */
1717 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1718 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1719 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1720 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1723 string session_parent_dir = Glib::path_get_dirname(_session->path());
1724 open_session_selector.set_current_folder(session_parent_dir);
1726 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1729 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1731 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1732 string default_session_folder = Config->get_default_session_parent_dir();
1733 open_session_selector.add_shortcut_folder (default_session_folder);
1735 catch (Glib::Error & e) {
1736 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1739 FileFilter session_filter;
1740 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1741 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1742 open_session_selector.add_filter (session_filter);
1743 open_session_selector.set_filter (session_filter);
1745 int response = open_session_selector.run();
1746 open_session_selector.hide ();
1748 if (response == Gtk::RESPONSE_CANCEL) {
1752 string session_path = open_session_selector.get_filename();
1756 if (session_path.length() > 0) {
1757 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1758 _session_is_new = isnew;
1759 load_session (path, name);
1766 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1767 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1769 list<boost::shared_ptr<MidiTrack> > tracks;
1771 if (_session == 0) {
1772 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1777 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1779 if (tracks.size() != how_many) {
1780 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1785 MessageDialog msg (_main_window,
1786 string_compose (_("There are insufficient ports available\n\
1787 to create a new track or bus.\n\
1788 You should save %1, exit and\n\
1789 restart with more ports."), PROGRAM_NAME));
1796 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1798 ChanCount one_midi_channel;
1799 one_midi_channel.set (DataType::MIDI, 1);
1802 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1807 ARDOUR_UI::session_add_audio_route (
1809 int32_t input_channels,
1810 int32_t output_channels,
1811 ARDOUR::TrackMode mode,
1812 RouteGroup* route_group,
1814 string const & name_template
1817 list<boost::shared_ptr<AudioTrack> > tracks;
1820 if (_session == 0) {
1821 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1827 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1829 if (tracks.size() != how_many) {
1830 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1836 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1838 if (routes.size() != how_many) {
1839 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1846 MessageDialog msg (_main_window,
1847 string_compose (_("There are insufficient ports available\n\
1848 to create a new track or bus.\n\
1849 You should save %1, exit and\n\
1850 restart with more ports."), PROGRAM_NAME));
1851 pop_back_splash (msg);
1857 ARDOUR_UI::transport_goto_start ()
1860 _session->goto_start();
1862 /* force displayed area in editor to start no matter
1863 what "follow playhead" setting is.
1867 editor->center_screen (_session->current_start_frame ());
1873 ARDOUR_UI::transport_goto_zero ()
1876 _session->request_locate (0);
1878 /* force displayed area in editor to start no matter
1879 what "follow playhead" setting is.
1883 editor->reset_x_origin (0);
1889 ARDOUR_UI::transport_goto_wallclock ()
1891 if (_session && editor) {
1898 localtime_r (&now, &tmnow);
1900 framecnt_t frame_rate = _session->frame_rate();
1902 if (frame_rate == 0) {
1903 /* no frame rate available */
1907 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1908 frames += tmnow.tm_min * (60 * frame_rate);
1909 frames += tmnow.tm_sec * frame_rate;
1911 _session->request_locate (frames, _session->transport_rolling ());
1913 /* force displayed area in editor to start no matter
1914 what "follow playhead" setting is.
1918 editor->center_screen (frames);
1924 ARDOUR_UI::transport_goto_end ()
1927 framepos_t const frame = _session->current_end_frame();
1928 _session->request_locate (frame);
1930 /* force displayed area in editor to start no matter
1931 what "follow playhead" setting is.
1935 editor->center_screen (frame);
1941 ARDOUR_UI::transport_stop ()
1947 if (_session->is_auditioning()) {
1948 _session->cancel_audition ();
1952 _session->request_stop (false, true);
1955 /** Check if any tracks are record enabled. If none are, record enable all of them.
1956 * @return true if track record-enabled status was changed, false otherwise.
1959 ARDOUR_UI::trx_record_enable_all_tracks ()
1965 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1966 bool none_record_enabled = true;
1968 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1969 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1972 if (t->record_enabled()) {
1973 none_record_enabled = false;
1978 if (none_record_enabled) {
1979 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1982 return none_record_enabled;
1986 ARDOUR_UI::transport_record (bool roll)
1989 switch (_session->record_status()) {
1990 case Session::Disabled:
1991 if (_session->ntracks() == 0) {
1992 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."));
1996 if (Profile->get_trx()) {
1997 roll = trx_record_enable_all_tracks ();
1999 _session->maybe_enable_record ();
2004 case Session::Recording:
2006 _session->request_stop();
2008 _session->disable_record (false, true);
2012 case Session::Enabled:
2013 _session->disable_record (false, true);
2019 ARDOUR_UI::transport_roll ()
2025 if (_session->is_auditioning()) {
2030 if (_session->config.get_external_sync()) {
2031 switch (Config->get_sync_source()) {
2035 /* transport controlled by the master */
2041 bool rolling = _session->transport_rolling();
2043 if (_session->get_play_loop()) {
2045 /* If loop playback is not a mode, then we should cancel
2046 it when this action is requested. If it is a mode
2047 we just leave it in place.
2050 if (!Config->get_loop_is_mode()) {
2051 /* XXX it is not possible to just leave seamless loop and keep
2052 playing at present (nov 4th 2009)
2054 if (!Config->get_seamless_loop()) {
2055 /* stop loop playback and stop rolling */
2056 _session->request_play_loop (false, true);
2057 } else if (rolling) {
2058 /* stop loop playback but keep rolling */
2059 _session->request_play_loop (false, false);
2063 } else if (_session->get_play_range () ) {
2064 /* stop playing a range if we currently are */
2065 _session->request_play_range (0, true);
2069 _session->request_transport_speed (1.0f);
2074 ARDOUR_UI::get_smart_mode() const
2076 return ( editor->get_smart_mode() );
2081 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2087 if (_session->is_auditioning()) {
2088 _session->cancel_audition ();
2092 if (_session->config.get_external_sync()) {
2093 switch (Config->get_sync_source()) {
2097 /* transport controlled by the master */
2102 bool rolling = _session->transport_rolling();
2103 bool affect_transport = true;
2105 if (rolling && roll_out_of_bounded_mode) {
2106 /* drop out of loop/range playback but leave transport rolling */
2107 if (_session->get_play_loop()) {
2108 if (_session->actively_recording()) {
2110 /* just stop using the loop, then actually stop
2113 _session->request_play_loop (false, affect_transport);
2116 if (Config->get_seamless_loop()) {
2117 /* the disk buffers contain copies of the loop - we can't
2118 just keep playing, so stop the transport. the user
2119 can restart as they wish.
2121 affect_transport = true;
2123 /* disk buffers are normal, so we can keep playing */
2124 affect_transport = false;
2126 _session->request_play_loop (false, affect_transport);
2128 } else if (_session->get_play_range ()) {
2129 affect_transport = false;
2130 _session->request_play_range (0, true);
2134 if (affect_transport) {
2136 _session->request_stop (with_abort, true);
2138 /* the only external sync condition we can be in here
2139 * would be Engine (JACK) sync, in which case we still
2143 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
2144 _session->request_play_range (&editor->get_selection().time, true);
2145 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2147 _session->request_transport_speed (1.0f);
2153 ARDOUR_UI::toggle_session_auto_loop ()
2159 Location * looploc = _session->locations()->auto_loop_location();
2165 if (_session->get_play_loop()) {
2167 /* looping enabled, our job is to disable it */
2169 _session->request_play_loop (false);
2173 /* looping not enabled, our job is to enable it.
2175 loop-is-NOT-mode: this action always starts the transport rolling.
2176 loop-IS-mode: this action simply sets the loop play mechanism, but
2177 does not start transport.
2179 if (Config->get_loop_is_mode()) {
2180 _session->request_play_loop (true, false);
2182 _session->request_play_loop (true, true);
2186 //show the loop markers
2187 looploc->set_hidden (false, this);
2191 ARDOUR_UI::transport_play_selection ()
2197 editor->play_selection ();
2201 ARDOUR_UI::transport_play_preroll ()
2206 editor->play_with_preroll ();
2210 ARDOUR_UI::transport_rewind (int option)
2212 float current_transport_speed;
2215 current_transport_speed = _session->transport_speed();
2217 if (current_transport_speed >= 0.0f) {
2220 _session->request_transport_speed (-1.0f);
2223 _session->request_transport_speed (-4.0f);
2226 _session->request_transport_speed (-0.5f);
2231 _session->request_transport_speed (current_transport_speed * 1.5f);
2237 ARDOUR_UI::transport_forward (int option)
2243 float current_transport_speed = _session->transport_speed();
2245 if (current_transport_speed <= 0.0f) {
2248 _session->request_transport_speed (1.0f);
2251 _session->request_transport_speed (4.0f);
2254 _session->request_transport_speed (0.5f);
2259 _session->request_transport_speed (current_transport_speed * 1.5f);
2264 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2270 boost::shared_ptr<Route> r;
2272 if ((r = _session->route_by_remote_id (rid)) != 0) {
2274 boost::shared_ptr<Track> t;
2276 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2277 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2283 ARDOUR_UI::map_transport_state ()
2286 auto_loop_button.unset_active_state ();
2287 play_selection_button.unset_active_state ();
2288 roll_button.unset_active_state ();
2289 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2293 shuttle_box->map_transport_state ();
2295 float sp = _session->transport_speed();
2301 if (_session->get_play_range()) {
2303 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2304 roll_button.unset_active_state ();
2305 auto_loop_button.unset_active_state ();
2307 } else if (_session->get_play_loop ()) {
2309 auto_loop_button.set_active (true);
2310 play_selection_button.set_active (false);
2311 if (Config->get_loop_is_mode()) {
2312 roll_button.set_active (true);
2314 roll_button.set_active (false);
2319 roll_button.set_active (true);
2320 play_selection_button.set_active (false);
2321 auto_loop_button.set_active (false);
2324 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2325 /* light up both roll and play-selection if they are joined */
2326 roll_button.set_active (true);
2327 play_selection_button.set_active (true);
2330 stop_button.set_active (false);
2334 stop_button.set_active (true);
2335 roll_button.set_active (false);
2336 play_selection_button.set_active (false);
2337 if (Config->get_loop_is_mode ()) {
2338 auto_loop_button.set_active (_session->get_play_loop());
2340 auto_loop_button.set_active (false);
2342 update_disk_space ();
2347 ARDOUR_UI::blink_handler (bool blink_on)
2349 transport_rec_enable_blink (blink_on);
2350 solo_blink (blink_on);
2351 sync_blink (blink_on);
2352 audition_blink (blink_on);
2353 feedback_blink (blink_on);
2354 error_blink (blink_on);
2358 ARDOUR_UI::update_clocks ()
2360 if (!_session) return;
2362 if (editor && !editor->dragging_playhead()) {
2363 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2368 ARDOUR_UI::start_clocking ()
2370 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2371 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2373 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2378 ARDOUR_UI::stop_clocking ()
2380 clock_signal_connection.disconnect ();
2384 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2388 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2390 label->set_text (buf);
2391 bar->set_fraction (fraction);
2393 /* process events, redraws, etc. */
2395 while (gtk_events_pending()) {
2396 gtk_main_iteration ();
2399 return true; /* continue with save-as */
2403 ARDOUR_UI::save_session_as ()
2409 if (!save_as_dialog) {
2410 save_as_dialog = new SaveAsDialog;
2413 save_as_dialog->set_name (_session->name());
2415 int response = save_as_dialog->run ();
2417 save_as_dialog->hide ();
2420 case Gtk::RESPONSE_OK:
2429 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2430 sa.new_name = save_as_dialog->new_name ();
2431 sa.switch_to = save_as_dialog->switch_to();
2432 sa.copy_media = save_as_dialog->copy_media();
2433 sa.copy_external = save_as_dialog->copy_external();
2434 sa.include_media = save_as_dialog->include_media ();
2436 /* Only bother with a progress dialog if we're going to copy
2437 media into the save-as target. Without that choice, this
2438 will be very fast because we're only talking about a few kB's to
2439 perhaps a couple of MB's of data.
2442 ArdourDialog progress_dialog (_("Save As"), true);
2444 if (sa.include_media && sa.copy_media) {
2447 Gtk::ProgressBar progress_bar;
2449 progress_dialog.get_vbox()->pack_start (label);
2450 progress_dialog.get_vbox()->pack_start (progress_bar);
2452 progress_bar.show ();
2454 /* this signal will be emitted from within this, the calling thread,
2455 * after every file is copied. It provides information on percentage
2456 * complete (in terms of total data to copy), the number of files
2457 * copied so far, and the total number to copy.
2462 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2464 progress_dialog.show_all ();
2465 progress_dialog.present ();
2468 if (_session->save_as (sa)) {
2470 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2474 if (!sa.include_media) {
2475 unload_session (false);
2476 load_session (sa.final_session_folder_name, sa.new_name);
2481 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2485 struct tm local_time;
2488 localtime_r (&n, &local_time);
2489 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2491 save_state (timebuf, switch_to_it);
2496 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2500 prompter.get_result (snapname);
2502 bool do_save = (snapname.length() != 0);
2505 char illegal = Session::session_name_is_legal(snapname);
2507 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2508 "snapshot names may not contain a '%1' character"), illegal));
2514 vector<std::string> p;
2515 get_state_files_in_directory (_session->session_directory().root_path(), p);
2516 vector<string> n = get_file_names_no_extension (p);
2518 if (find (n.begin(), n.end(), snapname) != n.end()) {
2520 do_save = overwrite_file_dialog (prompter,
2521 _("Confirm Snapshot Overwrite"),
2522 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2526 save_state (snapname, switch_to_it);
2536 /** Ask the user for the name of a new snapshot and then take it.
2540 ARDOUR_UI::snapshot_session (bool switch_to_it)
2542 ArdourPrompter prompter (true);
2544 prompter.set_name ("Prompter");
2545 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2547 prompter.set_title (_("Save as..."));
2548 prompter.set_prompt (_("New session name"));
2550 prompter.set_title (_("Take Snapshot"));
2551 prompter.set_prompt (_("Name of new snapshot"));
2555 prompter.set_initial_text (_session->snap_name());
2559 struct tm local_time;
2562 localtime_r (&n, &local_time);
2563 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2564 prompter.set_initial_text (timebuf);
2567 bool finished = false;
2569 switch (prompter.run()) {
2570 case RESPONSE_ACCEPT:
2572 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2583 /** Ask the user for a new session name and then rename the session to it.
2587 ARDOUR_UI::rename_session ()
2593 ArdourPrompter prompter (true);
2596 prompter.set_name ("Prompter");
2597 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2598 prompter.set_title (_("Rename Session"));
2599 prompter.set_prompt (_("New session name"));
2602 switch (prompter.run()) {
2603 case RESPONSE_ACCEPT:
2605 prompter.get_result (name);
2607 bool do_rename = (name.length() != 0);
2610 char illegal = Session::session_name_is_legal (name);
2613 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2614 "session names may not contain a '%1' character"), illegal));
2619 switch (_session->rename (name)) {
2621 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2622 msg.set_position (WIN_POS_MOUSE);
2630 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2631 msg.set_position (WIN_POS_MOUSE);
2647 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2649 if (!_session || _session->deletion_in_progress()) {
2653 XMLNode* node = new XMLNode (X_("UI"));
2655 WM::Manager::instance().add_state (*node);
2657 node->add_child_nocopy (gui_object_state->get_state());
2659 _session->add_extra_xml (*node);
2661 if (export_video_dialog) {
2662 _session->add_extra_xml (export_video_dialog->get_state());
2665 save_state_canfail (name, switch_to_it);
2669 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2674 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2679 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2684 ARDOUR_UI::primary_clock_value_changed ()
2687 _session->request_locate (primary_clock->current_time ());
2692 ARDOUR_UI::big_clock_value_changed ()
2695 _session->request_locate (big_clock->current_time ());
2700 ARDOUR_UI::secondary_clock_value_changed ()
2703 _session->request_locate (secondary_clock->current_time ());
2708 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2710 if (_session == 0) {
2714 if (_session->step_editing()) {
2718 Session::RecordState const r = _session->record_status ();
2719 bool const h = _session->have_rec_enabled_track ();
2721 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2723 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2725 rec_button.set_active_state (Gtkmm2ext::Off);
2727 } else if (r == Session::Recording && h) {
2728 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2730 rec_button.unset_active_state ();
2735 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2739 prompter.get_result (name);
2741 if (name.length()) {
2742 int failed = _session->save_template (name);
2744 if (failed == -2) { /* file already exists. */
2745 bool overwrite = overwrite_file_dialog (prompter,
2746 _("Confirm Template Overwrite"),
2747 _("A template already exists with that name. Do you want to overwrite it?"));
2750 _session->save_template (name, true);
2762 ARDOUR_UI::save_template ()
2764 ArdourPrompter prompter (true);
2766 if (!check_audioengine (_main_window)) {
2770 prompter.set_name (X_("Prompter"));
2771 prompter.set_title (_("Save Template"));
2772 prompter.set_prompt (_("Name for template:"));
2773 prompter.set_initial_text(_session->name() + _("-template"));
2774 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2776 bool finished = false;
2778 switch (prompter.run()) {
2779 case RESPONSE_ACCEPT:
2780 finished = process_save_template_prompter (prompter);
2791 ARDOUR_UI::edit_metadata ()
2793 SessionMetadataEditor dialog;
2794 dialog.set_session (_session);
2795 dialog.grab_focus ();
2800 ARDOUR_UI::import_metadata ()
2802 SessionMetadataImporter dialog;
2803 dialog.set_session (_session);
2808 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2810 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2812 MessageDialog msg (str,
2814 Gtk::MESSAGE_WARNING,
2815 Gtk::BUTTONS_YES_NO,
2819 msg.set_name (X_("OpenExistingDialog"));
2820 msg.set_title (_("Open Existing Session"));
2821 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2822 msg.set_position (Gtk::WIN_POS_CENTER);
2823 pop_back_splash (msg);
2825 switch (msg.run()) {
2834 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2836 BusProfile bus_profile;
2840 bus_profile.master_out_channels = 2;
2841 bus_profile.input_ac = AutoConnectPhysical;
2842 bus_profile.output_ac = AutoConnectMaster;
2843 bus_profile.requested_physical_in = 0; // use all available
2844 bus_profile.requested_physical_out = 0; // use all available
2848 /* get settings from advanced section of NSD */
2850 if (sd.create_master_bus()) {
2851 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2853 bus_profile.master_out_channels = 0;
2856 if (sd.connect_inputs()) {
2857 bus_profile.input_ac = AutoConnectPhysical;
2859 bus_profile.input_ac = AutoConnectOption (0);
2862 bus_profile.output_ac = AutoConnectOption (0);
2864 if (sd.connect_outputs ()) {
2865 if (sd.connect_outs_to_master()) {
2866 bus_profile.output_ac = AutoConnectMaster;
2867 } else if (sd.connect_outs_to_physical()) {
2868 bus_profile.output_ac = AutoConnectPhysical;
2872 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2873 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2876 if (build_session (session_path, session_name, bus_profile)) {
2884 ARDOUR_UI::load_from_application_api (const std::string& path)
2886 ARDOUR_COMMAND_LINE::session_name = path;
2887 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2889 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2891 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2892 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2893 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2894 * -> SessionDialog is not displayed
2897 if (_session_dialog) {
2898 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2899 std::string session_path = path;
2900 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2901 session_path = Glib::path_get_dirname (session_path);
2903 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2904 _session_dialog->set_provided_session (session_name, session_path);
2905 _session_dialog->response (RESPONSE_NONE);
2906 _session_dialog->hide();
2911 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2912 /* /path/to/foo => /path/to/foo, foo */
2913 rv = load_session (path, basename_nosuffix (path));
2915 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2916 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2919 // if load_session fails -> pop up SessionDialog.
2921 ARDOUR_COMMAND_LINE::session_name = "";
2923 if (get_session_parameters (true, false)) {
2929 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2931 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2933 string session_name;
2934 string session_path;
2935 string template_name;
2937 bool likely_new = false;
2938 bool cancel_not_quit;
2940 /* deal with any existing DIRTY session now, rather than later. don't
2941 * treat a non-dirty session this way, so that it stays visible
2942 * as we bring up the new session dialog.
2945 if (_session && ARDOUR_UI::instance()->video_timeline) {
2946 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2949 /* if there is already a session, relabel the button
2950 on the SessionDialog so that we don't Quit directly
2952 cancel_not_quit = (_session != 0);
2954 if (_session && _session->dirty()) {
2955 if (unload_session (false)) {
2956 /* unload cancelled by user */
2959 ARDOUR_COMMAND_LINE::session_name = "";
2962 if (!load_template.empty()) {
2963 should_be_new = true;
2964 template_name = load_template;
2967 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2968 session_path = ARDOUR_COMMAND_LINE::session_name;
2970 if (!session_path.empty()) {
2971 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2972 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2973 /* session/snapshot file, change path to be dir */
2974 session_path = Glib::path_get_dirname (session_path);
2979 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2981 _session_dialog = &session_dialog;
2984 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2986 /* if they named a specific statefile, use it, otherwise they are
2987 just giving a session folder, and we want to use it as is
2988 to find the session.
2991 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2993 if (suffix != string::npos) {
2994 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2995 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2996 session_name = Glib::path_get_basename (session_name);
2998 session_path = ARDOUR_COMMAND_LINE::session_name;
2999 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3004 session_dialog.clear_given ();
3007 if (should_be_new || session_name.empty()) {
3008 /* need the dialog to get info from user */
3010 cerr << "run dialog\n";
3012 switch (session_dialog.run()) {
3013 case RESPONSE_ACCEPT:
3016 /* this is used for async * app->ShouldLoad(). */
3017 continue; // while loop
3020 if (quit_on_cancel) {
3021 // JE - Currently (July 2014) this section can only get reached if the
3022 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3023 // point does NOT indicate an abnormal termination). Therefore, let's
3024 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3026 pthread_cancel_all ();
3034 session_dialog.hide ();
3037 /* if we run the startup dialog again, offer more than just "new session" */
3039 should_be_new = false;
3041 session_name = session_dialog.session_name (likely_new);
3042 session_path = session_dialog.session_folder ();
3048 string::size_type suffix = session_name.find (statefile_suffix);
3050 if (suffix != string::npos) {
3051 session_name = session_name.substr (0, suffix);
3054 /* this shouldn't happen, but we catch it just in case it does */
3056 if (session_name.empty()) {
3060 if (session_dialog.use_session_template()) {
3061 template_name = session_dialog.session_template_name();
3062 _session_is_new = true;
3065 if (session_name[0] == G_DIR_SEPARATOR ||
3066 #ifdef PLATFORM_WINDOWS
3067 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3069 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3070 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3075 /* absolute path or cwd-relative path specified for session name: infer session folder
3076 from what was given.
3079 session_path = Glib::path_get_dirname (session_name);
3080 session_name = Glib::path_get_basename (session_name);
3084 session_path = session_dialog.session_folder();
3086 char illegal = Session::session_name_is_legal (session_name);
3089 MessageDialog msg (session_dialog,
3090 string_compose (_("To ensure compatibility with various systems\n"
3091 "session names may not contain a '%1' character"),
3094 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3099 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3102 if (likely_new && !nsm) {
3104 std::string existing = Glib::build_filename (session_path, session_name);
3106 if (!ask_about_loading_existing_session (existing)) {
3107 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3112 _session_is_new = false;
3117 pop_back_splash (session_dialog);
3118 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3120 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3124 char illegal = Session::session_name_is_legal(session_name);
3127 pop_back_splash (session_dialog);
3128 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3129 "session names may not contain a '%1' character"), illegal));
3131 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3135 _session_is_new = true;
3138 if (likely_new && template_name.empty()) {
3140 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3144 ret = load_session (session_path, session_name, template_name);
3147 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3151 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3152 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3156 /* clear this to avoid endless attempts to load the
3160 ARDOUR_COMMAND_LINE::session_name = "";
3164 _session_dialog = NULL;
3170 ARDOUR_UI::close_session()
3172 if (!check_audioengine (_main_window)) {
3176 if (unload_session (true)) {
3180 ARDOUR_COMMAND_LINE::session_name = "";
3182 if (get_session_parameters (true, false)) {
3187 /** @param snap_name Snapshot name (without .ardour suffix).
3188 * @return -2 if the load failed because we are not connected to the AudioEngine.
3191 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3193 Session *new_session;
3198 unload_status = unload_session ();
3200 if (unload_status < 0) {
3202 } else if (unload_status > 0) {
3208 session_loaded = false;
3210 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3213 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3216 /* this one is special */
3218 catch (AudioEngine::PortRegistrationFailure& err) {
3220 MessageDialog msg (err.what(),
3223 Gtk::BUTTONS_CLOSE);
3225 msg.set_title (_("Port Registration Error"));
3226 msg.set_secondary_text (_("Click the Close button to try again."));
3227 msg.set_position (Gtk::WIN_POS_CENTER);
3228 pop_back_splash (msg);
3231 int response = msg.run ();
3236 case RESPONSE_CANCEL:
3243 catch (SessionException e) {
3244 MessageDialog msg (string_compose(
3245 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3246 path, snap_name, e.what()),
3251 msg.set_title (_("Loading Error"));
3252 msg.set_position (Gtk::WIN_POS_CENTER);
3253 pop_back_splash (msg);
3265 MessageDialog msg (string_compose(
3266 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3272 msg.set_title (_("Loading Error"));
3273 msg.set_position (Gtk::WIN_POS_CENTER);
3274 pop_back_splash (msg);
3286 list<string> const u = new_session->unknown_processors ();
3288 MissingPluginDialog d (_session, u);
3293 if (!new_session->writable()) {
3294 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3299 msg.set_title (_("Read-only Session"));
3300 msg.set_position (Gtk::WIN_POS_CENTER);
3301 pop_back_splash (msg);
3308 /* Now the session been created, add the transport controls */
3309 new_session->add_controllable(roll_controllable);
3310 new_session->add_controllable(stop_controllable);
3311 new_session->add_controllable(goto_start_controllable);
3312 new_session->add_controllable(goto_end_controllable);
3313 new_session->add_controllable(auto_loop_controllable);
3314 new_session->add_controllable(play_selection_controllable);
3315 new_session->add_controllable(rec_controllable);
3317 set_session (new_session);
3319 session_loaded = true;
3322 _session->set_clean ();
3325 #ifdef WINDOWS_VST_SUPPORT
3326 fst_stop_threading();
3330 Timers::TimerSuspender t;
3334 #ifdef WINDOWS_VST_SUPPORT
3335 fst_start_threading();
3344 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3346 Session *new_session;
3349 session_loaded = false;
3350 x = unload_session ();
3358 _session_is_new = true;
3361 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3364 catch (SessionException e) {
3366 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3367 msg.set_title (_("Loading Error"));
3368 msg.set_position (Gtk::WIN_POS_CENTER);
3369 pop_back_splash (msg);
3375 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3376 msg.set_title (_("Loading Error"));
3377 msg.set_position (Gtk::WIN_POS_CENTER);
3378 pop_back_splash (msg);
3383 /* Give the new session the default GUI state, if such things exist */
3386 n = Config->instant_xml (X_("Editor"));
3388 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3389 new_session->add_instant_xml (*n, false);
3391 n = Config->instant_xml (X_("Mixer"));
3393 new_session->add_instant_xml (*n, false);
3396 /* Put the playhead at 0 and scroll fully left */
3397 n = new_session->instant_xml (X_("Editor"));
3399 n->add_property (X_("playhead"), X_("0"));
3400 n->add_property (X_("left-frame"), X_("0"));
3403 set_session (new_session);
3405 session_loaded = true;
3407 new_session->save_state(new_session->name());
3413 ARDOUR_UI::launch_chat ()
3415 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3417 dialog.set_title (_("About the Chat"));
3418 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."));
3420 switch (dialog.run()) {
3423 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3424 #elif defined PLATFORM_WINDOWS
3425 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3427 open_uri("http://webchat.freenode.net/?channels=ardour");
3436 ARDOUR_UI::launch_manual ()
3438 PBD::open_uri (Config->get_tutorial_manual_url());
3442 ARDOUR_UI::launch_reference ()
3444 PBD::open_uri (Config->get_reference_manual_url());
3448 ARDOUR_UI::launch_tracker ()
3450 PBD::open_uri ("http://tracker.ardour.org");
3454 ARDOUR_UI::launch_subscribe ()
3456 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3460 ARDOUR_UI::launch_cheat_sheet ()
3463 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3465 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3470 ARDOUR_UI::launch_website ()
3472 PBD::open_uri ("http://ardour.org");
3476 ARDOUR_UI::launch_website_dev ()
3478 PBD::open_uri ("http://ardour.org/development.html");
3482 ARDOUR_UI::launch_forums ()
3484 PBD::open_uri ("https://community.ardour.org/forums");
3488 ARDOUR_UI::launch_howto_report ()
3490 PBD::open_uri ("http://ardour.org/reporting_bugs");
3494 ARDOUR_UI::loading_message (const std::string& msg)
3496 if (ARDOUR_COMMAND_LINE::no_splash) {
3504 splash->message (msg);
3508 ARDOUR_UI::show_splash ()
3512 splash = new Splash;
3522 ARDOUR_UI::hide_splash ()
3529 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3533 removed = rep.paths.size();
3536 MessageDialog msgd (_main_window,
3537 _("No files were ready for clean-up"),
3541 msgd.set_title (_("Clean-up"));
3542 msgd.set_secondary_text (_("If this seems suprising, \n\
3543 check for any existing snapshots.\n\
3544 These may still include regions that\n\
3545 require some unused files to continue to exist."));
3551 ArdourDialog results (_("Clean-up"), true, false);
3553 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3554 CleanupResultsModelColumns() {
3558 Gtk::TreeModelColumn<std::string> visible_name;
3559 Gtk::TreeModelColumn<std::string> fullpath;
3563 CleanupResultsModelColumns results_columns;
3564 Glib::RefPtr<Gtk::ListStore> results_model;
3565 Gtk::TreeView results_display;
3567 results_model = ListStore::create (results_columns);
3568 results_display.set_model (results_model);
3569 results_display.append_column (list_title, results_columns.visible_name);
3571 results_display.set_name ("CleanupResultsList");
3572 results_display.set_headers_visible (true);
3573 results_display.set_headers_clickable (false);
3574 results_display.set_reorderable (false);
3576 Gtk::ScrolledWindow list_scroller;
3579 Gtk::HBox dhbox; // the hbox for the image and text
3580 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3581 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3583 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3585 const string dead_directory = _session->session_directory().dead_path();
3588 %1 - number of files removed
3589 %2 - location of "dead"
3590 %3 - size of files affected
3591 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3594 const char* bprefix;
3595 double space_adjusted = 0;
3597 if (rep.space < 1000) {
3599 space_adjusted = rep.space;
3600 } else if (rep.space < 1000000) {
3601 bprefix = _("kilo");
3602 space_adjusted = floorf((float)rep.space / 1000.0);
3603 } else if (rep.space < 1000000 * 1000) {
3604 bprefix = _("mega");
3605 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3607 bprefix = _("giga");
3608 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3612 txt.set_markup (string_compose (P_("\
3613 The following file was deleted from %2,\n\
3614 releasing %3 %4bytes of disk space", "\
3615 The following %1 files were deleted from %2,\n\
3616 releasing %3 %4bytes of disk space", removed),
3617 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3619 txt.set_markup (string_compose (P_("\
3620 The following file was not in use and \n\
3621 has been moved to: %2\n\n\
3622 After a restart of %5\n\n\
3623 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3624 will release an additional %3 %4bytes of disk space.\n", "\
3625 The following %1 files were not in use and \n\
3626 have been moved to: %2\n\n\
3627 After a restart of %5\n\n\
3628 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3629 will release an additional %3 %4bytes of disk space.\n", removed),
3630 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3633 dhbox.pack_start (*dimage, true, false, 5);
3634 dhbox.pack_start (txt, true, false, 5);
3636 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3637 TreeModel::Row row = *(results_model->append());
3638 row[results_columns.visible_name] = *i;
3639 row[results_columns.fullpath] = *i;
3642 list_scroller.add (results_display);
3643 list_scroller.set_size_request (-1, 150);
3644 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3646 dvbox.pack_start (dhbox, true, false, 5);
3647 dvbox.pack_start (list_scroller, true, false, 5);
3648 ddhbox.pack_start (dvbox, true, false, 5);
3650 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3651 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3652 results.set_default_response (RESPONSE_CLOSE);
3653 results.set_position (Gtk::WIN_POS_MOUSE);
3655 results_display.show();
3656 list_scroller.show();
3663 //results.get_vbox()->show();
3664 results.set_resizable (false);
3671 ARDOUR_UI::cleanup ()
3673 if (_session == 0) {
3674 /* shouldn't happen: menu item is insensitive */
3679 MessageDialog checker (_("Are you sure you want to clean-up?"),
3681 Gtk::MESSAGE_QUESTION,
3684 checker.set_title (_("Clean-up"));
3686 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3687 ALL undo/redo information will be lost if you clean-up.\n\
3688 Clean-up will move all unused files to a \"dead\" location."));
3690 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3691 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3692 checker.set_default_response (RESPONSE_CANCEL);
3694 checker.set_name (_("CleanupDialog"));
3695 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3696 checker.set_position (Gtk::WIN_POS_MOUSE);
3698 switch (checker.run()) {
3699 case RESPONSE_ACCEPT:
3705 ARDOUR::CleanupReport rep;
3707 editor->prepare_for_cleanup ();
3709 /* do not allow flush until a session is reloaded */
3711 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3713 act->set_sensitive (false);
3716 if (_session->cleanup_sources (rep)) {
3717 editor->finish_cleanup ();
3721 editor->finish_cleanup ();
3724 display_cleanup_results (rep, _("Cleaned Files"), false);
3728 ARDOUR_UI::flush_trash ()
3730 if (_session == 0) {
3731 /* shouldn't happen: menu item is insensitive */
3735 ARDOUR::CleanupReport rep;
3737 if (_session->cleanup_trash_sources (rep)) {
3741 display_cleanup_results (rep, _("deleted file"), true);
3745 ARDOUR_UI::cleanup_peakfiles ()
3747 if (_session == 0) {
3748 /* shouldn't happen: menu item is insensitive */
3752 if (! _session->can_cleanup_peakfiles ()) {
3756 // get all region-views in this session
3758 TrackViewList empty;
3760 editor->get_regions_after(rs, (framepos_t) 0, empty);
3761 std::list<RegionView*> views = rs.by_layer();
3763 // remove displayed audio-region-views waveforms
3764 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3765 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3766 if (!arv) { continue ; }
3767 arv->delete_waves();
3770 // cleanup peak files:
3771 // - stop pending peakfile threads
3772 // - close peakfiles if any
3773 // - remove peak dir in session
3774 // - setup peakfiles (background thread)
3775 _session->cleanup_peakfiles ();
3777 // re-add waves to ARV
3778 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3779 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3780 if (!arv) { continue ; }
3781 arv->create_waves();
3786 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3788 uint32_t order_hint = UINT32_MAX;
3790 if (editor->get_selection().tracks.empty()) {
3795 we want the new routes to have their order keys set starting from
3796 the highest order key in the selection + 1 (if available).
3799 if (place == AddRouteDialog::AfterSelection) {
3800 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3802 order_hint = rtav->route()->order_key();
3805 } else if (place == AddRouteDialog::BeforeSelection) {
3806 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3808 order_hint = rtav->route()->order_key();
3810 } else if (place == AddRouteDialog::First) {
3813 /* leave order_hint at UINT32_MAX */
3816 if (order_hint == UINT32_MAX) {
3817 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3818 * not setting an order hint will place new routes last.
3823 _session->set_order_hint (order_hint);
3825 /* create a gap in the existing route order keys to accomodate new routes.*/
3826 boost::shared_ptr <RouteList> rd = _session->get_routes();
3827 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3828 boost::shared_ptr<Route> rt (*ri);
3830 if (rt->is_monitor()) {
3834 if (rt->order_key () >= order_hint) {
3835 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3841 ARDOUR_UI::start_duplicate_routes ()
3843 if (!duplicate_routes_dialog) {
3844 duplicate_routes_dialog = new DuplicateRouteDialog;
3847 if (duplicate_routes_dialog->restart (_session)) {
3851 duplicate_routes_dialog->present ();
3855 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3863 if (add_route_dialog->is_visible()) {
3864 /* we're already doing this */
3868 ResponseType r = (ResponseType) add_route_dialog->run ();
3870 add_route_dialog->hide();
3873 case RESPONSE_ACCEPT:
3880 if ((count = add_route_dialog->count()) <= 0) {
3884 setup_order_hint(add_route_dialog->insert_at());
3886 string template_path = add_route_dialog->track_template();
3887 DisplaySuspender ds;
3889 if (!template_path.empty()) {
3890 if (add_route_dialog->name_template_is_default()) {
3891 _session->new_route_from_template (count, template_path, string());
3893 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3898 ChanCount input_chan= add_route_dialog->channels ();
3899 ChanCount output_chan;
3900 string name_template = add_route_dialog->name_template ();
3901 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3902 RouteGroup* route_group = add_route_dialog->route_group ();
3903 AutoConnectOption oac = Config->get_output_auto_connect();
3905 if (oac & AutoConnectMaster) {
3906 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3907 output_chan.set (DataType::MIDI, 0);
3909 output_chan = input_chan;
3912 /* XXX do something with name template */
3914 switch (add_route_dialog->type_wanted()) {
3915 case AddRouteDialog::AudioTrack:
3916 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3918 case AddRouteDialog::MidiTrack:
3919 session_add_midi_track (route_group, count, name_template, instrument);
3921 case AddRouteDialog::MixedTrack:
3922 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3924 case AddRouteDialog::AudioBus:
3925 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3931 ARDOUR_UI::stop_video_server (bool ask_confirm)
3933 if (!video_server_process && ask_confirm) {
3934 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3936 if (video_server_process) {
3938 ArdourDialog confirm (_("Stop Video-Server"), true);
3939 Label m (_("Do you really want to stop the Video Server?"));
3940 confirm.get_vbox()->pack_start (m, true, true);
3941 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3942 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3943 confirm.show_all ();
3944 if (confirm.run() == RESPONSE_CANCEL) {
3948 delete video_server_process;
3949 video_server_process =0;
3954 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3956 ARDOUR_UI::start_video_server( float_window, true);
3960 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3966 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3967 if (video_server_process) {
3968 popup_error(_("The Video Server is already started."));
3970 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3976 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3978 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3980 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3982 video_server_dialog->set_transient_for (*float_window);
3985 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3986 video_server_dialog->hide();
3988 ResponseType r = (ResponseType) video_server_dialog->run ();
3989 video_server_dialog->hide();
3990 if (r != RESPONSE_ACCEPT) { return false; }
3991 if (video_server_dialog->show_again()) {
3992 Config->set_show_video_server_dialog(false);
3996 std::string icsd_exec = video_server_dialog->get_exec_path();
3997 std::string icsd_docroot = video_server_dialog->get_docroot();
3998 if (icsd_docroot.empty()) {
3999 #ifndef PLATFORM_WINDOWS
4000 icsd_docroot = X_("/");
4002 icsd_docroot = X_("C:\\");
4007 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4008 warning << _("Specified docroot is not an existing directory.") << endmsg;
4011 #ifndef PLATFORM_WINDOWS
4012 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4013 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4014 warning << _("Given Video Server is not an executable file.") << endmsg;
4018 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4019 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4020 warning << _("Given Video Server is not an executable file.") << endmsg;
4026 argp=(char**) calloc(9,sizeof(char*));
4027 argp[0] = strdup(icsd_exec.c_str());
4028 argp[1] = strdup("-P");
4029 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4030 argp[3] = strdup("-p");
4031 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4032 argp[5] = strdup("-C");
4033 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4034 argp[7] = strdup(icsd_docroot.c_str());
4036 stop_video_server();
4038 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4039 Config->set_video_advanced_setup(false);
4041 std::ostringstream osstream;
4042 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4043 Config->set_video_server_url(osstream.str());
4044 Config->set_video_server_docroot(icsd_docroot);
4045 Config->set_video_advanced_setup(true);
4048 if (video_server_process) {
4049 delete video_server_process;
4052 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4053 if (video_server_process->start()) {
4054 warning << _("Cannot launch the video-server") << endmsg;
4057 int timeout = 120; // 6 sec
4058 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4059 Glib::usleep (50000);
4061 if (--timeout <= 0 || !video_server_process->is_running()) break;
4064 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4066 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4067 delete video_server_process;
4068 video_server_process = 0;
4076 ARDOUR_UI::add_video (Gtk::Window* float_window)
4082 if (!start_video_server(float_window, false)) {
4083 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4088 add_video_dialog->set_transient_for (*float_window);
4091 if (add_video_dialog->is_visible()) {
4092 /* we're already doing this */
4096 ResponseType r = (ResponseType) add_video_dialog->run ();
4097 add_video_dialog->hide();
4098 if (r != RESPONSE_ACCEPT) { return; }
4100 bool local_file, orig_local_file;
4101 std::string path = add_video_dialog->file_name(local_file);
4103 std::string orig_path = path;
4104 orig_local_file = local_file;
4106 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4108 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4109 warning << string_compose(_("could not open %1"), path) << endmsg;
4112 if (!local_file && path.length() == 0) {
4113 warning << _("no video-file selected") << endmsg;
4117 std::string audio_from_video;
4118 bool detect_ltc = false;
4120 switch (add_video_dialog->import_option()) {
4121 case VTL_IMPORT_TRANSCODE:
4123 TranscodeVideoDialog *transcode_video_dialog;
4124 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4125 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4126 transcode_video_dialog->hide();
4127 if (r != RESPONSE_ACCEPT) {
4128 delete transcode_video_dialog;
4132 audio_from_video = transcode_video_dialog->get_audiofile();
4134 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4137 else if (!audio_from_video.empty()) {
4138 editor->embed_audio_from_video(
4140 video_timeline->get_offset(),
4141 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4144 switch (transcode_video_dialog->import_option()) {
4145 case VTL_IMPORT_TRANSCODED:
4146 path = transcode_video_dialog->get_filename();
4149 case VTL_IMPORT_REFERENCE:
4152 delete transcode_video_dialog;
4155 delete transcode_video_dialog;
4159 case VTL_IMPORT_NONE:
4163 /* strip _session->session_directory().video_path() from video file if possible */
4164 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4165 path=path.substr(_session->session_directory().video_path().size());
4166 if (path.at(0) == G_DIR_SEPARATOR) {
4167 path=path.substr(1);
4171 video_timeline->set_update_session_fps(auto_set_session_fps);
4173 if (video_timeline->video_file_info(path, local_file)) {
4174 XMLNode* node = new XMLNode(X_("Videotimeline"));
4175 node->add_property (X_("Filename"), path);
4176 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4177 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4178 if (orig_local_file) {
4179 node->add_property (X_("OriginalVideoFile"), orig_path);
4181 node->remove_property (X_("OriginalVideoFile"));
4183 _session->add_extra_xml (*node);
4184 _session->set_dirty ();
4186 if (!audio_from_video.empty() && detect_ltc) {
4187 std::vector<LTCFileReader::LTCMap> ltc_seq;
4190 /* TODO ask user about TV standard (LTC alignment if any) */
4191 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4192 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4194 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4196 /* TODO seek near end of file, and read LTC until end.
4197 * if it fails to find any LTC frames, scan complete file
4199 * calculate drift of LTC compared to video-duration,
4200 * ask user for reference (timecode from start/mid/end)
4203 // LTCFileReader will have written error messages
4206 ::g_unlink(audio_from_video.c_str());
4208 if (ltc_seq.size() == 0) {
4209 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4211 /* the very first TC in the file is somteimes not aligned properly */
4212 int i = ltc_seq.size() -1;
4213 ARDOUR::frameoffset_t video_start_offset =
4214 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4215 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4216 video_timeline->set_offset(video_start_offset);
4220 _session->maybe_update_session_range(
4221 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4222 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4225 if (add_video_dialog->launch_xjadeo() && local_file) {
4226 editor->set_xjadeo_sensitive(true);
4227 editor->toggle_xjadeo_proc(1);
4229 editor->toggle_xjadeo_proc(0);
4231 editor->toggle_ruler_video(true);
4236 ARDOUR_UI::remove_video ()
4238 video_timeline->close_session();
4239 editor->toggle_ruler_video(false);
4242 video_timeline->set_offset_locked(false);
4243 video_timeline->set_offset(0);
4245 /* delete session state */
4246 XMLNode* node = new XMLNode(X_("Videotimeline"));
4247 _session->add_extra_xml(*node);
4248 node = new XMLNode(X_("Videomonitor"));
4249 _session->add_extra_xml(*node);
4250 node = new XMLNode(X_("Videoexport"));
4251 _session->add_extra_xml(*node);
4252 stop_video_server();
4256 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4258 if (localcacheonly) {
4259 video_timeline->vmon_update();
4261 video_timeline->flush_cache();
4263 editor->queue_visual_videotimeline_update();
4267 ARDOUR_UI::export_video (bool range)
4269 if (ARDOUR::Config->get_show_video_export_info()) {
4270 ExportVideoInfobox infobox (_session);
4271 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4272 if (infobox.show_again()) {
4273 ARDOUR::Config->set_show_video_export_info(false);
4276 case GTK_RESPONSE_YES:
4277 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4283 export_video_dialog->set_session (_session);
4284 export_video_dialog->apply_state(editor->get_selection().time, range);
4285 export_video_dialog->run ();
4286 export_video_dialog->hide ();
4290 ARDOUR_UI::mixer_settings () const
4295 node = _session->instant_xml(X_("Mixer"));
4297 node = Config->instant_xml(X_("Mixer"));
4301 node = new XMLNode (X_("Mixer"));
4308 ARDOUR_UI::main_window_settings () const
4313 node = _session->instant_xml(X_("Main"));
4315 node = Config->instant_xml(X_("Main"));
4319 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4320 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4325 node = new XMLNode (X_("Main"));
4332 ARDOUR_UI::editor_settings () const
4337 node = _session->instant_xml(X_("Editor"));
4339 node = Config->instant_xml(X_("Editor"));
4343 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4344 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4349 node = new XMLNode (X_("Editor"));
4356 ARDOUR_UI::keyboard_settings () const
4360 node = Config->extra_xml(X_("Keyboard"));
4363 node = new XMLNode (X_("Keyboard"));
4370 ARDOUR_UI::create_xrun_marker (framepos_t where)
4373 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4374 _session->locations()->add (location);
4379 ARDOUR_UI::halt_on_xrun_message ()
4381 cerr << "HALT on xrun\n";
4382 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4387 ARDOUR_UI::xrun_handler (framepos_t where)
4393 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4395 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4396 create_xrun_marker(where);
4399 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4400 halt_on_xrun_message ();
4405 ARDOUR_UI::disk_overrun_handler ()
4407 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4409 if (!have_disk_speed_dialog_displayed) {
4410 have_disk_speed_dialog_displayed = true;
4411 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4412 The disk system on your computer\n\
4413 was not able to keep up with %1.\n\
4415 Specifically, it failed to write data to disk\n\
4416 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4417 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4423 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4424 static MessageDialog *scan_dlg = NULL;
4425 static ProgressBar *scan_pbar = NULL;
4426 static HBox *scan_tbox = NULL;
4427 static Gtk::Button *scan_timeout_button;
4430 ARDOUR_UI::cancel_plugin_scan ()
4432 PluginManager::instance().cancel_plugin_scan();
4436 ARDOUR_UI::cancel_plugin_timeout ()
4438 PluginManager::instance().cancel_plugin_timeout();
4439 scan_timeout_button->set_sensitive (false);
4443 ARDOUR_UI::plugin_scan_timeout (int timeout)
4445 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4449 scan_pbar->set_sensitive (false);
4450 scan_timeout_button->set_sensitive (true);
4451 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4454 scan_pbar->set_sensitive (false);
4455 scan_timeout_button->set_sensitive (false);
4461 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4463 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4467 const bool cancelled = PluginManager::instance().cancelled();
4468 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4469 if (cancelled && scan_dlg->is_mapped()) {
4474 if (cancelled || !can_cancel) {
4479 static Gtk::Button *cancel_button;
4481 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4482 VBox* vbox = scan_dlg->get_vbox();
4483 vbox->set_size_request(400,-1);
4484 scan_dlg->set_title (_("Scanning for plugins"));
4486 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4487 cancel_button->set_name ("EditorGTKButton");
4488 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4489 cancel_button->show();
4491 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4493 scan_tbox = manage( new HBox() );
4495 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4496 scan_timeout_button->set_name ("EditorGTKButton");
4497 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4498 scan_timeout_button->show();
4500 scan_pbar = manage(new ProgressBar());
4501 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4502 scan_pbar->set_text(_("Scan Timeout"));
4505 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4506 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4508 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4511 assert(scan_dlg && scan_tbox && cancel_button);
4513 if (type == X_("closeme")) {
4517 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4520 if (!can_cancel || !cancelled) {
4521 scan_timeout_button->set_sensitive(false);
4523 cancel_button->set_sensitive(can_cancel && !cancelled);
4529 ARDOUR_UI::gui_idle_handler ()
4532 /* due to idle calls, gtk_events_pending() may always return true */
4533 while (gtk_events_pending() && --timeout) {
4534 gtk_main_iteration ();
4539 ARDOUR_UI::disk_underrun_handler ()
4541 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4543 if (!have_disk_speed_dialog_displayed) {
4544 have_disk_speed_dialog_displayed = true;
4545 MessageDialog* msg = new MessageDialog (
4546 _main_window, string_compose (_("The disk system on your computer\n\
4547 was not able to keep up with %1.\n\
4549 Specifically, it failed to read data from disk\n\
4550 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4551 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4557 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4559 have_disk_speed_dialog_displayed = false;
4564 ARDOUR_UI::session_dialog (std::string msg)
4566 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4570 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4577 ARDOUR_UI::pending_state_dialog ()
4579 HBox* hbox = manage (new HBox());
4580 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4581 ArdourDialog dialog (_("Crash Recovery"), true);
4582 Label message (string_compose (_("\
4583 This session appears to have been in the\n\
4584 middle of recording when %1 or\n\
4585 the computer was shutdown.\n\
4587 %1 can recover any captured audio for\n\
4588 you, or it can ignore it. Please decide\n\
4589 what you would like to do.\n"), PROGRAM_NAME));
4590 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4591 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4592 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4593 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4594 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4595 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4596 dialog.set_default_response (RESPONSE_ACCEPT);
4597 dialog.set_position (WIN_POS_CENTER);
4602 switch (dialog.run ()) {
4603 case RESPONSE_ACCEPT:
4611 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4613 HBox* hbox = new HBox();
4614 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4615 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4616 Label message (string_compose (_("\
4617 This session was created with a sample rate of %1 Hz, but\n\
4618 %2 is currently running at %3 Hz. If you load this session,\n\
4619 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4621 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4622 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4623 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4624 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4625 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4626 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4627 dialog.set_default_response (RESPONSE_ACCEPT);
4628 dialog.set_position (WIN_POS_CENTER);
4633 switch (dialog.run()) {
4634 case RESPONSE_ACCEPT:
4644 ARDOUR_UI::use_config ()
4646 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4648 set_transport_controllable_state (*node);
4653 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4655 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4656 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4658 primary_clock->set (pos);
4661 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4662 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4664 secondary_clock->set (pos);
4667 if (big_clock_window) {
4668 big_clock->set (pos);
4670 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4674 ARDOUR_UI::step_edit_status_change (bool yn)
4676 // XXX should really store pre-step edit status of things
4677 // we make insensitive
4680 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4681 rec_button.set_sensitive (false);
4683 rec_button.unset_active_state ();;
4684 rec_button.set_sensitive (true);
4689 ARDOUR_UI::record_state_changed ()
4691 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4693 if (!_session || !big_clock_window) {
4694 /* why bother - the clock isn't visible */
4698 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4699 big_clock->set_active (true);
4701 big_clock->set_active (false);
4706 ARDOUR_UI::first_idle ()
4709 _session->allow_auto_play (true);
4713 editor->first_idle();
4716 Keyboard::set_can_save_keybindings (true);
4721 ARDOUR_UI::store_clock_modes ()
4723 XMLNode* node = new XMLNode(X_("ClockModes"));
4725 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4726 XMLNode* child = new XMLNode (X_("Clock"));
4728 child->add_property (X_("name"), (*x)->name());
4729 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4730 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4732 node->add_child_nocopy (*child);
4735 _session->add_extra_xml (*node);
4736 _session->set_dirty ();
4739 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4740 : Controllable (name), ui (u), type(tp)
4746 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4749 /* do nothing: these are radio-style actions */
4753 const char *action = 0;
4757 action = X_("Roll");
4760 action = X_("Stop");
4763 action = X_("GotoStart");
4766 action = X_("GotoEnd");
4769 action = X_("Loop");
4772 action = X_("PlaySelection");
4775 action = X_("Record");
4785 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4793 ARDOUR_UI::TransportControllable::get_value (void) const
4820 ARDOUR_UI::setup_profile ()
4822 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4823 Profile->set_small_screen ();
4826 if (g_getenv ("TRX")) {
4827 Profile->set_trx ();
4830 if (g_getenv ("MIXBUS")) {
4831 Profile->set_mixbus ();
4836 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4838 MissingFileDialog dialog (s, str, type);
4843 int result = dialog.run ();
4850 return 1; // quit entire session load
4853 result = dialog.get_action ();
4859 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4861 AmbiguousFileDialog dialog (file, hits);
4868 return dialog.get_which ();
4871 /** Allocate our thread-local buffers */
4873 ARDOUR_UI::get_process_buffers ()
4875 _process_thread->get_buffers ();
4878 /** Drop our thread-local buffers */
4880 ARDOUR_UI::drop_process_buffers ()
4882 _process_thread->drop_buffers ();
4886 ARDOUR_UI::feedback_detected ()
4888 _feedback_exists = true;
4892 ARDOUR_UI::successful_graph_sort ()
4894 _feedback_exists = false;
4898 ARDOUR_UI::midi_panic ()
4901 _session->midi_panic();
4906 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4908 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4909 const char* end_big = "</span>";
4910 const char* start_mono = "<tt>";
4911 const char* end_mono = "</tt>";
4913 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4914 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4915 "From now on, use the -2000 version with older versions of %3"),
4916 xml_path, backup_path, PROGRAM_NAME,
4918 start_mono, end_mono), true);
4925 ARDOUR_UI::reset_peak_display ()
4927 if (!_session || !_session->master_out() || !editor_meter) return;
4928 editor_meter->clear_meters();
4929 editor_meter_max_peak = -INFINITY;
4930 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4934 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4936 if (!_session || !_session->master_out()) return;
4937 if (group == _session->master_out()->route_group()) {
4938 reset_peak_display ();
4943 ARDOUR_UI::reset_route_peak_display (Route* route)
4945 if (!_session || !_session->master_out()) return;
4946 if (_session->master_out().get() == route) {
4947 reset_peak_display ();
4952 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4954 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4955 audio_midi_setup->set_position (WIN_POS_CENTER);
4960 response = audio_midi_setup->run();
4962 case Gtk::RESPONSE_OK:
4963 if (!AudioEngine::instance()->running()) {
4977 ARDOUR_UI::transport_numpad_timeout ()
4979 _numpad_locate_happening = false;
4980 if (_numpad_timeout_connection.connected() )
4981 _numpad_timeout_connection.disconnect();
4986 ARDOUR_UI::transport_numpad_decimal ()
4988 _numpad_timeout_connection.disconnect();
4990 if (_numpad_locate_happening) {
4991 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4992 _numpad_locate_happening = false;
4994 _pending_locate_num = 0;
4995 _numpad_locate_happening = true;
4996 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5001 ARDOUR_UI::transport_numpad_event (int num)
5003 if ( _numpad_locate_happening ) {
5004 _pending_locate_num = _pending_locate_num*10 + num;
5007 case 0: toggle_roll(false, false); break;
5008 case 1: transport_rewind(1); break;
5009 case 2: transport_forward(1); break;
5010 case 3: transport_record(true); break;
5011 case 4: toggle_session_auto_loop(); break;
5012 case 5: transport_record(false); toggle_session_auto_loop(); break;
5013 case 6: toggle_punch(); break;
5014 case 7: toggle_click(); break;
5015 case 8: toggle_auto_return(); break;
5016 case 9: toggle_follow_edits(); break;
5022 ARDOUR_UI::set_flat_buttons ()
5024 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5028 ARDOUR_UI::audioengine_became_silent ()
5030 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5032 Gtk::MESSAGE_WARNING,
5036 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5038 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5039 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5040 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5041 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5042 Gtk::HBox pay_button_box;
5043 Gtk::HBox subscribe_button_box;
5045 pay_button_box.pack_start (pay_button, true, false);
5046 subscribe_button_box.pack_start (subscribe_button, true, false);
5048 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 */
5050 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5051 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5053 msg.get_vbox()->pack_start (pay_label);
5054 msg.get_vbox()->pack_start (pay_button_box);
5055 msg.get_vbox()->pack_start (subscribe_label);
5056 msg.get_vbox()->pack_start (subscribe_button_box);
5058 msg.get_vbox()->show_all ();
5060 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5061 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5062 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5067 case Gtk::RESPONSE_YES:
5068 AudioEngine::instance()->reset_silence_countdown ();
5071 case Gtk::RESPONSE_NO:
5073 save_state_canfail ("");
5077 case Gtk::RESPONSE_CANCEL:
5079 /* don't reset, save session and exit */
5085 ARDOUR_UI::hide_application ()
5087 Application::instance ()-> hide ();
5091 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5093 /* icons, titles, WM stuff */
5095 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5097 if (window_icons.empty()) {
5098 Glib::RefPtr<Gdk::Pixbuf> icon;
5099 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5100 window_icons.push_back (icon);
5102 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5103 window_icons.push_back (icon);
5105 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5106 window_icons.push_back (icon);
5108 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5109 window_icons.push_back (icon);
5113 if (!window_icons.empty()) {
5114 window.set_default_icon_list (window_icons);
5117 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5119 if (!name.empty()) {
5123 window.set_title (title.get_string());
5124 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5126 window.set_flags (CAN_FOCUS);
5127 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5129 /* This is a hack to ensure that GTK-accelerators continue to
5130 * work. Once we switch over to entirely native bindings, this will be
5131 * unnecessary and should be removed
5133 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5135 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5136 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5137 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5138 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5142 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5144 Gtkmm2ext::Bindings* bindings = 0;
5145 Gtk::Window* window = 0;
5147 /* until we get ardour bindings working, we are not handling key
5151 if (ev->type != GDK_KEY_PRESS) {
5155 if (event_window == &_main_window) {
5157 window = event_window;
5159 /* find current tab contents */
5161 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5163 /* see if it uses the ardour binding system */
5166 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5169 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5173 window = event_window;
5175 /* see if window uses ardour binding system */
5177 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5180 /* An empty binding set is treated as if it doesn't exist */
5182 if (bindings && bindings->empty()) {
5186 return key_press_focus_accelerator_handler (*window, ev, bindings);
5190 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5192 GtkWindow* win = window.gobj();
5193 GtkWidget* focus = gtk_window_get_focus (win);
5194 bool special_handling_of_unmodified_accelerators = false;
5195 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5199 /* some widget has keyboard focus */
5201 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5203 /* A particular kind of focusable widget currently has keyboard
5204 * focus. All unmodified key events should go to that widget
5205 * first and not be used as an accelerator by default
5208 special_handling_of_unmodified_accelerators = true;
5212 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
5215 show_gdk_event_state (ev->state),
5216 special_handling_of_unmodified_accelerators,
5217 Keyboard::some_magic_widget_has_focus(),
5219 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5220 ((ev->state & mask) ? "yes" : "no")));
5222 /* This exists to allow us to override the way GTK handles
5223 key events. The normal sequence is:
5225 a) event is delivered to a GtkWindow
5226 b) accelerators/mnemonics are activated
5227 c) if (b) didn't handle the event, propagate to
5228 the focus widget and/or focus chain
5230 The problem with this is that if the accelerators include
5231 keys without modifiers, such as the space bar or the
5232 letter "e", then pressing the key while typing into
5233 a text entry widget results in the accelerator being
5234 activated, instead of the desired letter appearing
5237 There is no good way of fixing this, but this
5238 represents a compromise. The idea is that
5239 key events involving modifiers (not Shift)
5240 get routed into the activation pathway first, then
5241 get propagated to the focus widget if necessary.
5243 If the key event doesn't involve modifiers,
5244 we deliver to the focus widget first, thus allowing
5245 it to get "normal text" without interference
5248 Of course, this can also be problematic: if there
5249 is a widget with focus, then it will swallow
5250 all "normal text" accelerators.
5254 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5256 /* no special handling or there are modifiers in effect: accelerate first */
5258 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5259 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5260 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5262 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5263 KeyboardKey k (ev->state, ev->keyval);
5267 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5269 if (bindings->activate (k, Bindings::Press)) {
5270 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5275 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5277 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5278 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5282 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5284 if (gtk_window_propagate_key_event (win, ev)) {
5285 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5291 /* no modifiers, propagate first */
5293 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5295 if (gtk_window_propagate_key_event (win, ev)) {
5296 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5300 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5301 KeyboardKey k (ev->state, ev->keyval);
5305 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5308 if (bindings->activate (k, Bindings::Press)) {
5309 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5315 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5317 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5318 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5323 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5328 ARDOUR_UI::load_bindings ()
5330 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5331 error << _("Global keybindings are missing") << endmsg;
5336 ARDOUR_UI::cancel_solo ()
5339 if (_session->soloing()) {
5340 _session->set_solo (_session->get_routes(), false);
5341 } else if (_session->listening()) {
5342 _session->set_listen (_session->get_routes(), false);
5345 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window