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 #include "LuaBridge/LuaBridge.h"
96 #ifdef WINDOWS_VST_SUPPORT
99 #ifdef AUDIOUNIT_SUPPORT
100 #include "ardour/audio_unit.h"
103 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
108 #include "timecode/time.h"
110 typedef uint64_t microseconds_t;
115 #include "add_route_dialog.h"
116 #include "ambiguous_file_dialog.h"
117 #include "ardour_ui.h"
118 #include "audio_clock.h"
119 #include "audio_region_view.h"
120 #include "big_clock_window.h"
121 #include "bundle_manager.h"
122 #include "duplicate_routes_dialog.h"
124 #include "engine_dialog.h"
125 #include "export_video_dialog.h"
126 #include "export_video_infobox.h"
127 #include "gain_meter.h"
128 #include "global_port_matrix.h"
129 #include "gui_object.h"
130 #include "gui_thread.h"
131 #include "keyboard.h"
132 #include "keyeditor.h"
133 #include "location_ui.h"
134 #include "lua_script_manager.h"
135 #include "luawindow.h"
136 #include "main_clock.h"
137 #include "missing_file_dialog.h"
138 #include "missing_plugin_dialog.h"
139 #include "mixer_ui.h"
140 #include "meterbridge.h"
141 #include "mouse_cursors.h"
144 #include "pingback.h"
145 #include "processor_box.h"
146 #include "prompter.h"
147 #include "public_editor.h"
148 #include "rc_option_editor.h"
149 #include "route_time_axis.h"
150 #include "route_params_ui.h"
151 #include "save_as_dialog.h"
152 #include "script_selector.h"
153 #include "session_dialog.h"
154 #include "session_metadata_dialog.h"
155 #include "session_option_editor.h"
156 #include "shuttle_control.h"
157 #include "speaker_dialog.h"
160 #include "theme_manager.h"
161 #include "time_axis_view_item.h"
164 #include "video_server_dialog.h"
165 #include "add_video_dialog.h"
166 #include "transcode_video_dialog.h"
170 using namespace ARDOUR;
171 using namespace ARDOUR_UI_UTILS;
173 using namespace Gtkmm2ext;
176 using namespace Editing;
178 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
180 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
181 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
184 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
186 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
187 "Would you like these files to be copied and used for %1 %2.x?\n\n"
188 "(This will require you to restart %1.)"),
189 PROGRAM_NAME, PROGRAM_VERSION, version),
190 false, /* no markup */
193 true /* modal, though it hardly matters since it is the only window */
196 msg.set_default_response (Gtk::RESPONSE_YES);
199 return (msg.run() == Gtk::RESPONSE_YES);
203 libxml_generic_error_func (void* /* parsing_context*/,
211 vsnprintf (buf, sizeof (buf), msg, ap);
212 error << buf << endmsg;
217 libxml_structured_error_func (void* /* parsing_context*/,
225 replace_all (msg, "\n", "");
227 if (err->file && err->line) {
228 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
231 error << ':' << err->int2;
238 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
239 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
240 , session_loaded (false)
241 , gui_object_state (new GUIObjectState)
242 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
243 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
244 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
246 , global_actions (X_("global"))
247 , ignore_dual_punch (false)
252 , _mixer_on_top (false)
253 , _initial_verbose_plugin_scan (false)
254 , first_time_engine_run (true)
255 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
256 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
257 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
258 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
259 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
260 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
261 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
262 , auto_return_button (ArdourButton::led_default_elements)
263 , follow_edits_button (ArdourButton::led_default_elements)
264 , auto_input_button (ArdourButton::led_default_elements)
265 , auditioning_alert_button (_("Audition"))
266 , solo_alert_button (_("Solo"))
267 , feedback_alert_button (_("Feedback"))
268 , error_alert_button ( ArdourButton::just_led_default_elements )
270 , editor_meter_peak_display()
271 , _numpad_locate_happening (false)
272 , _session_is_new (false)
273 , last_key_press_time (0)
277 , rc_option_editor (0)
278 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
279 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
280 , about (X_("about"), _("About"))
281 , location_ui (X_("locations"), _("Locations"))
282 , route_params (X_("inspector"), _("Tracks and Busses"))
283 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
284 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
285 , lua_script_window (X_("script-manager"), _("Script Manager"))
286 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
287 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
288 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
289 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
290 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
291 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
292 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
293 , video_server_process (0)
295 , have_configure_timeout (false)
296 , last_configure_time (0)
298 , have_disk_speed_dialog_displayed (false)
299 , _status_bar_visibility (X_("status-bar"))
300 , _feedback_exists (false)
301 , _log_not_acknowledged (LogLevelNone)
302 , duplicate_routes_dialog (0)
303 , editor_visibility_button (S_("Window|Editor"))
304 , mixer_visibility_button (S_("Window|Mixer"))
305 , prefs_visibility_button (S_("Window|Preferences"))
307 Gtkmm2ext::init (localedir);
309 UIConfiguration::instance().post_gui_init ();
311 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
312 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
314 /* configuration was modified, exit immediately */
318 if (theArdourUI == 0) {
322 /* stop libxml from spewing to stdout/stderr */
324 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
325 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
327 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
328 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
329 UIConfiguration::instance().map_parameters (pc);
331 roll_button.set_controllable (roll_controllable);
332 stop_button.set_controllable (stop_controllable);
333 goto_start_button.set_controllable (goto_start_controllable);
334 goto_end_button.set_controllable (goto_end_controllable);
335 auto_loop_button.set_controllable (auto_loop_controllable);
336 play_selection_button.set_controllable (play_selection_controllable);
337 rec_button.set_controllable (rec_controllable);
339 roll_button.set_name ("transport button");
340 stop_button.set_name ("transport button");
341 goto_start_button.set_name ("transport button");
342 goto_end_button.set_name ("transport button");
343 auto_loop_button.set_name ("transport button");
344 play_selection_button.set_name ("transport button");
345 rec_button.set_name ("transport recenable button");
346 midi_panic_button.set_name ("transport button");
348 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
349 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
351 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
353 /* handle dialog requests */
355 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
357 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
359 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
361 /* handle Audio/MIDI setup when session requires it */
363 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
365 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
367 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
369 /* handle requests to quit (coming from JACK session) */
371 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
373 /* tell the user about feedback */
375 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
376 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
378 /* handle requests to deal with missing files */
380 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
382 /* and ambiguous files */
384 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
386 /* also plugin scan messages */
387 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
388 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
390 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
392 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
395 /* lets get this party started */
397 setup_gtk_ardour_enums ();
400 SessionEvent::create_per_thread_pool ("GUI", 4096);
402 /* we like keyboards */
404 keyboard = new ArdourKeyboard(*this);
406 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
408 keyboard->set_state (*node, Stateful::loading_state_version);
411 UIConfiguration::instance().reset_dpi ();
413 TimeAxisViewItem::set_constant_heights ();
415 /* Set this up so that our window proxies can register actions */
417 ActionManager::init ();
419 /* The following must happen after ARDOUR::init() so that Config is set up */
421 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
424 key_editor.set_state (*ui_xml, 0);
425 session_option_editor.set_state (*ui_xml, 0);
426 speaker_config_window.set_state (*ui_xml, 0);
427 about.set_state (*ui_xml, 0);
428 add_route_dialog.set_state (*ui_xml, 0);
429 add_video_dialog.set_state (*ui_xml, 0);
430 route_params.set_state (*ui_xml, 0);
431 bundle_manager.set_state (*ui_xml, 0);
432 location_ui.set_state (*ui_xml, 0);
433 big_clock_window.set_state (*ui_xml, 0);
434 audio_port_matrix.set_state (*ui_xml, 0);
435 midi_port_matrix.set_state (*ui_xml, 0);
436 export_video_dialog.set_state (*ui_xml, 0);
437 lua_script_window.set_state (*ui_xml, 0);
440 /* Separate windows */
442 WM::Manager::instance().register_window (&key_editor);
443 WM::Manager::instance().register_window (&session_option_editor);
444 WM::Manager::instance().register_window (&speaker_config_window);
445 WM::Manager::instance().register_window (&about);
446 WM::Manager::instance().register_window (&add_route_dialog);
447 WM::Manager::instance().register_window (&add_video_dialog);
448 WM::Manager::instance().register_window (&route_params);
449 WM::Manager::instance().register_window (&audio_midi_setup);
450 WM::Manager::instance().register_window (&export_video_dialog);
451 WM::Manager::instance().register_window (&lua_script_window);
452 WM::Manager::instance().register_window (&bundle_manager);
453 WM::Manager::instance().register_window (&location_ui);
454 WM::Manager::instance().register_window (&big_clock_window);
455 WM::Manager::instance().register_window (&audio_port_matrix);
456 WM::Manager::instance().register_window (&midi_port_matrix);
458 /* Trigger setting up the color scheme and loading the GTK RC file */
460 UIConfiguration::instance().load_rc_file (false);
462 _process_thread = new ProcessThread ();
463 _process_thread->init ();
465 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
470 GlobalPortMatrixWindow*
471 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
476 return new GlobalPortMatrixWindow (_session, type);
480 ARDOUR_UI::attach_to_engine ()
482 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
483 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
487 ARDOUR_UI::engine_stopped ()
489 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
490 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
491 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
492 update_sample_rate (0);
497 ARDOUR_UI::engine_running ()
499 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
500 if (first_time_engine_run) {
502 first_time_engine_run = false;
506 _session->reset_xrun_count ();
508 update_disk_space ();
510 update_xrun_count ();
511 update_sample_rate (AudioEngine::instance()->sample_rate());
512 update_timecode_format ();
513 update_peak_thread_work ();
514 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
515 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
519 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
521 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
522 /* we can't rely on the original string continuing to exist when we are called
523 again in the GUI thread, so make a copy and note that we need to
526 char *copy = strdup (reason);
527 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
531 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
532 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
534 update_sample_rate (0);
538 /* if the reason is a non-empty string, it means that the backend was shutdown
539 rather than just Ardour.
542 if (strlen (reason)) {
543 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
545 msgstr = string_compose (_("\
546 The audio backend has either been shutdown or it\n\
547 disconnected %1 because %1\n\
548 was not fast enough. Try to restart\n\
549 the audio backend and save the session."), PROGRAM_NAME);
552 MessageDialog msg (_main_window, msgstr);
553 pop_back_splash (msg);
557 free (const_cast<char*> (reason));
562 ARDOUR_UI::post_engine ()
564 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
566 #ifdef AUDIOUNIT_SUPPORT
568 if (AUPluginInfo::au_get_crashlog(au_msg)) {
569 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
570 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
571 info << au_msg << endmsg;
575 ARDOUR::init_post_engine ();
577 /* connect to important signals */
579 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
580 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
581 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
582 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
583 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
585 if (setup_windows ()) {
586 throw failed_constructor ();
589 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
590 XMLNode* n = Config->extra_xml (X_("UI"));
592 _status_bar_visibility.set_state (*n);
595 check_memory_locking();
597 /* this is the first point at which all the possible actions are
598 * available, because some of the available actions are dependent on
599 * aspects of the engine/backend.
602 if (ARDOUR_COMMAND_LINE::show_key_actions) {
605 vector<string> paths;
606 vector<string> labels;
607 vector<string> tooltips;
609 vector<Glib::RefPtr<Gtk::Action> > actions;
611 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
613 vector<string>::iterator k;
614 vector<string>::iterator p;
616 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
621 cout << *p << " => " << *k << endl;
625 halt_connection.disconnect ();
626 AudioEngine::instance()->stop ();
630 /* this being a GUI and all, we want peakfiles */
632 AudioFileSource::set_build_peakfiles (true);
633 AudioFileSource::set_build_missing_peakfiles (true);
635 /* set default clock modes */
637 primary_clock->set_mode (AudioClock::Timecode);
638 secondary_clock->set_mode (AudioClock::BBT);
640 /* start the time-of-day-clock */
643 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
644 update_wall_clock ();
645 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
650 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
651 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
652 Config->map_parameters (pc);
654 UIConfiguration::instance().map_parameters (pc);
658 ARDOUR_UI::~ARDOUR_UI ()
660 UIConfiguration::instance().save_state();
664 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
665 // don't bother at 'real' exit. the OS cleans up for us.
667 delete primary_clock;
668 delete secondary_clock;
669 delete _process_thread;
675 delete gui_object_state;
676 FastMeter::flush_pattern_cache ();
677 PixFader::flush_pattern_cache ();
681 /* Small trick to flush main-thread event pool.
682 * Other thread-pools are destroyed at pthread_exit(),
683 * but tmain thread termination is too late to trigger Pool::~Pool()
685 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.
686 delete ev->event_pool();
691 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
693 if (Splash::instance()) {
694 Splash::instance()->pop_back_for (win);
699 ARDOUR_UI::configure_timeout ()
701 if (last_configure_time == 0) {
702 /* no configure events yet */
706 /* force a gap of 0.5 seconds since the last configure event
709 if (get_microseconds() - last_configure_time < 500000) {
712 have_configure_timeout = false;
713 save_ardour_state ();
719 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
721 if (have_configure_timeout) {
722 last_configure_time = get_microseconds();
724 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
725 have_configure_timeout = true;
732 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
734 const XMLProperty* prop;
736 if ((prop = node.property ("roll")) != 0) {
737 roll_controllable->set_id (prop->value());
739 if ((prop = node.property ("stop")) != 0) {
740 stop_controllable->set_id (prop->value());
742 if ((prop = node.property ("goto-start")) != 0) {
743 goto_start_controllable->set_id (prop->value());
745 if ((prop = node.property ("goto-end")) != 0) {
746 goto_end_controllable->set_id (prop->value());
748 if ((prop = node.property ("auto-loop")) != 0) {
749 auto_loop_controllable->set_id (prop->value());
751 if ((prop = node.property ("play-selection")) != 0) {
752 play_selection_controllable->set_id (prop->value());
754 if ((prop = node.property ("rec")) != 0) {
755 rec_controllable->set_id (prop->value());
757 if ((prop = node.property ("shuttle")) != 0) {
758 shuttle_box->controllable()->set_id (prop->value());
763 ARDOUR_UI::get_transport_controllable_state ()
765 XMLNode* node = new XMLNode(X_("TransportControllables"));
768 roll_controllable->id().print (buf, sizeof (buf));
769 node->add_property (X_("roll"), buf);
770 stop_controllable->id().print (buf, sizeof (buf));
771 node->add_property (X_("stop"), buf);
772 goto_start_controllable->id().print (buf, sizeof (buf));
773 node->add_property (X_("goto_start"), buf);
774 goto_end_controllable->id().print (buf, sizeof (buf));
775 node->add_property (X_("goto_end"), buf);
776 auto_loop_controllable->id().print (buf, sizeof (buf));
777 node->add_property (X_("auto_loop"), buf);
778 play_selection_controllable->id().print (buf, sizeof (buf));
779 node->add_property (X_("play_selection"), buf);
780 rec_controllable->id().print (buf, sizeof (buf));
781 node->add_property (X_("rec"), buf);
782 shuttle_box->controllable()->id().print (buf, sizeof (buf));
783 node->add_property (X_("shuttle"), buf);
789 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
792 _session->save_state (snapshot_name);
797 ARDOUR_UI::autosave_session ()
799 if (g_main_depth() > 1) {
800 /* inside a recursive main loop,
801 give up because we may not be able to
807 if (!Config->get_periodic_safety_backups()) {
812 _session->maybe_write_autosave();
819 ARDOUR_UI::session_dirty_changed ()
826 ARDOUR_UI::update_autosave ()
828 if (_session && _session->dirty()) {
829 if (_autosave_connection.connected()) {
830 _autosave_connection.disconnect();
833 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
834 Config->get_periodic_safety_backup_interval() * 1000);
837 if (_autosave_connection.connected()) {
838 _autosave_connection.disconnect();
844 ARDOUR_UI::check_announcements ()
847 string _annc_filename;
850 _annc_filename = PROGRAM_NAME "_announcements_osx_";
851 #elif defined PLATFORM_WINDOWS
852 _annc_filename = PROGRAM_NAME "_announcements_windows_";
854 _annc_filename = PROGRAM_NAME "_announcements_linux_";
856 _annc_filename.append (VERSIONSTRING);
858 _announce_string = "";
860 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
861 FILE* fin = g_fopen (path.c_str(), "rb");
863 while (!feof (fin)) {
866 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
869 _announce_string.append (tmp, len);
874 pingback (VERSIONSTRING, path);
879 _hide_splash (gpointer arg)
881 ((ARDOUR_UI*)arg)->hide_splash();
886 ARDOUR_UI::starting ()
888 Application* app = Application::instance ();
890 bool brand_new_user = ArdourStartup::required ();
892 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
893 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
895 if (ARDOUR_COMMAND_LINE::check_announcements) {
896 check_announcements ();
901 /* we need to create this early because it may need to set the
902 * audio backend end up.
906 audio_midi_setup.get (true);
908 std::cerr << "audio-midi engine setup failed."<< std::endl;
912 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
913 nsm = new NSM_Client;
914 if (!nsm->init (nsm_url)) {
915 /* the ardour executable may have different names:
917 * waf's obj.target for distro versions: eg ardour4, ardourvst4
918 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
919 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
921 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
923 const char *process_name = g_getenv ("ARDOUR_SELF");
924 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
927 // wait for announce reply from nsm server
928 for ( i = 0; i < 5000; ++i) {
932 if (nsm->is_active()) {
937 error << _("NSM server did not announce itself") << endmsg;
940 // wait for open command from nsm server
941 for ( i = 0; i < 5000; ++i) {
944 if (nsm->client_id ()) {
950 error << _("NSM: no client ID provided") << endmsg;
954 if (_session && nsm) {
955 _session->set_nsm_state( nsm->is_active() );
957 error << _("NSM: no session created") << endmsg;
961 // nsm requires these actions disabled
962 vector<string> action_names;
963 action_names.push_back("SaveAs");
964 action_names.push_back("Rename");
965 action_names.push_back("New");
966 action_names.push_back("Open");
967 action_names.push_back("Recent");
968 action_names.push_back("Close");
970 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
971 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
973 act->set_sensitive (false);
980 error << _("NSM: initialization failed") << endmsg;
986 if (brand_new_user) {
987 _initial_verbose_plugin_scan = true;
992 _initial_verbose_plugin_scan = false;
993 switch (s.response ()) {
994 case Gtk::RESPONSE_OK:
1001 #ifdef NO_PLUGIN_STATE
1003 ARDOUR::RecentSessions rs;
1004 ARDOUR::read_recent_sessions (rs);
1006 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1008 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1010 /* already used Ardour, have sessions ... warn about plugin state */
1012 ArdourDialog d (_("Free/Demo Version Warning"), true);
1014 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1015 CheckButton c (_("Don't warn me about this again"));
1017 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"),
1018 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1019 _("It will not restore OR save any plugin settings"),
1020 _("If you load an existing session with plugin settings\n"
1021 "they will not be used and will be lost."),
1022 _("To get full access to updates without this limitation\n"
1023 "consider becoming a subscriber for a low cost every month.")));
1024 l.set_justify (JUSTIFY_CENTER);
1026 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1028 d.get_vbox()->pack_start (l, true, true);
1029 d.get_vbox()->pack_start (b, false, false, 12);
1030 d.get_vbox()->pack_start (c, false, false, 12);
1032 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1033 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1037 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1039 if (d.run () != RESPONSE_OK) {
1045 /* go get a session */
1047 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1049 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1050 std::cerr << "Cannot get session parameters."<< std::endl;
1057 WM::Manager::instance().show_visible ();
1059 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1060 * editor window, and we may want stuff to be hidden.
1062 _status_bar_visibility.update ();
1064 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1066 if (splash && splash->is_visible()) {
1067 // in 1 second, hide the splash screen
1068 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1071 /* all other dialogs are created conditionally */
1077 ARDOUR_UI::check_memory_locking ()
1079 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1080 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1084 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1086 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1088 struct rlimit limits;
1090 long pages, page_size;
1092 size_t pages_len=sizeof(pages);
1093 if ((page_size = getpagesize()) < 0 ||
1094 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1096 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1101 ram = (int64_t) pages * (int64_t) page_size;
1104 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1108 if (limits.rlim_cur != RLIM_INFINITY) {
1110 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1114 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1115 "This might cause %1 to run out of memory before your system "
1116 "runs out of memory. \n\n"
1117 "You can view the memory limit with 'ulimit -l', "
1118 "and it is normally controlled by %2"),
1121 X_("/etc/login.conf")
1123 X_(" /etc/security/limits.conf")
1127 msg.set_default_response (RESPONSE_OK);
1129 VBox* vbox = msg.get_vbox();
1131 CheckButton cb (_("Do not show this window again"));
1132 hbox.pack_start (cb, true, false);
1133 vbox->pack_start (hbox);
1138 pop_back_splash (msg);
1142 if (cb.get_active()) {
1143 XMLNode node (X_("no-memory-warning"));
1144 Config->add_instant_xml (node);
1149 #endif // !__APPLE__
1154 ARDOUR_UI::queue_finish ()
1156 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1160 ARDOUR_UI::idle_finish ()
1163 return false; /* do not call again */
1170 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1172 if (_session->dirty()) {
1173 vector<string> actions;
1174 actions.push_back (_("Don't quit"));
1175 actions.push_back (_("Just quit"));
1176 actions.push_back (_("Save and quit"));
1177 switch (ask_about_saving_session(actions)) {
1182 /* use the default name */
1183 if (save_state_canfail ("")) {
1184 /* failed - don't quit */
1185 MessageDialog msg (_main_window,
1186 string_compose (_("\
1187 %1 was unable to save your session.\n\n\
1188 If you still wish to quit, please use the\n\n\
1189 \"Just quit\" option."), PROGRAM_NAME));
1190 pop_back_splash(msg);
1200 second_connection.disconnect ();
1201 point_one_second_connection.disconnect ();
1202 point_zero_something_second_connection.disconnect();
1203 fps_connection.disconnect();
1206 delete ARDOUR_UI::instance()->video_timeline;
1207 ARDOUR_UI::instance()->video_timeline = NULL;
1208 stop_video_server();
1210 /* Save state before deleting the session, as that causes some
1211 windows to be destroyed before their visible state can be
1214 save_ardour_state ();
1216 close_all_dialogs ();
1219 _session->set_clean ();
1220 _session->remove_pending_capture_state ();
1225 halt_connection.disconnect ();
1226 AudioEngine::instance()->stop ();
1227 #ifdef WINDOWS_VST_SUPPORT
1228 fst_stop_threading();
1234 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1236 ArdourDialog window (_("Unsaved Session"));
1237 Gtk::HBox dhbox; // the hbox for the image and text
1238 Gtk::Label prompt_label;
1239 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1243 assert (actions.size() >= 3);
1245 window.add_button (actions[0], RESPONSE_REJECT);
1246 window.add_button (actions[1], RESPONSE_APPLY);
1247 window.add_button (actions[2], RESPONSE_ACCEPT);
1249 window.set_default_response (RESPONSE_ACCEPT);
1251 Gtk::Button noquit_button (msg);
1252 noquit_button.set_name ("EditorGTKButton");
1256 if (_session->snap_name() == _session->name()) {
1257 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?"),
1258 _session->snap_name());
1260 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?"),
1261 _session->snap_name());
1264 prompt_label.set_text (prompt);
1265 prompt_label.set_name (X_("PrompterLabel"));
1266 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1268 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1269 dhbox.set_homogeneous (false);
1270 dhbox.pack_start (*dimage, false, false, 5);
1271 dhbox.pack_start (prompt_label, true, false, 5);
1272 window.get_vbox()->pack_start (dhbox);
1274 window.set_name (_("Prompter"));
1275 window.set_modal (true);
1276 window.set_resizable (false);
1279 prompt_label.show();
1284 ResponseType r = (ResponseType) window.run();
1289 case RESPONSE_ACCEPT: // save and get out of here
1291 case RESPONSE_APPLY: // get out of here
1302 ARDOUR_UI::every_second ()
1305 update_xrun_count ();
1306 update_buffer_load ();
1307 update_disk_space ();
1308 update_timecode_format ();
1309 update_peak_thread_work ();
1311 if (nsm && nsm->is_active ()) {
1314 if (!_was_dirty && _session->dirty ()) {
1318 else if (_was_dirty && !_session->dirty ()){
1326 ARDOUR_UI::every_point_one_seconds ()
1328 // TODO get rid of this..
1329 // ShuttleControl is updated directly via TransportStateChange signal
1333 ARDOUR_UI::every_point_zero_something_seconds ()
1335 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1337 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1338 float mpeak = editor_meter->update_meters();
1339 if (mpeak > editor_meter_max_peak) {
1340 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1341 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1348 ARDOUR_UI::set_fps_timeout_connection ()
1350 unsigned int interval = 40;
1351 if (!_session) return;
1352 if (_session->timecode_frames_per_second() != 0) {
1353 /* ideally we'll use a select() to sleep and not accumulate
1354 * idle time to provide a regular periodic signal.
1355 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1356 * However, that'll require a dedicated thread and cross-thread
1357 * signals to the GUI Thread..
1359 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1360 * _session->frame_rate() / _session->nominal_frame_rate()
1361 / _session->timecode_frames_per_second()
1363 #ifdef PLATFORM_WINDOWS
1364 // the smallest windows scheduler time-slice is ~15ms.
1365 // periodic GUI timeouts shorter than that will cause
1366 // WaitForSingleObject to spinlock (100% of one CPU Core)
1367 // and gtk never enters idle mode.
1368 // also changing timeBeginPeriod(1) does not affect that in
1369 // any beneficial way, so we just limit the max rate for now.
1370 interval = std::max(30u, interval); // at most ~33Hz.
1372 interval = std::max(8u, interval); // at most 120Hz.
1375 fps_connection.disconnect();
1376 Timers::set_fps_interval (interval);
1380 ARDOUR_UI::update_sample_rate (framecnt_t)
1384 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1386 if (!AudioEngine::instance()->connected()) {
1388 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1392 framecnt_t rate = AudioEngine::instance()->sample_rate();
1395 /* no sample rate available */
1396 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1399 if (fmod (rate, 1000.0) != 0.0) {
1400 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1401 (float) rate / 1000.0f,
1402 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1404 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1406 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1410 sample_rate_label.set_markup (buf);
1414 ARDOUR_UI::update_format ()
1417 format_label.set_text ("");
1422 s << _("File:") << X_(" <span foreground=\"green\">");
1424 switch (_session->config.get_native_file_header_format ()) {
1456 switch (_session->config.get_native_file_data_format ()) {
1470 format_label.set_markup (s.str ());
1474 ARDOUR_UI::update_xrun_count ()
1478 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1479 should also be changed.
1483 const unsigned int x = _session->get_xrun_count ();
1485 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1487 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1490 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1492 xrun_label.set_markup (buf);
1493 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1497 ARDOUR_UI::update_cpu_load ()
1501 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1502 should also be changed.
1505 double const c = AudioEngine::instance()->get_dsp_load ();
1506 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1507 cpu_load_label.set_markup (buf);
1511 ARDOUR_UI::update_peak_thread_work ()
1514 const int c = SourceFactory::peak_work_queue_length ();
1516 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1517 peak_thread_work_label.set_markup (buf);
1519 peak_thread_work_label.set_markup (X_(""));
1524 ARDOUR_UI::update_buffer_load ()
1528 uint32_t const playback = _session ? _session->playback_load () : 100;
1529 uint32_t const capture = _session ? _session->capture_load () : 100;
1531 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1532 should also be changed.
1538 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1539 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1540 playback <= 5 ? X_("red") : X_("green"),
1542 capture <= 5 ? X_("red") : X_("green"),
1546 buffer_load_label.set_markup (buf);
1548 buffer_load_label.set_text ("");
1553 ARDOUR_UI::count_recenabled_streams (Route& route)
1555 Track* track = dynamic_cast<Track*>(&route);
1556 if (track && track->record_enabled()) {
1557 rec_enabled_streams += track->n_inputs().n_total();
1562 ARDOUR_UI::update_disk_space()
1564 if (_session == 0) {
1568 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1570 framecnt_t fr = _session->frame_rate();
1573 /* skip update - no SR available */
1578 /* Available space is unknown */
1579 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1580 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1581 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1583 rec_enabled_streams = 0;
1584 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1586 framecnt_t frames = opt_frames.get_value_or (0);
1588 if (rec_enabled_streams) {
1589 frames /= rec_enabled_streams;
1596 hrs = frames / (fr * 3600);
1599 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1601 frames -= hrs * fr * 3600;
1602 mins = frames / (fr * 60);
1603 frames -= mins * fr * 60;
1606 bool const low = (hrs == 0 && mins <= 30);
1610 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1611 low ? X_("red") : X_("green"),
1617 disk_space_label.set_markup (buf);
1621 ARDOUR_UI::update_timecode_format ()
1627 TimecodeSlave* tcslave;
1628 SyncSource sync_src = Config->get_sync_source();
1630 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1631 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1636 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1637 matching ? X_("green") : X_("red"),
1638 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1640 snprintf (buf, sizeof (buf), "TC: n/a");
1643 timecode_format_label.set_markup (buf);
1647 ARDOUR_UI::update_wall_clock ()
1651 static int last_min = -1;
1654 tm_now = localtime (&now);
1655 if (last_min != tm_now->tm_min) {
1657 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1658 wall_clock_label.set_text (buf);
1659 last_min = tm_now->tm_min;
1666 ARDOUR_UI::open_recent_session ()
1668 bool can_return = (_session != 0);
1670 SessionDialog recent_session_dialog;
1674 ResponseType r = (ResponseType) recent_session_dialog.run ();
1677 case RESPONSE_ACCEPT:
1681 recent_session_dialog.hide();
1688 recent_session_dialog.hide();
1692 std::string path = recent_session_dialog.session_folder();
1693 std::string state = recent_session_dialog.session_name (should_be_new);
1695 if (should_be_new == true) {
1699 _session_is_new = false;
1701 if (load_session (path, state) == 0) {
1710 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1712 if (!AudioEngine::instance()->connected()) {
1713 MessageDialog msg (parent, string_compose (
1714 _("%1 is not connected to any audio backend.\n"
1715 "You cannot open or close sessions in this condition"),
1717 pop_back_splash (msg);
1725 ARDOUR_UI::open_session ()
1727 if (!check_audioengine (_main_window)) {
1731 /* ardour sessions are folders */
1732 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1733 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1734 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1735 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1738 string session_parent_dir = Glib::path_get_dirname(_session->path());
1739 open_session_selector.set_current_folder(session_parent_dir);
1741 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1744 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1746 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1747 string default_session_folder = Config->get_default_session_parent_dir();
1748 open_session_selector.add_shortcut_folder (default_session_folder);
1750 catch (Glib::Error & e) {
1751 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1754 FileFilter session_filter;
1755 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1756 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1757 open_session_selector.add_filter (session_filter);
1758 open_session_selector.set_filter (session_filter);
1760 int response = open_session_selector.run();
1761 open_session_selector.hide ();
1763 if (response == Gtk::RESPONSE_CANCEL) {
1767 string session_path = open_session_selector.get_filename();
1771 if (session_path.length() > 0) {
1772 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1773 _session_is_new = isnew;
1774 load_session (path, name);
1781 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1782 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1784 list<boost::shared_ptr<MidiTrack> > tracks;
1786 if (_session == 0) {
1787 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1792 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1794 if (tracks.size() != how_many) {
1795 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1800 MessageDialog msg (_main_window,
1801 string_compose (_("There are insufficient ports available\n\
1802 to create a new track or bus.\n\
1803 You should save %1, exit and\n\
1804 restart with more ports."), PROGRAM_NAME));
1811 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1813 ChanCount one_midi_channel;
1814 one_midi_channel.set (DataType::MIDI, 1);
1817 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1822 ARDOUR_UI::session_add_audio_route (
1824 int32_t input_channels,
1825 int32_t output_channels,
1826 ARDOUR::TrackMode mode,
1827 RouteGroup* route_group,
1829 string const & name_template
1832 list<boost::shared_ptr<AudioTrack> > tracks;
1835 if (_session == 0) {
1836 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1842 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1844 if (tracks.size() != how_many) {
1845 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1851 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1853 if (routes.size() != how_many) {
1854 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1861 MessageDialog msg (_main_window,
1862 string_compose (_("There are insufficient ports available\n\
1863 to create a new track or bus.\n\
1864 You should save %1, exit and\n\
1865 restart with more ports."), PROGRAM_NAME));
1866 pop_back_splash (msg);
1872 ARDOUR_UI::transport_goto_start ()
1875 _session->goto_start();
1877 /* force displayed area in editor to start no matter
1878 what "follow playhead" setting is.
1882 editor->center_screen (_session->current_start_frame ());
1888 ARDOUR_UI::transport_goto_zero ()
1891 _session->request_locate (0);
1893 /* force displayed area in editor to start no matter
1894 what "follow playhead" setting is.
1898 editor->reset_x_origin (0);
1904 ARDOUR_UI::transport_goto_wallclock ()
1906 if (_session && editor) {
1913 localtime_r (&now, &tmnow);
1915 framecnt_t frame_rate = _session->frame_rate();
1917 if (frame_rate == 0) {
1918 /* no frame rate available */
1922 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1923 frames += tmnow.tm_min * (60 * frame_rate);
1924 frames += tmnow.tm_sec * frame_rate;
1926 _session->request_locate (frames, _session->transport_rolling ());
1928 /* force displayed area in editor to start no matter
1929 what "follow playhead" setting is.
1933 editor->center_screen (frames);
1939 ARDOUR_UI::transport_goto_end ()
1942 framepos_t const frame = _session->current_end_frame();
1943 _session->request_locate (frame);
1945 /* force displayed area in editor to start no matter
1946 what "follow playhead" setting is.
1950 editor->center_screen (frame);
1956 ARDOUR_UI::transport_stop ()
1962 if (_session->is_auditioning()) {
1963 _session->cancel_audition ();
1967 _session->request_stop (false, true);
1970 /** Check if any tracks are record enabled. If none are, record enable all of them.
1971 * @return true if track record-enabled status was changed, false otherwise.
1974 ARDOUR_UI::trx_record_enable_all_tracks ()
1980 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1981 bool none_record_enabled = true;
1983 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1984 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1987 if (t->record_enabled()) {
1988 none_record_enabled = false;
1993 if (none_record_enabled) {
1994 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1997 return none_record_enabled;
2001 ARDOUR_UI::transport_record (bool roll)
2004 switch (_session->record_status()) {
2005 case Session::Disabled:
2006 if (_session->ntracks() == 0) {
2007 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."));
2011 if (Profile->get_trx()) {
2012 roll = trx_record_enable_all_tracks ();
2014 _session->maybe_enable_record ();
2019 case Session::Recording:
2021 _session->request_stop();
2023 _session->disable_record (false, true);
2027 case Session::Enabled:
2028 _session->disable_record (false, true);
2034 ARDOUR_UI::transport_roll ()
2040 if (_session->is_auditioning()) {
2045 if (_session->config.get_external_sync()) {
2046 switch (Config->get_sync_source()) {
2050 /* transport controlled by the master */
2056 bool rolling = _session->transport_rolling();
2058 if (_session->get_play_loop()) {
2060 /* If loop playback is not a mode, then we should cancel
2061 it when this action is requested. If it is a mode
2062 we just leave it in place.
2065 if (!Config->get_loop_is_mode()) {
2066 /* XXX it is not possible to just leave seamless loop and keep
2067 playing at present (nov 4th 2009)
2069 if (!Config->get_seamless_loop()) {
2070 /* stop loop playback and stop rolling */
2071 _session->request_play_loop (false, true);
2072 } else if (rolling) {
2073 /* stop loop playback but keep rolling */
2074 _session->request_play_loop (false, false);
2078 } else if (_session->get_play_range () ) {
2079 /* stop playing a range if we currently are */
2080 _session->request_play_range (0, true);
2084 _session->request_transport_speed (1.0f);
2089 ARDOUR_UI::get_smart_mode() const
2091 return ( editor->get_smart_mode() );
2096 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2102 if (_session->is_auditioning()) {
2103 _session->cancel_audition ();
2107 if (_session->config.get_external_sync()) {
2108 switch (Config->get_sync_source()) {
2112 /* transport controlled by the master */
2117 bool rolling = _session->transport_rolling();
2118 bool affect_transport = true;
2120 if (rolling && roll_out_of_bounded_mode) {
2121 /* drop out of loop/range playback but leave transport rolling */
2122 if (_session->get_play_loop()) {
2123 if (_session->actively_recording()) {
2125 /* just stop using the loop, then actually stop
2128 _session->request_play_loop (false, affect_transport);
2131 if (Config->get_seamless_loop()) {
2132 /* the disk buffers contain copies of the loop - we can't
2133 just keep playing, so stop the transport. the user
2134 can restart as they wish.
2136 affect_transport = true;
2138 /* disk buffers are normal, so we can keep playing */
2139 affect_transport = false;
2141 _session->request_play_loop (false, affect_transport);
2143 } else if (_session->get_play_range ()) {
2144 affect_transport = false;
2145 _session->request_play_range (0, true);
2149 if (affect_transport) {
2151 _session->request_stop (with_abort, true);
2153 /* the only external sync condition we can be in here
2154 * would be Engine (JACK) sync, in which case we still
2158 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
2159 _session->request_play_range (&editor->get_selection().time, true);
2160 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2162 _session->request_transport_speed (1.0f);
2168 ARDOUR_UI::toggle_session_auto_loop ()
2174 Location * looploc = _session->locations()->auto_loop_location();
2180 if (_session->get_play_loop()) {
2182 /* looping enabled, our job is to disable it */
2184 _session->request_play_loop (false);
2188 /* looping not enabled, our job is to enable it.
2190 loop-is-NOT-mode: this action always starts the transport rolling.
2191 loop-IS-mode: this action simply sets the loop play mechanism, but
2192 does not start transport.
2194 if (Config->get_loop_is_mode()) {
2195 _session->request_play_loop (true, false);
2197 _session->request_play_loop (true, true);
2201 //show the loop markers
2202 looploc->set_hidden (false, this);
2206 ARDOUR_UI::transport_play_selection ()
2212 editor->play_selection ();
2216 ARDOUR_UI::transport_play_preroll ()
2221 editor->play_with_preroll ();
2225 ARDOUR_UI::transport_rewind (int option)
2227 float current_transport_speed;
2230 current_transport_speed = _session->transport_speed();
2232 if (current_transport_speed >= 0.0f) {
2235 _session->request_transport_speed (-1.0f);
2238 _session->request_transport_speed (-4.0f);
2241 _session->request_transport_speed (-0.5f);
2246 _session->request_transport_speed (current_transport_speed * 1.5f);
2252 ARDOUR_UI::transport_forward (int option)
2258 float current_transport_speed = _session->transport_speed();
2260 if (current_transport_speed <= 0.0f) {
2263 _session->request_transport_speed (1.0f);
2266 _session->request_transport_speed (4.0f);
2269 _session->request_transport_speed (0.5f);
2274 _session->request_transport_speed (current_transport_speed * 1.5f);
2279 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2285 boost::shared_ptr<Route> r;
2287 if ((r = _session->route_by_remote_id (rid)) != 0) {
2289 boost::shared_ptr<Track> t;
2291 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2292 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2298 ARDOUR_UI::map_transport_state ()
2301 auto_loop_button.unset_active_state ();
2302 play_selection_button.unset_active_state ();
2303 roll_button.unset_active_state ();
2304 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2308 shuttle_box->map_transport_state ();
2310 float sp = _session->transport_speed();
2316 if (_session->get_play_range()) {
2318 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2319 roll_button.unset_active_state ();
2320 auto_loop_button.unset_active_state ();
2322 } else if (_session->get_play_loop ()) {
2324 auto_loop_button.set_active (true);
2325 play_selection_button.set_active (false);
2326 if (Config->get_loop_is_mode()) {
2327 roll_button.set_active (true);
2329 roll_button.set_active (false);
2334 roll_button.set_active (true);
2335 play_selection_button.set_active (false);
2336 auto_loop_button.set_active (false);
2339 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2340 /* light up both roll and play-selection if they are joined */
2341 roll_button.set_active (true);
2342 play_selection_button.set_active (true);
2345 stop_button.set_active (false);
2349 stop_button.set_active (true);
2350 roll_button.set_active (false);
2351 play_selection_button.set_active (false);
2352 if (Config->get_loop_is_mode ()) {
2353 auto_loop_button.set_active (_session->get_play_loop());
2355 auto_loop_button.set_active (false);
2357 update_disk_space ();
2362 ARDOUR_UI::blink_handler (bool blink_on)
2364 transport_rec_enable_blink (blink_on);
2365 solo_blink (blink_on);
2366 sync_blink (blink_on);
2367 audition_blink (blink_on);
2368 feedback_blink (blink_on);
2369 error_blink (blink_on);
2373 ARDOUR_UI::update_clocks ()
2375 if (!_session) return;
2377 if (editor && !editor->dragging_playhead()) {
2378 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2383 ARDOUR_UI::start_clocking ()
2385 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2386 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2388 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2393 ARDOUR_UI::stop_clocking ()
2395 clock_signal_connection.disconnect ();
2399 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2403 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2405 label->set_text (buf);
2406 bar->set_fraction (fraction);
2408 /* process events, redraws, etc. */
2410 while (gtk_events_pending()) {
2411 gtk_main_iteration ();
2414 return true; /* continue with save-as */
2418 ARDOUR_UI::save_session_as ()
2424 if (!save_as_dialog) {
2425 save_as_dialog = new SaveAsDialog;
2428 save_as_dialog->set_name (_session->name());
2430 int response = save_as_dialog->run ();
2432 save_as_dialog->hide ();
2435 case Gtk::RESPONSE_OK:
2444 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2445 sa.new_name = save_as_dialog->new_name ();
2446 sa.switch_to = save_as_dialog->switch_to();
2447 sa.copy_media = save_as_dialog->copy_media();
2448 sa.copy_external = save_as_dialog->copy_external();
2449 sa.include_media = save_as_dialog->include_media ();
2451 /* Only bother with a progress dialog if we're going to copy
2452 media into the save-as target. Without that choice, this
2453 will be very fast because we're only talking about a few kB's to
2454 perhaps a couple of MB's of data.
2457 ArdourDialog progress_dialog (_("Save As"), true);
2459 if (sa.include_media && sa.copy_media) {
2462 Gtk::ProgressBar progress_bar;
2464 progress_dialog.get_vbox()->pack_start (label);
2465 progress_dialog.get_vbox()->pack_start (progress_bar);
2467 progress_bar.show ();
2469 /* this signal will be emitted from within this, the calling thread,
2470 * after every file is copied. It provides information on percentage
2471 * complete (in terms of total data to copy), the number of files
2472 * copied so far, and the total number to copy.
2477 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2479 progress_dialog.show_all ();
2480 progress_dialog.present ();
2483 if (_session->save_as (sa)) {
2485 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2489 if (!sa.include_media) {
2490 unload_session (false);
2491 load_session (sa.final_session_folder_name, sa.new_name);
2496 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2500 struct tm local_time;
2503 localtime_r (&n, &local_time);
2504 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2506 save_state (timebuf, switch_to_it);
2511 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2515 prompter.get_result (snapname);
2517 bool do_save = (snapname.length() != 0);
2520 char illegal = Session::session_name_is_legal(snapname);
2522 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2523 "snapshot names may not contain a '%1' character"), illegal));
2529 vector<std::string> p;
2530 get_state_files_in_directory (_session->session_directory().root_path(), p);
2531 vector<string> n = get_file_names_no_extension (p);
2533 if (find (n.begin(), n.end(), snapname) != n.end()) {
2535 do_save = overwrite_file_dialog (prompter,
2536 _("Confirm Snapshot Overwrite"),
2537 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2541 save_state (snapname, switch_to_it);
2551 /** Ask the user for the name of a new snapshot and then take it.
2555 ARDOUR_UI::snapshot_session (bool switch_to_it)
2557 ArdourPrompter prompter (true);
2559 prompter.set_name ("Prompter");
2560 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2562 prompter.set_title (_("Save as..."));
2563 prompter.set_prompt (_("New session name"));
2565 prompter.set_title (_("Take Snapshot"));
2566 prompter.set_prompt (_("Name of new snapshot"));
2570 prompter.set_initial_text (_session->snap_name());
2574 struct tm local_time;
2577 localtime_r (&n, &local_time);
2578 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2579 prompter.set_initial_text (timebuf);
2582 bool finished = false;
2584 switch (prompter.run()) {
2585 case RESPONSE_ACCEPT:
2587 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2598 /** Ask the user for a new session name and then rename the session to it.
2602 ARDOUR_UI::rename_session ()
2608 ArdourPrompter prompter (true);
2611 prompter.set_name ("Prompter");
2612 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2613 prompter.set_title (_("Rename Session"));
2614 prompter.set_prompt (_("New session name"));
2617 switch (prompter.run()) {
2618 case RESPONSE_ACCEPT:
2620 prompter.get_result (name);
2622 bool do_rename = (name.length() != 0);
2625 char illegal = Session::session_name_is_legal (name);
2628 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2629 "session names may not contain a '%1' character"), illegal));
2634 switch (_session->rename (name)) {
2636 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2637 msg.set_position (WIN_POS_MOUSE);
2645 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2646 msg.set_position (WIN_POS_MOUSE);
2662 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2664 if (!_session || _session->deletion_in_progress()) {
2668 XMLNode* node = new XMLNode (X_("UI"));
2670 WM::Manager::instance().add_state (*node);
2672 node->add_child_nocopy (gui_object_state->get_state());
2674 _session->add_extra_xml (*node);
2676 if (export_video_dialog) {
2677 _session->add_extra_xml (export_video_dialog->get_state());
2680 save_state_canfail (name, switch_to_it);
2684 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2689 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2694 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2699 ARDOUR_UI::primary_clock_value_changed ()
2702 _session->request_locate (primary_clock->current_time ());
2707 ARDOUR_UI::big_clock_value_changed ()
2710 _session->request_locate (big_clock->current_time ());
2715 ARDOUR_UI::secondary_clock_value_changed ()
2718 _session->request_locate (secondary_clock->current_time ());
2723 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2725 if (_session == 0) {
2729 if (_session->step_editing()) {
2733 Session::RecordState const r = _session->record_status ();
2734 bool const h = _session->have_rec_enabled_track ();
2736 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2738 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2740 rec_button.set_active_state (Gtkmm2ext::Off);
2742 } else if (r == Session::Recording && h) {
2743 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2745 rec_button.unset_active_state ();
2750 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2754 prompter.get_result (name);
2756 if (name.length()) {
2757 int failed = _session->save_template (name);
2759 if (failed == -2) { /* file already exists. */
2760 bool overwrite = overwrite_file_dialog (prompter,
2761 _("Confirm Template Overwrite"),
2762 _("A template already exists with that name. Do you want to overwrite it?"));
2765 _session->save_template (name, true);
2777 ARDOUR_UI::save_template ()
2779 ArdourPrompter prompter (true);
2781 if (!check_audioengine (_main_window)) {
2785 prompter.set_name (X_("Prompter"));
2786 prompter.set_title (_("Save Template"));
2787 prompter.set_prompt (_("Name for template:"));
2788 prompter.set_initial_text(_session->name() + _("-template"));
2789 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2791 bool finished = false;
2793 switch (prompter.run()) {
2794 case RESPONSE_ACCEPT:
2795 finished = process_save_template_prompter (prompter);
2806 ARDOUR_UI::edit_metadata ()
2808 SessionMetadataEditor dialog;
2809 dialog.set_session (_session);
2810 dialog.grab_focus ();
2815 ARDOUR_UI::import_metadata ()
2817 SessionMetadataImporter dialog;
2818 dialog.set_session (_session);
2823 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2825 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2827 MessageDialog msg (str,
2829 Gtk::MESSAGE_WARNING,
2830 Gtk::BUTTONS_YES_NO,
2834 msg.set_name (X_("OpenExistingDialog"));
2835 msg.set_title (_("Open Existing Session"));
2836 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2837 msg.set_position (Gtk::WIN_POS_CENTER);
2838 pop_back_splash (msg);
2840 switch (msg.run()) {
2849 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2851 BusProfile bus_profile;
2855 bus_profile.master_out_channels = 2;
2856 bus_profile.input_ac = AutoConnectPhysical;
2857 bus_profile.output_ac = AutoConnectMaster;
2858 bus_profile.requested_physical_in = 0; // use all available
2859 bus_profile.requested_physical_out = 0; // use all available
2863 /* get settings from advanced section of NSD */
2865 if (sd.create_master_bus()) {
2866 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2868 bus_profile.master_out_channels = 0;
2871 if (sd.connect_inputs()) {
2872 bus_profile.input_ac = AutoConnectPhysical;
2874 bus_profile.input_ac = AutoConnectOption (0);
2877 bus_profile.output_ac = AutoConnectOption (0);
2879 if (sd.connect_outputs ()) {
2880 if (sd.connect_outs_to_master()) {
2881 bus_profile.output_ac = AutoConnectMaster;
2882 } else if (sd.connect_outs_to_physical()) {
2883 bus_profile.output_ac = AutoConnectPhysical;
2887 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2888 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2891 if (build_session (session_path, session_name, bus_profile)) {
2899 ARDOUR_UI::load_from_application_api (const std::string& path)
2901 ARDOUR_COMMAND_LINE::session_name = path;
2902 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2904 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2906 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2907 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2908 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2909 * -> SessionDialog is not displayed
2912 if (_session_dialog) {
2913 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2914 std::string session_path = path;
2915 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2916 session_path = Glib::path_get_dirname (session_path);
2918 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2919 _session_dialog->set_provided_session (session_name, session_path);
2920 _session_dialog->response (RESPONSE_NONE);
2921 _session_dialog->hide();
2926 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2927 /* /path/to/foo => /path/to/foo, foo */
2928 rv = load_session (path, basename_nosuffix (path));
2930 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2931 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2934 // if load_session fails -> pop up SessionDialog.
2936 ARDOUR_COMMAND_LINE::session_name = "";
2938 if (get_session_parameters (true, false)) {
2944 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2946 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2948 string session_name;
2949 string session_path;
2950 string template_name;
2952 bool likely_new = false;
2953 bool cancel_not_quit;
2955 /* deal with any existing DIRTY session now, rather than later. don't
2956 * treat a non-dirty session this way, so that it stays visible
2957 * as we bring up the new session dialog.
2960 if (_session && ARDOUR_UI::instance()->video_timeline) {
2961 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2964 /* if there is already a session, relabel the button
2965 on the SessionDialog so that we don't Quit directly
2967 cancel_not_quit = (_session != 0);
2969 if (_session && _session->dirty()) {
2970 if (unload_session (false)) {
2971 /* unload cancelled by user */
2974 ARDOUR_COMMAND_LINE::session_name = "";
2977 if (!load_template.empty()) {
2978 should_be_new = true;
2979 template_name = load_template;
2982 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2983 session_path = ARDOUR_COMMAND_LINE::session_name;
2985 if (!session_path.empty()) {
2986 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2987 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2988 /* session/snapshot file, change path to be dir */
2989 session_path = Glib::path_get_dirname (session_path);
2994 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2996 _session_dialog = &session_dialog;
2999 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3001 /* if they named a specific statefile, use it, otherwise they are
3002 just giving a session folder, and we want to use it as is
3003 to find the session.
3006 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3008 if (suffix != string::npos) {
3009 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3010 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3011 session_name = Glib::path_get_basename (session_name);
3013 session_path = ARDOUR_COMMAND_LINE::session_name;
3014 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3019 session_dialog.clear_given ();
3022 if (should_be_new || session_name.empty()) {
3023 /* need the dialog to get info from user */
3025 cerr << "run dialog\n";
3027 switch (session_dialog.run()) {
3028 case RESPONSE_ACCEPT:
3031 /* this is used for async * app->ShouldLoad(). */
3032 continue; // while loop
3035 if (quit_on_cancel) {
3036 // JE - Currently (July 2014) this section can only get reached if the
3037 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3038 // point does NOT indicate an abnormal termination). Therefore, let's
3039 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3041 pthread_cancel_all ();
3049 session_dialog.hide ();
3052 /* if we run the startup dialog again, offer more than just "new session" */
3054 should_be_new = false;
3056 session_name = session_dialog.session_name (likely_new);
3057 session_path = session_dialog.session_folder ();
3063 string::size_type suffix = session_name.find (statefile_suffix);
3065 if (suffix != string::npos) {
3066 session_name = session_name.substr (0, suffix);
3069 /* this shouldn't happen, but we catch it just in case it does */
3071 if (session_name.empty()) {
3075 if (session_dialog.use_session_template()) {
3076 template_name = session_dialog.session_template_name();
3077 _session_is_new = true;
3080 if (session_name[0] == G_DIR_SEPARATOR ||
3081 #ifdef PLATFORM_WINDOWS
3082 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3084 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3085 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3090 /* absolute path or cwd-relative path specified for session name: infer session folder
3091 from what was given.
3094 session_path = Glib::path_get_dirname (session_name);
3095 session_name = Glib::path_get_basename (session_name);
3099 session_path = session_dialog.session_folder();
3101 char illegal = Session::session_name_is_legal (session_name);
3104 MessageDialog msg (session_dialog,
3105 string_compose (_("To ensure compatibility with various systems\n"
3106 "session names may not contain a '%1' character"),
3109 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3114 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3117 if (likely_new && !nsm) {
3119 std::string existing = Glib::build_filename (session_path, session_name);
3121 if (!ask_about_loading_existing_session (existing)) {
3122 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3127 _session_is_new = false;
3132 pop_back_splash (session_dialog);
3133 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3135 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3139 char illegal = Session::session_name_is_legal(session_name);
3142 pop_back_splash (session_dialog);
3143 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3144 "session names may not contain a '%1' character"), illegal));
3146 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3150 _session_is_new = true;
3153 if (likely_new && template_name.empty()) {
3155 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3159 ret = load_session (session_path, session_name, template_name);
3162 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3166 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3167 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3171 /* clear this to avoid endless attempts to load the
3175 ARDOUR_COMMAND_LINE::session_name = "";
3179 _session_dialog = NULL;
3185 ARDOUR_UI::close_session()
3187 if (!check_audioengine (_main_window)) {
3191 if (unload_session (true)) {
3195 ARDOUR_COMMAND_LINE::session_name = "";
3197 if (get_session_parameters (true, false)) {
3202 /** @param snap_name Snapshot name (without .ardour suffix).
3203 * @return -2 if the load failed because we are not connected to the AudioEngine.
3206 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3208 Session *new_session;
3213 unload_status = unload_session ();
3215 if (unload_status < 0) {
3217 } else if (unload_status > 0) {
3223 session_loaded = false;
3225 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3228 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3231 /* this one is special */
3233 catch (AudioEngine::PortRegistrationFailure& err) {
3235 MessageDialog msg (err.what(),
3238 Gtk::BUTTONS_CLOSE);
3240 msg.set_title (_("Port Registration Error"));
3241 msg.set_secondary_text (_("Click the Close button to try again."));
3242 msg.set_position (Gtk::WIN_POS_CENTER);
3243 pop_back_splash (msg);
3246 int response = msg.run ();
3251 case RESPONSE_CANCEL:
3258 catch (SessionException e) {
3259 MessageDialog msg (string_compose(
3260 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3261 path, snap_name, e.what()),
3266 msg.set_title (_("Loading Error"));
3267 msg.set_position (Gtk::WIN_POS_CENTER);
3268 pop_back_splash (msg);
3280 MessageDialog msg (string_compose(
3281 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3287 msg.set_title (_("Loading Error"));
3288 msg.set_position (Gtk::WIN_POS_CENTER);
3289 pop_back_splash (msg);
3301 list<string> const u = new_session->unknown_processors ();
3303 MissingPluginDialog d (_session, u);
3308 if (!new_session->writable()) {
3309 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3314 msg.set_title (_("Read-only Session"));
3315 msg.set_position (Gtk::WIN_POS_CENTER);
3316 pop_back_splash (msg);
3323 /* Now the session been created, add the transport controls */
3324 new_session->add_controllable(roll_controllable);
3325 new_session->add_controllable(stop_controllable);
3326 new_session->add_controllable(goto_start_controllable);
3327 new_session->add_controllable(goto_end_controllable);
3328 new_session->add_controllable(auto_loop_controllable);
3329 new_session->add_controllable(play_selection_controllable);
3330 new_session->add_controllable(rec_controllable);
3332 set_session (new_session);
3334 session_loaded = true;
3337 _session->set_clean ();
3340 #ifdef WINDOWS_VST_SUPPORT
3341 fst_stop_threading();
3345 Timers::TimerSuspender t;
3349 #ifdef WINDOWS_VST_SUPPORT
3350 fst_start_threading();
3359 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3361 Session *new_session;
3364 session_loaded = false;
3365 x = unload_session ();
3373 _session_is_new = true;
3376 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3379 catch (SessionException e) {
3381 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3382 msg.set_title (_("Loading Error"));
3383 msg.set_position (Gtk::WIN_POS_CENTER);
3384 pop_back_splash (msg);
3390 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3391 msg.set_title (_("Loading Error"));
3392 msg.set_position (Gtk::WIN_POS_CENTER);
3393 pop_back_splash (msg);
3398 /* Give the new session the default GUI state, if such things exist */
3401 n = Config->instant_xml (X_("Editor"));
3403 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3404 new_session->add_instant_xml (*n, false);
3406 n = Config->instant_xml (X_("Mixer"));
3408 new_session->add_instant_xml (*n, false);
3411 /* Put the playhead at 0 and scroll fully left */
3412 n = new_session->instant_xml (X_("Editor"));
3414 n->add_property (X_("playhead"), X_("0"));
3415 n->add_property (X_("left-frame"), X_("0"));
3418 set_session (new_session);
3420 session_loaded = true;
3422 new_session->save_state(new_session->name());
3428 ARDOUR_UI::launch_chat ()
3430 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3432 dialog.set_title (_("About the Chat"));
3433 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."));
3435 switch (dialog.run()) {
3438 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3439 #elif defined PLATFORM_WINDOWS
3440 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3442 open_uri("http://webchat.freenode.net/?channels=ardour");
3451 ARDOUR_UI::launch_manual ()
3453 PBD::open_uri (Config->get_tutorial_manual_url());
3457 ARDOUR_UI::launch_reference ()
3459 PBD::open_uri (Config->get_reference_manual_url());
3463 ARDOUR_UI::launch_tracker ()
3465 PBD::open_uri ("http://tracker.ardour.org");
3469 ARDOUR_UI::launch_subscribe ()
3471 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3475 ARDOUR_UI::launch_cheat_sheet ()
3478 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3480 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3485 ARDOUR_UI::launch_website ()
3487 PBD::open_uri ("http://ardour.org");
3491 ARDOUR_UI::launch_website_dev ()
3493 PBD::open_uri ("http://ardour.org/development.html");
3497 ARDOUR_UI::launch_forums ()
3499 PBD::open_uri ("https://community.ardour.org/forums");
3503 ARDOUR_UI::launch_howto_report ()
3505 PBD::open_uri ("http://ardour.org/reporting_bugs");
3509 ARDOUR_UI::loading_message (const std::string& msg)
3511 if (ARDOUR_COMMAND_LINE::no_splash) {
3519 splash->message (msg);
3523 ARDOUR_UI::show_splash ()
3527 splash = new Splash;
3537 ARDOUR_UI::hide_splash ()
3544 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3548 removed = rep.paths.size();
3551 MessageDialog msgd (_main_window,
3552 _("No files were ready for clean-up"),
3556 msgd.set_title (_("Clean-up"));
3557 msgd.set_secondary_text (_("If this seems suprising, \n\
3558 check for any existing snapshots.\n\
3559 These may still include regions that\n\
3560 require some unused files to continue to exist."));
3566 ArdourDialog results (_("Clean-up"), true, false);
3568 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3569 CleanupResultsModelColumns() {
3573 Gtk::TreeModelColumn<std::string> visible_name;
3574 Gtk::TreeModelColumn<std::string> fullpath;
3578 CleanupResultsModelColumns results_columns;
3579 Glib::RefPtr<Gtk::ListStore> results_model;
3580 Gtk::TreeView results_display;
3582 results_model = ListStore::create (results_columns);
3583 results_display.set_model (results_model);
3584 results_display.append_column (list_title, results_columns.visible_name);
3586 results_display.set_name ("CleanupResultsList");
3587 results_display.set_headers_visible (true);
3588 results_display.set_headers_clickable (false);
3589 results_display.set_reorderable (false);
3591 Gtk::ScrolledWindow list_scroller;
3594 Gtk::HBox dhbox; // the hbox for the image and text
3595 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3596 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3598 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3600 const string dead_directory = _session->session_directory().dead_path();
3603 %1 - number of files removed
3604 %2 - location of "dead"
3605 %3 - size of files affected
3606 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3609 const char* bprefix;
3610 double space_adjusted = 0;
3612 if (rep.space < 1000) {
3614 space_adjusted = rep.space;
3615 } else if (rep.space < 1000000) {
3616 bprefix = _("kilo");
3617 space_adjusted = floorf((float)rep.space / 1000.0);
3618 } else if (rep.space < 1000000 * 1000) {
3619 bprefix = _("mega");
3620 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3622 bprefix = _("giga");
3623 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3627 txt.set_markup (string_compose (P_("\
3628 The following file was deleted from %2,\n\
3629 releasing %3 %4bytes of disk space", "\
3630 The following %1 files were deleted from %2,\n\
3631 releasing %3 %4bytes of disk space", removed),
3632 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3634 txt.set_markup (string_compose (P_("\
3635 The following file was not in use and \n\
3636 has been moved to: %2\n\n\
3637 After a restart of %5\n\n\
3638 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3639 will release an additional %3 %4bytes of disk space.\n", "\
3640 The following %1 files were not in use and \n\
3641 have been moved to: %2\n\n\
3642 After a restart of %5\n\n\
3643 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3644 will release an additional %3 %4bytes of disk space.\n", removed),
3645 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3648 dhbox.pack_start (*dimage, true, false, 5);
3649 dhbox.pack_start (txt, true, false, 5);
3651 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3652 TreeModel::Row row = *(results_model->append());
3653 row[results_columns.visible_name] = *i;
3654 row[results_columns.fullpath] = *i;
3657 list_scroller.add (results_display);
3658 list_scroller.set_size_request (-1, 150);
3659 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3661 dvbox.pack_start (dhbox, true, false, 5);
3662 dvbox.pack_start (list_scroller, true, false, 5);
3663 ddhbox.pack_start (dvbox, true, false, 5);
3665 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3666 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3667 results.set_default_response (RESPONSE_CLOSE);
3668 results.set_position (Gtk::WIN_POS_MOUSE);
3670 results_display.show();
3671 list_scroller.show();
3678 //results.get_vbox()->show();
3679 results.set_resizable (false);
3686 ARDOUR_UI::cleanup ()
3688 if (_session == 0) {
3689 /* shouldn't happen: menu item is insensitive */
3694 MessageDialog checker (_("Are you sure you want to clean-up?"),
3696 Gtk::MESSAGE_QUESTION,
3699 checker.set_title (_("Clean-up"));
3701 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3702 ALL undo/redo information will be lost if you clean-up.\n\
3703 Clean-up will move all unused files to a \"dead\" location."));
3705 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3706 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3707 checker.set_default_response (RESPONSE_CANCEL);
3709 checker.set_name (_("CleanupDialog"));
3710 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3711 checker.set_position (Gtk::WIN_POS_MOUSE);
3713 switch (checker.run()) {
3714 case RESPONSE_ACCEPT:
3720 ARDOUR::CleanupReport rep;
3722 editor->prepare_for_cleanup ();
3724 /* do not allow flush until a session is reloaded */
3726 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3728 act->set_sensitive (false);
3731 if (_session->cleanup_sources (rep)) {
3732 editor->finish_cleanup ();
3736 editor->finish_cleanup ();
3739 display_cleanup_results (rep, _("Cleaned Files"), false);
3743 ARDOUR_UI::flush_trash ()
3745 if (_session == 0) {
3746 /* shouldn't happen: menu item is insensitive */
3750 ARDOUR::CleanupReport rep;
3752 if (_session->cleanup_trash_sources (rep)) {
3756 display_cleanup_results (rep, _("deleted file"), true);
3760 ARDOUR_UI::cleanup_peakfiles ()
3762 if (_session == 0) {
3763 /* shouldn't happen: menu item is insensitive */
3767 if (! _session->can_cleanup_peakfiles ()) {
3771 // get all region-views in this session
3773 TrackViewList empty;
3775 editor->get_regions_after(rs, (framepos_t) 0, empty);
3776 std::list<RegionView*> views = rs.by_layer();
3778 // remove displayed audio-region-views waveforms
3779 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3780 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3781 if (!arv) { continue ; }
3782 arv->delete_waves();
3785 // cleanup peak files:
3786 // - stop pending peakfile threads
3787 // - close peakfiles if any
3788 // - remove peak dir in session
3789 // - setup peakfiles (background thread)
3790 _session->cleanup_peakfiles ();
3792 // re-add waves to ARV
3793 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3794 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3795 if (!arv) { continue ; }
3796 arv->create_waves();
3801 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3803 uint32_t order_hint = UINT32_MAX;
3805 if (editor->get_selection().tracks.empty()) {
3810 we want the new routes to have their order keys set starting from
3811 the highest order key in the selection + 1 (if available).
3814 if (place == AddRouteDialog::AfterSelection) {
3815 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3817 order_hint = rtav->route()->order_key();
3820 } else if (place == AddRouteDialog::BeforeSelection) {
3821 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3823 order_hint = rtav->route()->order_key();
3825 } else if (place == AddRouteDialog::First) {
3828 /* leave order_hint at UINT32_MAX */
3831 if (order_hint == UINT32_MAX) {
3832 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3833 * not setting an order hint will place new routes last.
3838 _session->set_order_hint (order_hint);
3840 /* create a gap in the existing route order keys to accomodate new routes.*/
3841 boost::shared_ptr <RouteList> rd = _session->get_routes();
3842 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3843 boost::shared_ptr<Route> rt (*ri);
3845 if (rt->is_monitor()) {
3849 if (rt->order_key () >= order_hint) {
3850 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3856 ARDOUR_UI::start_duplicate_routes ()
3858 if (!duplicate_routes_dialog) {
3859 duplicate_routes_dialog = new DuplicateRouteDialog;
3862 if (duplicate_routes_dialog->restart (_session)) {
3866 duplicate_routes_dialog->present ();
3870 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3878 if (add_route_dialog->is_visible()) {
3879 /* we're already doing this */
3883 ResponseType r = (ResponseType) add_route_dialog->run ();
3885 add_route_dialog->hide();
3888 case RESPONSE_ACCEPT:
3895 if ((count = add_route_dialog->count()) <= 0) {
3899 setup_order_hint(add_route_dialog->insert_at());
3901 string template_path = add_route_dialog->track_template();
3902 DisplaySuspender ds;
3904 if (!template_path.empty()) {
3905 if (add_route_dialog->name_template_is_default()) {
3906 _session->new_route_from_template (count, template_path, string());
3908 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3913 ChanCount input_chan= add_route_dialog->channels ();
3914 ChanCount output_chan;
3915 string name_template = add_route_dialog->name_template ();
3916 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3917 RouteGroup* route_group = add_route_dialog->route_group ();
3918 AutoConnectOption oac = Config->get_output_auto_connect();
3920 if (oac & AutoConnectMaster) {
3921 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3922 output_chan.set (DataType::MIDI, 0);
3924 output_chan = input_chan;
3927 /* XXX do something with name template */
3929 switch (add_route_dialog->type_wanted()) {
3930 case AddRouteDialog::AudioTrack:
3931 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3933 case AddRouteDialog::MidiTrack:
3934 session_add_midi_track (route_group, count, name_template, instrument);
3936 case AddRouteDialog::MixedTrack:
3937 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3939 case AddRouteDialog::AudioBus:
3940 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3946 ARDOUR_UI::add_lua_script ()
3952 LuaScriptInfoPtr spi;
3953 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
3954 switch (ss.run ()) {
3955 case Gtk::RESPONSE_ACCEPT:
3962 std::string script = "";
3965 script = Glib::file_get_contents (spi->path);
3966 } catch (Glib::FileError e) {
3967 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
3968 MessageDialog am (msg);
3973 LuaScriptParamList lsp = LuaScripting::session_script_params (spi);
3974 std::vector<std::string> reg = _session->registered_lua_functions ();
3976 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
3977 switch (spd.run ()) {
3978 case Gtk::RESPONSE_ACCEPT:
3985 _session->register_lua_function (spd.name(), script, lsp);
3986 } catch (luabridge::LuaException const& e) {
3987 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
3988 MessageDialog am (msg);
3990 } catch (SessionException e) {
3991 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
3992 MessageDialog am (msg);
3998 ARDOUR_UI::remove_lua_script ()
4003 if (_session->registered_lua_function_count () == 0) {
4004 string msg = _("There are no active Lua session scripts present in this session.");
4005 MessageDialog am (msg);
4010 std::vector<std::string> reg = _session->registered_lua_functions ();
4011 SessionScriptManager sm ("Remove Lua Session Script", reg);
4012 switch (sm.run ()) {
4013 case Gtk::RESPONSE_ACCEPT:
4019 _session->unregister_lua_function (sm.name());
4020 } catch (luabridge::LuaException const& e) {
4021 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4022 MessageDialog am (msg);
4028 ARDOUR_UI::stop_video_server (bool ask_confirm)
4030 if (!video_server_process && ask_confirm) {
4031 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4033 if (video_server_process) {
4035 ArdourDialog confirm (_("Stop Video-Server"), true);
4036 Label m (_("Do you really want to stop the Video Server?"));
4037 confirm.get_vbox()->pack_start (m, true, true);
4038 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4039 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4040 confirm.show_all ();
4041 if (confirm.run() == RESPONSE_CANCEL) {
4045 delete video_server_process;
4046 video_server_process =0;
4051 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4053 ARDOUR_UI::start_video_server( float_window, true);
4057 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4063 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4064 if (video_server_process) {
4065 popup_error(_("The Video Server is already started."));
4067 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4073 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4075 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4077 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4079 video_server_dialog->set_transient_for (*float_window);
4082 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4083 video_server_dialog->hide();
4085 ResponseType r = (ResponseType) video_server_dialog->run ();
4086 video_server_dialog->hide();
4087 if (r != RESPONSE_ACCEPT) { return false; }
4088 if (video_server_dialog->show_again()) {
4089 Config->set_show_video_server_dialog(false);
4093 std::string icsd_exec = video_server_dialog->get_exec_path();
4094 std::string icsd_docroot = video_server_dialog->get_docroot();
4095 if (icsd_docroot.empty()) {
4096 #ifndef PLATFORM_WINDOWS
4097 icsd_docroot = X_("/");
4099 icsd_docroot = X_("C:\\");
4104 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4105 warning << _("Specified docroot is not an existing directory.") << endmsg;
4108 #ifndef PLATFORM_WINDOWS
4109 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4110 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4111 warning << _("Given Video Server is not an executable file.") << endmsg;
4115 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4116 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4117 warning << _("Given Video Server is not an executable file.") << endmsg;
4123 argp=(char**) calloc(9,sizeof(char*));
4124 argp[0] = strdup(icsd_exec.c_str());
4125 argp[1] = strdup("-P");
4126 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4127 argp[3] = strdup("-p");
4128 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4129 argp[5] = strdup("-C");
4130 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4131 argp[7] = strdup(icsd_docroot.c_str());
4133 stop_video_server();
4135 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4136 Config->set_video_advanced_setup(false);
4138 std::ostringstream osstream;
4139 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4140 Config->set_video_server_url(osstream.str());
4141 Config->set_video_server_docroot(icsd_docroot);
4142 Config->set_video_advanced_setup(true);
4145 if (video_server_process) {
4146 delete video_server_process;
4149 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4150 if (video_server_process->start()) {
4151 warning << _("Cannot launch the video-server") << endmsg;
4154 int timeout = 120; // 6 sec
4155 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4156 Glib::usleep (50000);
4158 if (--timeout <= 0 || !video_server_process->is_running()) break;
4161 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4163 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4164 delete video_server_process;
4165 video_server_process = 0;
4173 ARDOUR_UI::add_video (Gtk::Window* float_window)
4179 if (!start_video_server(float_window, false)) {
4180 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4185 add_video_dialog->set_transient_for (*float_window);
4188 if (add_video_dialog->is_visible()) {
4189 /* we're already doing this */
4193 ResponseType r = (ResponseType) add_video_dialog->run ();
4194 add_video_dialog->hide();
4195 if (r != RESPONSE_ACCEPT) { return; }
4197 bool local_file, orig_local_file;
4198 std::string path = add_video_dialog->file_name(local_file);
4200 std::string orig_path = path;
4201 orig_local_file = local_file;
4203 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4205 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4206 warning << string_compose(_("could not open %1"), path) << endmsg;
4209 if (!local_file && path.length() == 0) {
4210 warning << _("no video-file selected") << endmsg;
4214 std::string audio_from_video;
4215 bool detect_ltc = false;
4217 switch (add_video_dialog->import_option()) {
4218 case VTL_IMPORT_TRANSCODE:
4220 TranscodeVideoDialog *transcode_video_dialog;
4221 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4222 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4223 transcode_video_dialog->hide();
4224 if (r != RESPONSE_ACCEPT) {
4225 delete transcode_video_dialog;
4229 audio_from_video = transcode_video_dialog->get_audiofile();
4231 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4234 else if (!audio_from_video.empty()) {
4235 editor->embed_audio_from_video(
4237 video_timeline->get_offset(),
4238 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4241 switch (transcode_video_dialog->import_option()) {
4242 case VTL_IMPORT_TRANSCODED:
4243 path = transcode_video_dialog->get_filename();
4246 case VTL_IMPORT_REFERENCE:
4249 delete transcode_video_dialog;
4252 delete transcode_video_dialog;
4256 case VTL_IMPORT_NONE:
4260 /* strip _session->session_directory().video_path() from video file if possible */
4261 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4262 path=path.substr(_session->session_directory().video_path().size());
4263 if (path.at(0) == G_DIR_SEPARATOR) {
4264 path=path.substr(1);
4268 video_timeline->set_update_session_fps(auto_set_session_fps);
4270 if (video_timeline->video_file_info(path, local_file)) {
4271 XMLNode* node = new XMLNode(X_("Videotimeline"));
4272 node->add_property (X_("Filename"), path);
4273 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4274 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4275 if (orig_local_file) {
4276 node->add_property (X_("OriginalVideoFile"), orig_path);
4278 node->remove_property (X_("OriginalVideoFile"));
4280 _session->add_extra_xml (*node);
4281 _session->set_dirty ();
4283 if (!audio_from_video.empty() && detect_ltc) {
4284 std::vector<LTCFileReader::LTCMap> ltc_seq;
4287 /* TODO ask user about TV standard (LTC alignment if any) */
4288 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4289 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4291 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4293 /* TODO seek near end of file, and read LTC until end.
4294 * if it fails to find any LTC frames, scan complete file
4296 * calculate drift of LTC compared to video-duration,
4297 * ask user for reference (timecode from start/mid/end)
4300 // LTCFileReader will have written error messages
4303 ::g_unlink(audio_from_video.c_str());
4305 if (ltc_seq.size() == 0) {
4306 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4308 /* the very first TC in the file is somteimes not aligned properly */
4309 int i = ltc_seq.size() -1;
4310 ARDOUR::frameoffset_t video_start_offset =
4311 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4312 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4313 video_timeline->set_offset(video_start_offset);
4317 _session->maybe_update_session_range(
4318 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4319 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4322 if (add_video_dialog->launch_xjadeo() && local_file) {
4323 editor->set_xjadeo_sensitive(true);
4324 editor->toggle_xjadeo_proc(1);
4326 editor->toggle_xjadeo_proc(0);
4328 editor->toggle_ruler_video(true);
4333 ARDOUR_UI::remove_video ()
4335 video_timeline->close_session();
4336 editor->toggle_ruler_video(false);
4339 video_timeline->set_offset_locked(false);
4340 video_timeline->set_offset(0);
4342 /* delete session state */
4343 XMLNode* node = new XMLNode(X_("Videotimeline"));
4344 _session->add_extra_xml(*node);
4345 node = new XMLNode(X_("Videomonitor"));
4346 _session->add_extra_xml(*node);
4347 node = new XMLNode(X_("Videoexport"));
4348 _session->add_extra_xml(*node);
4349 stop_video_server();
4353 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4355 if (localcacheonly) {
4356 video_timeline->vmon_update();
4358 video_timeline->flush_cache();
4360 editor->queue_visual_videotimeline_update();
4364 ARDOUR_UI::export_video (bool range)
4366 if (ARDOUR::Config->get_show_video_export_info()) {
4367 ExportVideoInfobox infobox (_session);
4368 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4369 if (infobox.show_again()) {
4370 ARDOUR::Config->set_show_video_export_info(false);
4373 case GTK_RESPONSE_YES:
4374 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4380 export_video_dialog->set_session (_session);
4381 export_video_dialog->apply_state(editor->get_selection().time, range);
4382 export_video_dialog->run ();
4383 export_video_dialog->hide ();
4387 ARDOUR_UI::mixer_settings () const
4392 node = _session->instant_xml(X_("Mixer"));
4394 node = Config->instant_xml(X_("Mixer"));
4398 node = new XMLNode (X_("Mixer"));
4405 ARDOUR_UI::main_window_settings () const
4410 node = _session->instant_xml(X_("Main"));
4412 node = Config->instant_xml(X_("Main"));
4416 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4417 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4422 node = new XMLNode (X_("Main"));
4429 ARDOUR_UI::editor_settings () const
4434 node = _session->instant_xml(X_("Editor"));
4436 node = Config->instant_xml(X_("Editor"));
4440 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4441 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4446 node = new XMLNode (X_("Editor"));
4453 ARDOUR_UI::keyboard_settings () const
4457 node = Config->extra_xml(X_("Keyboard"));
4460 node = new XMLNode (X_("Keyboard"));
4467 ARDOUR_UI::create_xrun_marker (framepos_t where)
4470 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4471 _session->locations()->add (location);
4476 ARDOUR_UI::halt_on_xrun_message ()
4478 cerr << "HALT on xrun\n";
4479 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4484 ARDOUR_UI::xrun_handler (framepos_t where)
4490 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4492 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4493 create_xrun_marker(where);
4496 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4497 halt_on_xrun_message ();
4502 ARDOUR_UI::disk_overrun_handler ()
4504 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4506 if (!have_disk_speed_dialog_displayed) {
4507 have_disk_speed_dialog_displayed = true;
4508 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4509 The disk system on your computer\n\
4510 was not able to keep up with %1.\n\
4512 Specifically, it failed to write data to disk\n\
4513 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4514 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4520 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4521 static MessageDialog *scan_dlg = NULL;
4522 static ProgressBar *scan_pbar = NULL;
4523 static HBox *scan_tbox = NULL;
4524 static Gtk::Button *scan_timeout_button;
4527 ARDOUR_UI::cancel_plugin_scan ()
4529 PluginManager::instance().cancel_plugin_scan();
4533 ARDOUR_UI::cancel_plugin_timeout ()
4535 PluginManager::instance().cancel_plugin_timeout();
4536 scan_timeout_button->set_sensitive (false);
4540 ARDOUR_UI::plugin_scan_timeout (int timeout)
4542 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4546 scan_pbar->set_sensitive (false);
4547 scan_timeout_button->set_sensitive (true);
4548 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4551 scan_pbar->set_sensitive (false);
4552 scan_timeout_button->set_sensitive (false);
4558 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4560 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4564 const bool cancelled = PluginManager::instance().cancelled();
4565 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4566 if (cancelled && scan_dlg->is_mapped()) {
4571 if (cancelled || !can_cancel) {
4576 static Gtk::Button *cancel_button;
4578 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4579 VBox* vbox = scan_dlg->get_vbox();
4580 vbox->set_size_request(400,-1);
4581 scan_dlg->set_title (_("Scanning for plugins"));
4583 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4584 cancel_button->set_name ("EditorGTKButton");
4585 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4586 cancel_button->show();
4588 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4590 scan_tbox = manage( new HBox() );
4592 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4593 scan_timeout_button->set_name ("EditorGTKButton");
4594 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4595 scan_timeout_button->show();
4597 scan_pbar = manage(new ProgressBar());
4598 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4599 scan_pbar->set_text(_("Scan Timeout"));
4602 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4603 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4605 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4608 assert(scan_dlg && scan_tbox && cancel_button);
4610 if (type == X_("closeme")) {
4614 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4617 if (!can_cancel || !cancelled) {
4618 scan_timeout_button->set_sensitive(false);
4620 cancel_button->set_sensitive(can_cancel && !cancelled);
4626 ARDOUR_UI::gui_idle_handler ()
4629 /* due to idle calls, gtk_events_pending() may always return true */
4630 while (gtk_events_pending() && --timeout) {
4631 gtk_main_iteration ();
4636 ARDOUR_UI::disk_underrun_handler ()
4638 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4640 if (!have_disk_speed_dialog_displayed) {
4641 have_disk_speed_dialog_displayed = true;
4642 MessageDialog* msg = new MessageDialog (
4643 _main_window, string_compose (_("The disk system on your computer\n\
4644 was not able to keep up with %1.\n\
4646 Specifically, it failed to read data from disk\n\
4647 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4648 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4654 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4656 have_disk_speed_dialog_displayed = false;
4661 ARDOUR_UI::session_dialog (std::string msg)
4663 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4667 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4674 ARDOUR_UI::pending_state_dialog ()
4676 HBox* hbox = manage (new HBox());
4677 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4678 ArdourDialog dialog (_("Crash Recovery"), true);
4679 Label message (string_compose (_("\
4680 This session appears to have been in the\n\
4681 middle of recording when %1 or\n\
4682 the computer was shutdown.\n\
4684 %1 can recover any captured audio for\n\
4685 you, or it can ignore it. Please decide\n\
4686 what you would like to do.\n"), PROGRAM_NAME));
4687 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4688 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4689 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4690 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4691 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4692 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4693 dialog.set_default_response (RESPONSE_ACCEPT);
4694 dialog.set_position (WIN_POS_CENTER);
4699 switch (dialog.run ()) {
4700 case RESPONSE_ACCEPT:
4708 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4710 HBox* hbox = new HBox();
4711 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4712 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4713 Label message (string_compose (_("\
4714 This session was created with a sample rate of %1 Hz, but\n\
4715 %2 is currently running at %3 Hz. If you load this session,\n\
4716 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4718 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4719 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4720 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4721 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4722 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4723 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4724 dialog.set_default_response (RESPONSE_ACCEPT);
4725 dialog.set_position (WIN_POS_CENTER);
4730 switch (dialog.run()) {
4731 case RESPONSE_ACCEPT:
4741 ARDOUR_UI::use_config ()
4743 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4745 set_transport_controllable_state (*node);
4750 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4752 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4753 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4755 primary_clock->set (pos);
4758 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4759 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4761 secondary_clock->set (pos);
4764 if (big_clock_window) {
4765 big_clock->set (pos);
4767 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4771 ARDOUR_UI::step_edit_status_change (bool yn)
4773 // XXX should really store pre-step edit status of things
4774 // we make insensitive
4777 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4778 rec_button.set_sensitive (false);
4780 rec_button.unset_active_state ();;
4781 rec_button.set_sensitive (true);
4786 ARDOUR_UI::record_state_changed ()
4788 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4790 if (!_session || !big_clock_window) {
4791 /* why bother - the clock isn't visible */
4795 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4796 big_clock->set_active (true);
4798 big_clock->set_active (false);
4803 ARDOUR_UI::first_idle ()
4806 _session->allow_auto_play (true);
4810 editor->first_idle();
4813 Keyboard::set_can_save_keybindings (true);
4818 ARDOUR_UI::store_clock_modes ()
4820 XMLNode* node = new XMLNode(X_("ClockModes"));
4822 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4823 XMLNode* child = new XMLNode (X_("Clock"));
4825 child->add_property (X_("name"), (*x)->name());
4826 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4827 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4829 node->add_child_nocopy (*child);
4832 _session->add_extra_xml (*node);
4833 _session->set_dirty ();
4836 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4837 : Controllable (name), ui (u), type(tp)
4843 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4846 /* do nothing: these are radio-style actions */
4850 const char *action = 0;
4854 action = X_("Roll");
4857 action = X_("Stop");
4860 action = X_("GotoStart");
4863 action = X_("GotoEnd");
4866 action = X_("Loop");
4869 action = X_("PlaySelection");
4872 action = X_("Record");
4882 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4890 ARDOUR_UI::TransportControllable::get_value (void) const
4917 ARDOUR_UI::setup_profile ()
4919 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4920 Profile->set_small_screen ();
4923 if (g_getenv ("TRX")) {
4924 Profile->set_trx ();
4927 if (g_getenv ("MIXBUS")) {
4928 Profile->set_mixbus ();
4933 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4935 MissingFileDialog dialog (s, str, type);
4940 int result = dialog.run ();
4947 return 1; // quit entire session load
4950 result = dialog.get_action ();
4956 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4958 AmbiguousFileDialog dialog (file, hits);
4965 return dialog.get_which ();
4968 /** Allocate our thread-local buffers */
4970 ARDOUR_UI::get_process_buffers ()
4972 _process_thread->get_buffers ();
4975 /** Drop our thread-local buffers */
4977 ARDOUR_UI::drop_process_buffers ()
4979 _process_thread->drop_buffers ();
4983 ARDOUR_UI::feedback_detected ()
4985 _feedback_exists = true;
4989 ARDOUR_UI::successful_graph_sort ()
4991 _feedback_exists = false;
4995 ARDOUR_UI::midi_panic ()
4998 _session->midi_panic();
5003 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5005 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5006 const char* end_big = "</span>";
5007 const char* start_mono = "<tt>";
5008 const char* end_mono = "</tt>";
5010 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5011 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5012 "From now on, use the -2000 version with older versions of %3"),
5013 xml_path, backup_path, PROGRAM_NAME,
5015 start_mono, end_mono), true);
5022 ARDOUR_UI::reset_peak_display ()
5024 if (!_session || !_session->master_out() || !editor_meter) return;
5025 editor_meter->clear_meters();
5026 editor_meter_max_peak = -INFINITY;
5027 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5031 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5033 if (!_session || !_session->master_out()) return;
5034 if (group == _session->master_out()->route_group()) {
5035 reset_peak_display ();
5040 ARDOUR_UI::reset_route_peak_display (Route* route)
5042 if (!_session || !_session->master_out()) return;
5043 if (_session->master_out().get() == route) {
5044 reset_peak_display ();
5049 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5051 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5052 audio_midi_setup->set_position (WIN_POS_CENTER);
5057 response = audio_midi_setup->run();
5059 case Gtk::RESPONSE_OK:
5060 if (!AudioEngine::instance()->running()) {
5074 ARDOUR_UI::transport_numpad_timeout ()
5076 _numpad_locate_happening = false;
5077 if (_numpad_timeout_connection.connected() )
5078 _numpad_timeout_connection.disconnect();
5083 ARDOUR_UI::transport_numpad_decimal ()
5085 _numpad_timeout_connection.disconnect();
5087 if (_numpad_locate_happening) {
5088 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5089 _numpad_locate_happening = false;
5091 _pending_locate_num = 0;
5092 _numpad_locate_happening = true;
5093 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5098 ARDOUR_UI::transport_numpad_event (int num)
5100 if ( _numpad_locate_happening ) {
5101 _pending_locate_num = _pending_locate_num*10 + num;
5104 case 0: toggle_roll(false, false); break;
5105 case 1: transport_rewind(1); break;
5106 case 2: transport_forward(1); break;
5107 case 3: transport_record(true); break;
5108 case 4: toggle_session_auto_loop(); break;
5109 case 5: transport_record(false); toggle_session_auto_loop(); break;
5110 case 6: toggle_punch(); break;
5111 case 7: toggle_click(); break;
5112 case 8: toggle_auto_return(); break;
5113 case 9: toggle_follow_edits(); break;
5119 ARDOUR_UI::set_flat_buttons ()
5121 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5125 ARDOUR_UI::audioengine_became_silent ()
5127 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5129 Gtk::MESSAGE_WARNING,
5133 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5135 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5136 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5137 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5138 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5139 Gtk::HBox pay_button_box;
5140 Gtk::HBox subscribe_button_box;
5142 pay_button_box.pack_start (pay_button, true, false);
5143 subscribe_button_box.pack_start (subscribe_button, true, false);
5145 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 */
5147 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5148 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5150 msg.get_vbox()->pack_start (pay_label);
5151 msg.get_vbox()->pack_start (pay_button_box);
5152 msg.get_vbox()->pack_start (subscribe_label);
5153 msg.get_vbox()->pack_start (subscribe_button_box);
5155 msg.get_vbox()->show_all ();
5157 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5158 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5159 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5164 case Gtk::RESPONSE_YES:
5165 AudioEngine::instance()->reset_silence_countdown ();
5168 case Gtk::RESPONSE_NO:
5170 save_state_canfail ("");
5174 case Gtk::RESPONSE_CANCEL:
5176 /* don't reset, save session and exit */
5182 ARDOUR_UI::hide_application ()
5184 Application::instance ()-> hide ();
5188 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5190 /* icons, titles, WM stuff */
5192 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5194 if (window_icons.empty()) {
5195 Glib::RefPtr<Gdk::Pixbuf> icon;
5196 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5197 window_icons.push_back (icon);
5199 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5200 window_icons.push_back (icon);
5202 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5203 window_icons.push_back (icon);
5205 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5206 window_icons.push_back (icon);
5210 if (!window_icons.empty()) {
5211 window.set_default_icon_list (window_icons);
5214 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5216 if (!name.empty()) {
5220 window.set_title (title.get_string());
5221 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5223 window.set_flags (CAN_FOCUS);
5224 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5226 /* This is a hack to ensure that GTK-accelerators continue to
5227 * work. Once we switch over to entirely native bindings, this will be
5228 * unnecessary and should be removed
5230 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5232 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5233 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5234 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5235 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5239 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5241 Gtkmm2ext::Bindings* bindings = 0;
5242 Gtk::Window* window = 0;
5244 /* until we get ardour bindings working, we are not handling key
5248 if (ev->type != GDK_KEY_PRESS) {
5252 if (event_window == &_main_window) {
5254 window = event_window;
5256 /* find current tab contents */
5258 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5260 /* see if it uses the ardour binding system */
5263 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5266 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5270 window = event_window;
5272 /* see if window uses ardour binding system */
5274 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5277 /* An empty binding set is treated as if it doesn't exist */
5279 if (bindings && bindings->empty()) {
5283 return key_press_focus_accelerator_handler (*window, ev, bindings);
5287 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5289 GtkWindow* win = window.gobj();
5290 GtkWidget* focus = gtk_window_get_focus (win);
5291 bool special_handling_of_unmodified_accelerators = false;
5292 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5296 /* some widget has keyboard focus */
5298 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5300 /* A particular kind of focusable widget currently has keyboard
5301 * focus. All unmodified key events should go to that widget
5302 * first and not be used as an accelerator by default
5305 special_handling_of_unmodified_accelerators = true;
5309 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",
5312 show_gdk_event_state (ev->state),
5313 special_handling_of_unmodified_accelerators,
5314 Keyboard::some_magic_widget_has_focus(),
5316 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5317 ((ev->state & mask) ? "yes" : "no")));
5319 /* This exists to allow us to override the way GTK handles
5320 key events. The normal sequence is:
5322 a) event is delivered to a GtkWindow
5323 b) accelerators/mnemonics are activated
5324 c) if (b) didn't handle the event, propagate to
5325 the focus widget and/or focus chain
5327 The problem with this is that if the accelerators include
5328 keys without modifiers, such as the space bar or the
5329 letter "e", then pressing the key while typing into
5330 a text entry widget results in the accelerator being
5331 activated, instead of the desired letter appearing
5334 There is no good way of fixing this, but this
5335 represents a compromise. The idea is that
5336 key events involving modifiers (not Shift)
5337 get routed into the activation pathway first, then
5338 get propagated to the focus widget if necessary.
5340 If the key event doesn't involve modifiers,
5341 we deliver to the focus widget first, thus allowing
5342 it to get "normal text" without interference
5345 Of course, this can also be problematic: if there
5346 is a widget with focus, then it will swallow
5347 all "normal text" accelerators.
5351 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5353 /* no special handling or there are modifiers in effect: accelerate first */
5355 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5356 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5357 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5359 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5360 KeyboardKey k (ev->state, ev->keyval);
5364 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5366 if (bindings->activate (k, Bindings::Press)) {
5367 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5372 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5374 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5375 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5379 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5381 if (gtk_window_propagate_key_event (win, ev)) {
5382 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5388 /* no modifiers, propagate first */
5390 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5392 if (gtk_window_propagate_key_event (win, ev)) {
5393 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5397 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5398 KeyboardKey k (ev->state, ev->keyval);
5402 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5405 if (bindings->activate (k, Bindings::Press)) {
5406 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5412 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5414 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5415 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5420 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5425 ARDOUR_UI::load_bindings ()
5427 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5428 error << _("Global keybindings are missing") << endmsg;
5433 ARDOUR_UI::cancel_solo ()
5436 if (_session->soloing()) {
5437 _session->set_solo (_session->get_routes(), false);
5438 } else if (_session->listening()) {
5439 _session->set_listen (_session->get_routes(), false);
5442 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window