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 #include "timecode/time.h"
105 typedef uint64_t microseconds_t;
110 #include "add_route_dialog.h"
111 #include "ambiguous_file_dialog.h"
112 #include "ardour_ui.h"
113 #include "audio_clock.h"
114 #include "audio_region_view.h"
115 #include "big_clock_window.h"
116 #include "bundle_manager.h"
117 #include "duplicate_routes_dialog.h"
119 #include "engine_dialog.h"
120 #include "export_video_dialog.h"
121 #include "export_video_infobox.h"
122 #include "gain_meter.h"
123 #include "global_port_matrix.h"
124 #include "gui_object.h"
125 #include "gui_thread.h"
126 #include "keyboard.h"
127 #include "keyeditor.h"
128 #include "location_ui.h"
129 #include "luawindow.h"
130 #include "main_clock.h"
131 #include "missing_file_dialog.h"
132 #include "missing_plugin_dialog.h"
133 #include "mixer_ui.h"
134 #include "meterbridge.h"
135 #include "mouse_cursors.h"
138 #include "pingback.h"
139 #include "processor_box.h"
140 #include "prompter.h"
141 #include "public_editor.h"
142 #include "rc_option_editor.h"
143 #include "route_time_axis.h"
144 #include "route_params_ui.h"
145 #include "save_as_dialog.h"
146 #include "script_selector.h"
147 #include "session_dialog.h"
148 #include "session_metadata_dialog.h"
149 #include "session_option_editor.h"
150 #include "shuttle_control.h"
151 #include "speaker_dialog.h"
154 #include "theme_manager.h"
155 #include "time_axis_view_item.h"
158 #include "video_server_dialog.h"
159 #include "add_video_dialog.h"
160 #include "transcode_video_dialog.h"
164 using namespace ARDOUR;
165 using namespace ARDOUR_UI_UTILS;
167 using namespace Gtkmm2ext;
170 using namespace Editing;
172 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
174 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
175 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
178 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
180 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
181 "Would you like these files to be copied and used for %1 %2.x?\n\n"
182 "(This will require you to restart %1.)"),
183 PROGRAM_NAME, PROGRAM_VERSION, version),
184 false, /* no markup */
187 true /* modal, though it hardly matters since it is the only window */
190 msg.set_default_response (Gtk::RESPONSE_YES);
193 return (msg.run() == Gtk::RESPONSE_YES);
197 libxml_generic_error_func (void* /* parsing_context*/,
205 vsnprintf (buf, sizeof (buf), msg, ap);
206 error << buf << endmsg;
211 libxml_structured_error_func (void* /* parsing_context*/,
219 replace_all (msg, "\n", "");
221 if (err->file && err->line) {
222 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
225 error << ':' << err->int2;
232 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
233 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
234 , session_loaded (false)
235 , gui_object_state (new GUIObjectState)
236 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
237 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
238 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
240 , global_actions (X_("global"))
241 , ignore_dual_punch (false)
246 , _mixer_on_top (false)
247 , _initial_verbose_plugin_scan (false)
248 , first_time_engine_run (true)
249 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
250 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
251 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
252 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
253 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
254 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
255 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
256 , auto_return_button (ArdourButton::led_default_elements)
257 , follow_edits_button (ArdourButton::led_default_elements)
258 , auto_input_button (ArdourButton::led_default_elements)
259 , auditioning_alert_button (_("Audition"))
260 , solo_alert_button (_("Solo"))
261 , feedback_alert_button (_("Feedback"))
262 , error_alert_button ( ArdourButton::just_led_default_elements )
264 , editor_meter_peak_display()
265 , _numpad_locate_happening (false)
266 , _session_is_new (false)
267 , last_key_press_time (0)
271 , rc_option_editor (0)
272 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
273 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
274 , about (X_("about"), _("About"))
275 , location_ui (X_("locations"), _("Locations"))
276 , route_params (X_("inspector"), _("Tracks and Busses"))
277 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
278 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
279 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
280 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
281 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
282 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
283 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
284 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
285 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
286 , video_server_process (0)
288 , have_configure_timeout (false)
289 , last_configure_time (0)
291 , have_disk_speed_dialog_displayed (false)
292 , _status_bar_visibility (X_("status-bar"))
293 , _feedback_exists (false)
294 , _log_not_acknowledged (LogLevelNone)
295 , duplicate_routes_dialog (0)
296 , editor_visibility_button (S_("Window|Editor"))
297 , mixer_visibility_button (S_("Window|Mixer"))
298 , prefs_visibility_button (S_("Window|Preferences"))
300 Gtkmm2ext::init (localedir);
302 UIConfiguration::instance().post_gui_init ();
304 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
305 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
307 /* configuration was modified, exit immediately */
311 if (theArdourUI == 0) {
315 /* stop libxml from spewing to stdout/stderr */
317 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
318 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
320 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
321 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
322 UIConfiguration::instance().map_parameters (pc);
324 roll_button.set_controllable (roll_controllable);
325 stop_button.set_controllable (stop_controllable);
326 goto_start_button.set_controllable (goto_start_controllable);
327 goto_end_button.set_controllable (goto_end_controllable);
328 auto_loop_button.set_controllable (auto_loop_controllable);
329 play_selection_button.set_controllable (play_selection_controllable);
330 rec_button.set_controllable (rec_controllable);
332 roll_button.set_name ("transport button");
333 stop_button.set_name ("transport button");
334 goto_start_button.set_name ("transport button");
335 goto_end_button.set_name ("transport button");
336 auto_loop_button.set_name ("transport button");
337 play_selection_button.set_name ("transport button");
338 rec_button.set_name ("transport recenable button");
339 midi_panic_button.set_name ("transport button");
341 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
342 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
344 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
346 /* handle dialog requests */
348 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
350 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
352 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
354 /* handle Audio/MIDI setup when session requires it */
356 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
358 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
360 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
362 /* handle requests to quit (coming from JACK session) */
364 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
366 /* tell the user about feedback */
368 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
369 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
371 /* handle requests to deal with missing files */
373 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
375 /* and ambiguous files */
377 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
379 /* also plugin scan messages */
380 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
381 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
383 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
385 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
388 /* lets get this party started */
390 setup_gtk_ardour_enums ();
393 SessionEvent::create_per_thread_pool ("GUI", 4096);
395 /* we like keyboards */
397 keyboard = new ArdourKeyboard(*this);
399 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
401 keyboard->set_state (*node, Stateful::loading_state_version);
404 UIConfiguration::instance().reset_dpi ();
406 TimeAxisViewItem::set_constant_heights ();
408 /* Set this up so that our window proxies can register actions */
410 ActionManager::init ();
412 /* The following must happen after ARDOUR::init() so that Config is set up */
414 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
417 key_editor.set_state (*ui_xml, 0);
418 session_option_editor.set_state (*ui_xml, 0);
419 speaker_config_window.set_state (*ui_xml, 0);
420 about.set_state (*ui_xml, 0);
421 add_route_dialog.set_state (*ui_xml, 0);
422 add_video_dialog.set_state (*ui_xml, 0);
423 route_params.set_state (*ui_xml, 0);
424 bundle_manager.set_state (*ui_xml, 0);
425 location_ui.set_state (*ui_xml, 0);
426 big_clock_window.set_state (*ui_xml, 0);
427 audio_port_matrix.set_state (*ui_xml, 0);
428 midi_port_matrix.set_state (*ui_xml, 0);
429 export_video_dialog.set_state (*ui_xml, 0);
432 /* Separate windows */
434 WM::Manager::instance().register_window (&key_editor);
435 WM::Manager::instance().register_window (&session_option_editor);
436 WM::Manager::instance().register_window (&speaker_config_window);
437 WM::Manager::instance().register_window (&about);
438 WM::Manager::instance().register_window (&add_route_dialog);
439 WM::Manager::instance().register_window (&add_video_dialog);
440 WM::Manager::instance().register_window (&route_params);
441 WM::Manager::instance().register_window (&audio_midi_setup);
442 WM::Manager::instance().register_window (&export_video_dialog);
443 WM::Manager::instance().register_window (&bundle_manager);
444 WM::Manager::instance().register_window (&location_ui);
445 WM::Manager::instance().register_window (&big_clock_window);
446 WM::Manager::instance().register_window (&audio_port_matrix);
447 WM::Manager::instance().register_window (&midi_port_matrix);
449 /* Trigger setting up the color scheme and loading the GTK RC file */
451 UIConfiguration::instance().load_rc_file (false);
453 _process_thread = new ProcessThread ();
454 _process_thread->init ();
456 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
461 GlobalPortMatrixWindow*
462 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
467 return new GlobalPortMatrixWindow (_session, type);
471 ARDOUR_UI::attach_to_engine ()
473 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
474 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
478 ARDOUR_UI::engine_stopped ()
480 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
481 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
482 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
483 update_sample_rate (0);
488 ARDOUR_UI::engine_running ()
490 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
491 if (first_time_engine_run) {
493 first_time_engine_run = false;
497 _session->reset_xrun_count ();
499 update_disk_space ();
501 update_xrun_count ();
502 update_sample_rate (AudioEngine::instance()->sample_rate());
503 update_timecode_format ();
504 update_peak_thread_work ();
505 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
506 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
510 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
512 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
513 /* we can't rely on the original string continuing to exist when we are called
514 again in the GUI thread, so make a copy and note that we need to
517 char *copy = strdup (reason);
518 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
522 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
523 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
525 update_sample_rate (0);
529 /* if the reason is a non-empty string, it means that the backend was shutdown
530 rather than just Ardour.
533 if (strlen (reason)) {
534 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
536 msgstr = string_compose (_("\
537 The audio backend has either been shutdown or it\n\
538 disconnected %1 because %1\n\
539 was not fast enough. Try to restart\n\
540 the audio backend and save the session."), PROGRAM_NAME);
543 MessageDialog msg (_main_window, msgstr);
544 pop_back_splash (msg);
548 free (const_cast<char*> (reason));
553 ARDOUR_UI::post_engine ()
555 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
557 #ifdef AUDIOUNIT_SUPPORT
559 if (AUPluginInfo::au_get_crashlog(au_msg)) {
560 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
561 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
562 info << au_msg << endmsg;
566 ARDOUR::init_post_engine ();
568 /* connect to important signals */
570 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
571 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
572 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
573 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
574 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
576 if (setup_windows ()) {
577 throw failed_constructor ();
580 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
581 XMLNode* n = Config->extra_xml (X_("UI"));
583 _status_bar_visibility.set_state (*n);
586 check_memory_locking();
588 /* this is the first point at which all the possible actions are
589 * available, because some of the available actions are dependent on
590 * aspects of the engine/backend.
593 if (ARDOUR_COMMAND_LINE::show_key_actions) {
596 vector<string> paths;
597 vector<string> labels;
598 vector<string> tooltips;
600 vector<Glib::RefPtr<Gtk::Action> > actions;
602 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
604 vector<string>::iterator k;
605 vector<string>::iterator p;
607 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
612 cout << *p << " => " << *k << endl;
616 halt_connection.disconnect ();
617 AudioEngine::instance()->stop ();
621 /* this being a GUI and all, we want peakfiles */
623 AudioFileSource::set_build_peakfiles (true);
624 AudioFileSource::set_build_missing_peakfiles (true);
626 /* set default clock modes */
628 primary_clock->set_mode (AudioClock::Timecode);
629 secondary_clock->set_mode (AudioClock::BBT);
631 /* start the time-of-day-clock */
634 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
635 update_wall_clock ();
636 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
641 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
642 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
643 Config->map_parameters (pc);
645 UIConfiguration::instance().map_parameters (pc);
649 ARDOUR_UI::~ARDOUR_UI ()
651 UIConfiguration::instance().save_state();
655 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
656 // don't bother at 'real' exit. the OS cleans up for us.
658 delete primary_clock;
659 delete secondary_clock;
660 delete _process_thread;
666 delete gui_object_state;
667 FastMeter::flush_pattern_cache ();
668 PixFader::flush_pattern_cache ();
672 /* Small trick to flush main-thread event pool.
673 * Other thread-pools are destroyed at pthread_exit(),
674 * but tmain thread termination is too late to trigger Pool::~Pool()
676 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.
677 delete ev->event_pool();
682 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
684 if (Splash::instance()) {
685 Splash::instance()->pop_back_for (win);
690 ARDOUR_UI::configure_timeout ()
692 if (last_configure_time == 0) {
693 /* no configure events yet */
697 /* force a gap of 0.5 seconds since the last configure event
700 if (get_microseconds() - last_configure_time < 500000) {
703 have_configure_timeout = false;
704 save_ardour_state ();
710 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
712 if (have_configure_timeout) {
713 last_configure_time = get_microseconds();
715 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
716 have_configure_timeout = true;
723 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
725 const XMLProperty* prop;
727 if ((prop = node.property ("roll")) != 0) {
728 roll_controllable->set_id (prop->value());
730 if ((prop = node.property ("stop")) != 0) {
731 stop_controllable->set_id (prop->value());
733 if ((prop = node.property ("goto-start")) != 0) {
734 goto_start_controllable->set_id (prop->value());
736 if ((prop = node.property ("goto-end")) != 0) {
737 goto_end_controllable->set_id (prop->value());
739 if ((prop = node.property ("auto-loop")) != 0) {
740 auto_loop_controllable->set_id (prop->value());
742 if ((prop = node.property ("play-selection")) != 0) {
743 play_selection_controllable->set_id (prop->value());
745 if ((prop = node.property ("rec")) != 0) {
746 rec_controllable->set_id (prop->value());
748 if ((prop = node.property ("shuttle")) != 0) {
749 shuttle_box->controllable()->set_id (prop->value());
754 ARDOUR_UI::get_transport_controllable_state ()
756 XMLNode* node = new XMLNode(X_("TransportControllables"));
759 roll_controllable->id().print (buf, sizeof (buf));
760 node->add_property (X_("roll"), buf);
761 stop_controllable->id().print (buf, sizeof (buf));
762 node->add_property (X_("stop"), buf);
763 goto_start_controllable->id().print (buf, sizeof (buf));
764 node->add_property (X_("goto_start"), buf);
765 goto_end_controllable->id().print (buf, sizeof (buf));
766 node->add_property (X_("goto_end"), buf);
767 auto_loop_controllable->id().print (buf, sizeof (buf));
768 node->add_property (X_("auto_loop"), buf);
769 play_selection_controllable->id().print (buf, sizeof (buf));
770 node->add_property (X_("play_selection"), buf);
771 rec_controllable->id().print (buf, sizeof (buf));
772 node->add_property (X_("rec"), buf);
773 shuttle_box->controllable()->id().print (buf, sizeof (buf));
774 node->add_property (X_("shuttle"), buf);
780 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
783 _session->save_state (snapshot_name);
788 ARDOUR_UI::autosave_session ()
790 if (g_main_depth() > 1) {
791 /* inside a recursive main loop,
792 give up because we may not be able to
798 if (!Config->get_periodic_safety_backups()) {
803 _session->maybe_write_autosave();
810 ARDOUR_UI::session_dirty_changed ()
817 ARDOUR_UI::update_autosave ()
819 if (_session && _session->dirty()) {
820 if (_autosave_connection.connected()) {
821 _autosave_connection.disconnect();
824 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
825 Config->get_periodic_safety_backup_interval() * 1000);
828 if (_autosave_connection.connected()) {
829 _autosave_connection.disconnect();
835 ARDOUR_UI::check_announcements ()
838 string _annc_filename;
841 _annc_filename = PROGRAM_NAME "_announcements_osx_";
842 #elif defined PLATFORM_WINDOWS
843 _annc_filename = PROGRAM_NAME "_announcements_windows_";
845 _annc_filename = PROGRAM_NAME "_announcements_linux_";
847 _annc_filename.append (VERSIONSTRING);
849 _announce_string = "";
851 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
852 FILE* fin = g_fopen (path.c_str(), "rb");
854 while (!feof (fin)) {
857 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
860 _announce_string.append (tmp, len);
865 pingback (VERSIONSTRING, path);
870 _hide_splash (gpointer arg)
872 ((ARDOUR_UI*)arg)->hide_splash();
877 ARDOUR_UI::starting ()
879 Application* app = Application::instance ();
881 bool brand_new_user = ArdourStartup::required ();
883 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
884 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
886 if (ARDOUR_COMMAND_LINE::check_announcements) {
887 check_announcements ();
892 /* we need to create this early because it may need to set the
893 * audio backend end up.
897 audio_midi_setup.get (true);
899 std::cerr << "audio-midi engine setup failed."<< std::endl;
903 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
904 nsm = new NSM_Client;
905 if (!nsm->init (nsm_url)) {
906 /* the ardour executable may have different names:
908 * waf's obj.target for distro versions: eg ardour4, ardourvst4
909 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
910 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
912 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
914 const char *process_name = g_getenv ("ARDOUR_SELF");
915 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
918 // wait for announce reply from nsm server
919 for ( i = 0; i < 5000; ++i) {
923 if (nsm->is_active()) {
928 error << _("NSM server did not announce itself") << endmsg;
931 // wait for open command from nsm server
932 for ( i = 0; i < 5000; ++i) {
935 if (nsm->client_id ()) {
941 error << _("NSM: no client ID provided") << endmsg;
945 if (_session && nsm) {
946 _session->set_nsm_state( nsm->is_active() );
948 error << _("NSM: no session created") << endmsg;
952 // nsm requires these actions disabled
953 vector<string> action_names;
954 action_names.push_back("SaveAs");
955 action_names.push_back("Rename");
956 action_names.push_back("New");
957 action_names.push_back("Open");
958 action_names.push_back("Recent");
959 action_names.push_back("Close");
961 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
962 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
964 act->set_sensitive (false);
971 error << _("NSM: initialization failed") << endmsg;
977 if (brand_new_user) {
978 _initial_verbose_plugin_scan = true;
983 _initial_verbose_plugin_scan = false;
984 switch (s.response ()) {
985 case Gtk::RESPONSE_OK:
992 #ifdef NO_PLUGIN_STATE
994 ARDOUR::RecentSessions rs;
995 ARDOUR::read_recent_sessions (rs);
997 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
999 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1001 /* already used Ardour, have sessions ... warn about plugin state */
1003 ArdourDialog d (_("Free/Demo Version Warning"), true);
1005 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1006 CheckButton c (_("Don't warn me about this again"));
1008 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"),
1009 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1010 _("It will not restore OR save any plugin settings"),
1011 _("If you load an existing session with plugin settings\n"
1012 "they will not be used and will be lost."),
1013 _("To get full access to updates without this limitation\n"
1014 "consider becoming a subscriber for a low cost every month.")));
1015 l.set_justify (JUSTIFY_CENTER);
1017 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1019 d.get_vbox()->pack_start (l, true, true);
1020 d.get_vbox()->pack_start (b, false, false, 12);
1021 d.get_vbox()->pack_start (c, false, false, 12);
1023 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1024 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1028 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1030 if (d.run () != RESPONSE_OK) {
1036 /* go get a session */
1038 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1040 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1041 std::cerr << "Cannot get session parameters."<< std::endl;
1048 WM::Manager::instance().show_visible ();
1050 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1051 * editor window, and we may want stuff to be hidden.
1053 _status_bar_visibility.update ();
1055 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1057 if (splash && splash->is_visible()) {
1058 // in 1 second, hide the splash screen
1059 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1062 /* all other dialogs are created conditionally */
1068 ARDOUR_UI::check_memory_locking ()
1070 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1071 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1075 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1077 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1079 struct rlimit limits;
1081 long pages, page_size;
1083 size_t pages_len=sizeof(pages);
1084 if ((page_size = getpagesize()) < 0 ||
1085 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1087 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1092 ram = (int64_t) pages * (int64_t) page_size;
1095 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1099 if (limits.rlim_cur != RLIM_INFINITY) {
1101 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1105 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1106 "This might cause %1 to run out of memory before your system "
1107 "runs out of memory. \n\n"
1108 "You can view the memory limit with 'ulimit -l', "
1109 "and it is normally controlled by %2"),
1112 X_("/etc/login.conf")
1114 X_(" /etc/security/limits.conf")
1118 msg.set_default_response (RESPONSE_OK);
1120 VBox* vbox = msg.get_vbox();
1122 CheckButton cb (_("Do not show this window again"));
1123 hbox.pack_start (cb, true, false);
1124 vbox->pack_start (hbox);
1129 pop_back_splash (msg);
1133 if (cb.get_active()) {
1134 XMLNode node (X_("no-memory-warning"));
1135 Config->add_instant_xml (node);
1140 #endif // !__APPLE__
1145 ARDOUR_UI::queue_finish ()
1147 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1151 ARDOUR_UI::idle_finish ()
1154 return false; /* do not call again */
1161 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1163 if (_session->dirty()) {
1164 vector<string> actions;
1165 actions.push_back (_("Don't quit"));
1166 actions.push_back (_("Just quit"));
1167 actions.push_back (_("Save and quit"));
1168 switch (ask_about_saving_session(actions)) {
1173 /* use the default name */
1174 if (save_state_canfail ("")) {
1175 /* failed - don't quit */
1176 MessageDialog msg (_main_window,
1177 string_compose (_("\
1178 %1 was unable to save your session.\n\n\
1179 If you still wish to quit, please use the\n\n\
1180 \"Just quit\" option."), PROGRAM_NAME));
1181 pop_back_splash(msg);
1191 second_connection.disconnect ();
1192 point_one_second_connection.disconnect ();
1193 point_zero_something_second_connection.disconnect();
1194 fps_connection.disconnect();
1197 delete ARDOUR_UI::instance()->video_timeline;
1198 ARDOUR_UI::instance()->video_timeline = NULL;
1199 stop_video_server();
1201 /* Save state before deleting the session, as that causes some
1202 windows to be destroyed before their visible state can be
1205 save_ardour_state ();
1207 close_all_dialogs ();
1210 _session->set_clean ();
1211 _session->remove_pending_capture_state ();
1216 halt_connection.disconnect ();
1217 AudioEngine::instance()->stop ();
1218 #ifdef WINDOWS_VST_SUPPORT
1219 fst_stop_threading();
1225 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1227 ArdourDialog window (_("Unsaved Session"));
1228 Gtk::HBox dhbox; // the hbox for the image and text
1229 Gtk::Label prompt_label;
1230 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1234 assert (actions.size() >= 3);
1236 window.add_button (actions[0], RESPONSE_REJECT);
1237 window.add_button (actions[1], RESPONSE_APPLY);
1238 window.add_button (actions[2], RESPONSE_ACCEPT);
1240 window.set_default_response (RESPONSE_ACCEPT);
1242 Gtk::Button noquit_button (msg);
1243 noquit_button.set_name ("EditorGTKButton");
1247 if (_session->snap_name() == _session->name()) {
1248 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?"),
1249 _session->snap_name());
1251 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?"),
1252 _session->snap_name());
1255 prompt_label.set_text (prompt);
1256 prompt_label.set_name (X_("PrompterLabel"));
1257 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1259 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1260 dhbox.set_homogeneous (false);
1261 dhbox.pack_start (*dimage, false, false, 5);
1262 dhbox.pack_start (prompt_label, true, false, 5);
1263 window.get_vbox()->pack_start (dhbox);
1265 window.set_name (_("Prompter"));
1266 window.set_modal (true);
1267 window.set_resizable (false);
1270 prompt_label.show();
1275 ResponseType r = (ResponseType) window.run();
1280 case RESPONSE_ACCEPT: // save and get out of here
1282 case RESPONSE_APPLY: // get out of here
1293 ARDOUR_UI::every_second ()
1296 update_xrun_count ();
1297 update_buffer_load ();
1298 update_disk_space ();
1299 update_timecode_format ();
1300 update_peak_thread_work ();
1302 if (nsm && nsm->is_active ()) {
1305 if (!_was_dirty && _session->dirty ()) {
1309 else if (_was_dirty && !_session->dirty ()){
1317 ARDOUR_UI::every_point_one_seconds ()
1319 // TODO get rid of this..
1320 // ShuttleControl is updated directly via TransportStateChange signal
1324 ARDOUR_UI::every_point_zero_something_seconds ()
1326 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1328 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1329 float mpeak = editor_meter->update_meters();
1330 if (mpeak > editor_meter_max_peak) {
1331 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1332 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1339 ARDOUR_UI::set_fps_timeout_connection ()
1341 unsigned int interval = 40;
1342 if (!_session) return;
1343 if (_session->timecode_frames_per_second() != 0) {
1344 /* ideally we'll use a select() to sleep and not accumulate
1345 * idle time to provide a regular periodic signal.
1346 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1347 * However, that'll require a dedicated thread and cross-thread
1348 * signals to the GUI Thread..
1350 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1351 * _session->frame_rate() / _session->nominal_frame_rate()
1352 / _session->timecode_frames_per_second()
1354 #ifdef PLATFORM_WINDOWS
1355 // the smallest windows scheduler time-slice is ~15ms.
1356 // periodic GUI timeouts shorter than that will cause
1357 // WaitForSingleObject to spinlock (100% of one CPU Core)
1358 // and gtk never enters idle mode.
1359 // also changing timeBeginPeriod(1) does not affect that in
1360 // any beneficial way, so we just limit the max rate for now.
1361 interval = std::max(30u, interval); // at most ~33Hz.
1363 interval = std::max(8u, interval); // at most 120Hz.
1366 fps_connection.disconnect();
1367 Timers::set_fps_interval (interval);
1371 ARDOUR_UI::update_sample_rate (framecnt_t)
1375 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1377 if (!AudioEngine::instance()->connected()) {
1379 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1383 framecnt_t rate = AudioEngine::instance()->sample_rate();
1386 /* no sample rate available */
1387 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1390 if (fmod (rate, 1000.0) != 0.0) {
1391 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1392 (float) rate / 1000.0f,
1393 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1395 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1397 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1401 sample_rate_label.set_markup (buf);
1405 ARDOUR_UI::update_format ()
1408 format_label.set_text ("");
1413 s << _("File:") << X_(" <span foreground=\"green\">");
1415 switch (_session->config.get_native_file_header_format ()) {
1447 switch (_session->config.get_native_file_data_format ()) {
1461 format_label.set_markup (s.str ());
1465 ARDOUR_UI::update_xrun_count ()
1469 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1470 should also be changed.
1474 const unsigned int x = _session->get_xrun_count ();
1476 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1478 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1481 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1483 xrun_label.set_markup (buf);
1484 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1488 ARDOUR_UI::update_cpu_load ()
1492 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1493 should also be changed.
1496 double const c = AudioEngine::instance()->get_dsp_load ();
1497 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1498 cpu_load_label.set_markup (buf);
1502 ARDOUR_UI::update_peak_thread_work ()
1505 const int c = SourceFactory::peak_work_queue_length ();
1507 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1508 peak_thread_work_label.set_markup (buf);
1510 peak_thread_work_label.set_markup (X_(""));
1515 ARDOUR_UI::update_buffer_load ()
1519 uint32_t const playback = _session ? _session->playback_load () : 100;
1520 uint32_t const capture = _session ? _session->capture_load () : 100;
1522 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1523 should also be changed.
1529 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1530 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1531 playback <= 5 ? X_("red") : X_("green"),
1533 capture <= 5 ? X_("red") : X_("green"),
1537 buffer_load_label.set_markup (buf);
1539 buffer_load_label.set_text ("");
1544 ARDOUR_UI::count_recenabled_streams (Route& route)
1546 Track* track = dynamic_cast<Track*>(&route);
1547 if (track && track->record_enabled()) {
1548 rec_enabled_streams += track->n_inputs().n_total();
1553 ARDOUR_UI::update_disk_space()
1555 if (_session == 0) {
1559 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1561 framecnt_t fr = _session->frame_rate();
1564 /* skip update - no SR available */
1569 /* Available space is unknown */
1570 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1571 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1572 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1574 rec_enabled_streams = 0;
1575 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1577 framecnt_t frames = opt_frames.get_value_or (0);
1579 if (rec_enabled_streams) {
1580 frames /= rec_enabled_streams;
1587 hrs = frames / (fr * 3600);
1590 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1592 frames -= hrs * fr * 3600;
1593 mins = frames / (fr * 60);
1594 frames -= mins * fr * 60;
1597 bool const low = (hrs == 0 && mins <= 30);
1601 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1602 low ? X_("red") : X_("green"),
1608 disk_space_label.set_markup (buf);
1612 ARDOUR_UI::update_timecode_format ()
1618 TimecodeSlave* tcslave;
1619 SyncSource sync_src = Config->get_sync_source();
1621 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1622 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1627 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1628 matching ? X_("green") : X_("red"),
1629 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1631 snprintf (buf, sizeof (buf), "TC: n/a");
1634 timecode_format_label.set_markup (buf);
1638 ARDOUR_UI::update_wall_clock ()
1642 static int last_min = -1;
1645 tm_now = localtime (&now);
1646 if (last_min != tm_now->tm_min) {
1648 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1649 wall_clock_label.set_text (buf);
1650 last_min = tm_now->tm_min;
1657 ARDOUR_UI::open_recent_session ()
1659 bool can_return = (_session != 0);
1661 SessionDialog recent_session_dialog;
1665 ResponseType r = (ResponseType) recent_session_dialog.run ();
1668 case RESPONSE_ACCEPT:
1672 recent_session_dialog.hide();
1679 recent_session_dialog.hide();
1683 std::string path = recent_session_dialog.session_folder();
1684 std::string state = recent_session_dialog.session_name (should_be_new);
1686 if (should_be_new == true) {
1690 _session_is_new = false;
1692 if (load_session (path, state) == 0) {
1701 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1703 if (!AudioEngine::instance()->connected()) {
1704 MessageDialog msg (parent, string_compose (
1705 _("%1 is not connected to any audio backend.\n"
1706 "You cannot open or close sessions in this condition"),
1708 pop_back_splash (msg);
1716 ARDOUR_UI::open_session ()
1718 if (!check_audioengine (_main_window)) {
1722 /* ardour sessions are folders */
1723 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1724 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1725 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1726 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1729 string session_parent_dir = Glib::path_get_dirname(_session->path());
1730 open_session_selector.set_current_folder(session_parent_dir);
1732 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1735 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1737 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1738 string default_session_folder = Config->get_default_session_parent_dir();
1739 open_session_selector.add_shortcut_folder (default_session_folder);
1741 catch (Glib::Error & e) {
1742 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1745 FileFilter session_filter;
1746 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1747 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1748 open_session_selector.add_filter (session_filter);
1749 open_session_selector.set_filter (session_filter);
1751 int response = open_session_selector.run();
1752 open_session_selector.hide ();
1754 if (response == Gtk::RESPONSE_CANCEL) {
1758 string session_path = open_session_selector.get_filename();
1762 if (session_path.length() > 0) {
1763 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1764 _session_is_new = isnew;
1765 load_session (path, name);
1772 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1773 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1775 list<boost::shared_ptr<MidiTrack> > tracks;
1777 if (_session == 0) {
1778 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1783 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1785 if (tracks.size() != how_many) {
1786 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1791 MessageDialog msg (_main_window,
1792 string_compose (_("There are insufficient ports available\n\
1793 to create a new track or bus.\n\
1794 You should save %1, exit and\n\
1795 restart with more ports."), PROGRAM_NAME));
1802 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1804 ChanCount one_midi_channel;
1805 one_midi_channel.set (DataType::MIDI, 1);
1808 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1813 ARDOUR_UI::session_add_audio_route (
1815 int32_t input_channels,
1816 int32_t output_channels,
1817 ARDOUR::TrackMode mode,
1818 RouteGroup* route_group,
1820 string const & name_template
1823 list<boost::shared_ptr<AudioTrack> > tracks;
1826 if (_session == 0) {
1827 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1833 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1835 if (tracks.size() != how_many) {
1836 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1842 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1844 if (routes.size() != how_many) {
1845 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1852 MessageDialog msg (_main_window,
1853 string_compose (_("There are insufficient ports available\n\
1854 to create a new track or bus.\n\
1855 You should save %1, exit and\n\
1856 restart with more ports."), PROGRAM_NAME));
1857 pop_back_splash (msg);
1863 ARDOUR_UI::transport_goto_start ()
1866 _session->goto_start();
1868 /* force displayed area in editor to start no matter
1869 what "follow playhead" setting is.
1873 editor->center_screen (_session->current_start_frame ());
1879 ARDOUR_UI::transport_goto_zero ()
1882 _session->request_locate (0);
1884 /* force displayed area in editor to start no matter
1885 what "follow playhead" setting is.
1889 editor->reset_x_origin (0);
1895 ARDOUR_UI::transport_goto_wallclock ()
1897 if (_session && editor) {
1904 localtime_r (&now, &tmnow);
1906 framecnt_t frame_rate = _session->frame_rate();
1908 if (frame_rate == 0) {
1909 /* no frame rate available */
1913 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1914 frames += tmnow.tm_min * (60 * frame_rate);
1915 frames += tmnow.tm_sec * frame_rate;
1917 _session->request_locate (frames, _session->transport_rolling ());
1919 /* force displayed area in editor to start no matter
1920 what "follow playhead" setting is.
1924 editor->center_screen (frames);
1930 ARDOUR_UI::transport_goto_end ()
1933 framepos_t const frame = _session->current_end_frame();
1934 _session->request_locate (frame);
1936 /* force displayed area in editor to start no matter
1937 what "follow playhead" setting is.
1941 editor->center_screen (frame);
1947 ARDOUR_UI::transport_stop ()
1953 if (_session->is_auditioning()) {
1954 _session->cancel_audition ();
1958 _session->request_stop (false, true);
1961 /** Check if any tracks are record enabled. If none are, record enable all of them.
1962 * @return true if track record-enabled status was changed, false otherwise.
1965 ARDOUR_UI::trx_record_enable_all_tracks ()
1971 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1972 bool none_record_enabled = true;
1974 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1975 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1978 if (t->record_enabled()) {
1979 none_record_enabled = false;
1984 if (none_record_enabled) {
1985 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1988 return none_record_enabled;
1992 ARDOUR_UI::transport_record (bool roll)
1995 switch (_session->record_status()) {
1996 case Session::Disabled:
1997 if (_session->ntracks() == 0) {
1998 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."));
2002 if (Profile->get_trx()) {
2003 roll = trx_record_enable_all_tracks ();
2005 _session->maybe_enable_record ();
2010 case Session::Recording:
2012 _session->request_stop();
2014 _session->disable_record (false, true);
2018 case Session::Enabled:
2019 _session->disable_record (false, true);
2025 ARDOUR_UI::transport_roll ()
2031 if (_session->is_auditioning()) {
2036 if (_session->config.get_external_sync()) {
2037 switch (Config->get_sync_source()) {
2041 /* transport controlled by the master */
2047 bool rolling = _session->transport_rolling();
2049 if (_session->get_play_loop()) {
2051 /* If loop playback is not a mode, then we should cancel
2052 it when this action is requested. If it is a mode
2053 we just leave it in place.
2056 if (!Config->get_loop_is_mode()) {
2057 /* XXX it is not possible to just leave seamless loop and keep
2058 playing at present (nov 4th 2009)
2060 if (!Config->get_seamless_loop()) {
2061 /* stop loop playback and stop rolling */
2062 _session->request_play_loop (false, true);
2063 } else if (rolling) {
2064 /* stop loop playback but keep rolling */
2065 _session->request_play_loop (false, false);
2069 } else if (_session->get_play_range () ) {
2070 /* stop playing a range if we currently are */
2071 _session->request_play_range (0, true);
2075 _session->request_transport_speed (1.0f);
2080 ARDOUR_UI::get_smart_mode() const
2082 return ( editor->get_smart_mode() );
2087 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2093 if (_session->is_auditioning()) {
2094 _session->cancel_audition ();
2098 if (_session->config.get_external_sync()) {
2099 switch (Config->get_sync_source()) {
2103 /* transport controlled by the master */
2108 bool rolling = _session->transport_rolling();
2109 bool affect_transport = true;
2111 if (rolling && roll_out_of_bounded_mode) {
2112 /* drop out of loop/range playback but leave transport rolling */
2113 if (_session->get_play_loop()) {
2114 if (_session->actively_recording()) {
2116 /* just stop using the loop, then actually stop
2119 _session->request_play_loop (false, affect_transport);
2122 if (Config->get_seamless_loop()) {
2123 /* the disk buffers contain copies of the loop - we can't
2124 just keep playing, so stop the transport. the user
2125 can restart as they wish.
2127 affect_transport = true;
2129 /* disk buffers are normal, so we can keep playing */
2130 affect_transport = false;
2132 _session->request_play_loop (false, affect_transport);
2134 } else if (_session->get_play_range ()) {
2135 affect_transport = false;
2136 _session->request_play_range (0, true);
2140 if (affect_transport) {
2142 _session->request_stop (with_abort, true);
2144 /* the only external sync condition we can be in here
2145 * would be Engine (JACK) sync, in which case we still
2149 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
2150 _session->request_play_range (&editor->get_selection().time, true);
2151 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2153 _session->request_transport_speed (1.0f);
2159 ARDOUR_UI::toggle_session_auto_loop ()
2165 Location * looploc = _session->locations()->auto_loop_location();
2171 if (_session->get_play_loop()) {
2173 /* looping enabled, our job is to disable it */
2175 _session->request_play_loop (false);
2179 /* looping not enabled, our job is to enable it.
2181 loop-is-NOT-mode: this action always starts the transport rolling.
2182 loop-IS-mode: this action simply sets the loop play mechanism, but
2183 does not start transport.
2185 if (Config->get_loop_is_mode()) {
2186 _session->request_play_loop (true, false);
2188 _session->request_play_loop (true, true);
2192 //show the loop markers
2193 looploc->set_hidden (false, this);
2197 ARDOUR_UI::transport_play_selection ()
2203 editor->play_selection ();
2207 ARDOUR_UI::transport_play_preroll ()
2212 editor->play_with_preroll ();
2216 ARDOUR_UI::transport_rewind (int option)
2218 float current_transport_speed;
2221 current_transport_speed = _session->transport_speed();
2223 if (current_transport_speed >= 0.0f) {
2226 _session->request_transport_speed (-1.0f);
2229 _session->request_transport_speed (-4.0f);
2232 _session->request_transport_speed (-0.5f);
2237 _session->request_transport_speed (current_transport_speed * 1.5f);
2243 ARDOUR_UI::transport_forward (int option)
2249 float current_transport_speed = _session->transport_speed();
2251 if (current_transport_speed <= 0.0f) {
2254 _session->request_transport_speed (1.0f);
2257 _session->request_transport_speed (4.0f);
2260 _session->request_transport_speed (0.5f);
2265 _session->request_transport_speed (current_transport_speed * 1.5f);
2270 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2276 boost::shared_ptr<Route> r;
2278 if ((r = _session->route_by_remote_id (rid)) != 0) {
2280 boost::shared_ptr<Track> t;
2282 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2283 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2289 ARDOUR_UI::map_transport_state ()
2292 auto_loop_button.unset_active_state ();
2293 play_selection_button.unset_active_state ();
2294 roll_button.unset_active_state ();
2295 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2299 shuttle_box->map_transport_state ();
2301 float sp = _session->transport_speed();
2307 if (_session->get_play_range()) {
2309 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2310 roll_button.unset_active_state ();
2311 auto_loop_button.unset_active_state ();
2313 } else if (_session->get_play_loop ()) {
2315 auto_loop_button.set_active (true);
2316 play_selection_button.set_active (false);
2317 if (Config->get_loop_is_mode()) {
2318 roll_button.set_active (true);
2320 roll_button.set_active (false);
2325 roll_button.set_active (true);
2326 play_selection_button.set_active (false);
2327 auto_loop_button.set_active (false);
2330 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2331 /* light up both roll and play-selection if they are joined */
2332 roll_button.set_active (true);
2333 play_selection_button.set_active (true);
2336 stop_button.set_active (false);
2340 stop_button.set_active (true);
2341 roll_button.set_active (false);
2342 play_selection_button.set_active (false);
2343 if (Config->get_loop_is_mode ()) {
2344 auto_loop_button.set_active (_session->get_play_loop());
2346 auto_loop_button.set_active (false);
2348 update_disk_space ();
2353 ARDOUR_UI::blink_handler (bool blink_on)
2355 transport_rec_enable_blink (blink_on);
2356 solo_blink (blink_on);
2357 sync_blink (blink_on);
2358 audition_blink (blink_on);
2359 feedback_blink (blink_on);
2360 error_blink (blink_on);
2364 ARDOUR_UI::update_clocks ()
2366 if (!_session) return;
2368 if (editor && !editor->dragging_playhead()) {
2369 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2374 ARDOUR_UI::start_clocking ()
2376 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2377 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2379 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2384 ARDOUR_UI::stop_clocking ()
2386 clock_signal_connection.disconnect ();
2390 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2394 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2396 label->set_text (buf);
2397 bar->set_fraction (fraction);
2399 /* process events, redraws, etc. */
2401 while (gtk_events_pending()) {
2402 gtk_main_iteration ();
2405 return true; /* continue with save-as */
2409 ARDOUR_UI::save_session_as ()
2415 if (!save_as_dialog) {
2416 save_as_dialog = new SaveAsDialog;
2419 save_as_dialog->set_name (_session->name());
2421 int response = save_as_dialog->run ();
2423 save_as_dialog->hide ();
2426 case Gtk::RESPONSE_OK:
2435 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2436 sa.new_name = save_as_dialog->new_name ();
2437 sa.switch_to = save_as_dialog->switch_to();
2438 sa.copy_media = save_as_dialog->copy_media();
2439 sa.copy_external = save_as_dialog->copy_external();
2440 sa.include_media = save_as_dialog->include_media ();
2442 /* Only bother with a progress dialog if we're going to copy
2443 media into the save-as target. Without that choice, this
2444 will be very fast because we're only talking about a few kB's to
2445 perhaps a couple of MB's of data.
2448 ArdourDialog progress_dialog (_("Save As"), true);
2450 if (sa.include_media && sa.copy_media) {
2453 Gtk::ProgressBar progress_bar;
2455 progress_dialog.get_vbox()->pack_start (label);
2456 progress_dialog.get_vbox()->pack_start (progress_bar);
2458 progress_bar.show ();
2460 /* this signal will be emitted from within this, the calling thread,
2461 * after every file is copied. It provides information on percentage
2462 * complete (in terms of total data to copy), the number of files
2463 * copied so far, and the total number to copy.
2468 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2470 progress_dialog.show_all ();
2471 progress_dialog.present ();
2474 if (_session->save_as (sa)) {
2476 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2480 if (!sa.include_media) {
2481 unload_session (false);
2482 load_session (sa.final_session_folder_name, sa.new_name);
2487 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2491 struct tm local_time;
2494 localtime_r (&n, &local_time);
2495 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2497 save_state (timebuf, switch_to_it);
2502 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2506 prompter.get_result (snapname);
2508 bool do_save = (snapname.length() != 0);
2511 char illegal = Session::session_name_is_legal(snapname);
2513 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2514 "snapshot names may not contain a '%1' character"), illegal));
2520 vector<std::string> p;
2521 get_state_files_in_directory (_session->session_directory().root_path(), p);
2522 vector<string> n = get_file_names_no_extension (p);
2524 if (find (n.begin(), n.end(), snapname) != n.end()) {
2526 do_save = overwrite_file_dialog (prompter,
2527 _("Confirm Snapshot Overwrite"),
2528 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2532 save_state (snapname, switch_to_it);
2542 /** Ask the user for the name of a new snapshot and then take it.
2546 ARDOUR_UI::snapshot_session (bool switch_to_it)
2548 ArdourPrompter prompter (true);
2550 prompter.set_name ("Prompter");
2551 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2553 prompter.set_title (_("Save as..."));
2554 prompter.set_prompt (_("New session name"));
2556 prompter.set_title (_("Take Snapshot"));
2557 prompter.set_prompt (_("Name of new snapshot"));
2561 prompter.set_initial_text (_session->snap_name());
2565 struct tm local_time;
2568 localtime_r (&n, &local_time);
2569 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2570 prompter.set_initial_text (timebuf);
2573 bool finished = false;
2575 switch (prompter.run()) {
2576 case RESPONSE_ACCEPT:
2578 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2589 /** Ask the user for a new session name and then rename the session to it.
2593 ARDOUR_UI::rename_session ()
2599 ArdourPrompter prompter (true);
2602 prompter.set_name ("Prompter");
2603 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2604 prompter.set_title (_("Rename Session"));
2605 prompter.set_prompt (_("New session name"));
2608 switch (prompter.run()) {
2609 case RESPONSE_ACCEPT:
2611 prompter.get_result (name);
2613 bool do_rename = (name.length() != 0);
2616 char illegal = Session::session_name_is_legal (name);
2619 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2620 "session names may not contain a '%1' character"), illegal));
2625 switch (_session->rename (name)) {
2627 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2628 msg.set_position (WIN_POS_MOUSE);
2636 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2637 msg.set_position (WIN_POS_MOUSE);
2653 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2655 if (!_session || _session->deletion_in_progress()) {
2659 XMLNode* node = new XMLNode (X_("UI"));
2661 WM::Manager::instance().add_state (*node);
2663 node->add_child_nocopy (gui_object_state->get_state());
2665 _session->add_extra_xml (*node);
2667 if (export_video_dialog) {
2668 _session->add_extra_xml (export_video_dialog->get_state());
2671 save_state_canfail (name, switch_to_it);
2675 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2680 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2685 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2690 ARDOUR_UI::primary_clock_value_changed ()
2693 _session->request_locate (primary_clock->current_time ());
2698 ARDOUR_UI::big_clock_value_changed ()
2701 _session->request_locate (big_clock->current_time ());
2706 ARDOUR_UI::secondary_clock_value_changed ()
2709 _session->request_locate (secondary_clock->current_time ());
2714 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2716 if (_session == 0) {
2720 if (_session->step_editing()) {
2724 Session::RecordState const r = _session->record_status ();
2725 bool const h = _session->have_rec_enabled_track ();
2727 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2729 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2731 rec_button.set_active_state (Gtkmm2ext::Off);
2733 } else if (r == Session::Recording && h) {
2734 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2736 rec_button.unset_active_state ();
2741 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2745 prompter.get_result (name);
2747 if (name.length()) {
2748 int failed = _session->save_template (name);
2750 if (failed == -2) { /* file already exists. */
2751 bool overwrite = overwrite_file_dialog (prompter,
2752 _("Confirm Template Overwrite"),
2753 _("A template already exists with that name. Do you want to overwrite it?"));
2756 _session->save_template (name, true);
2768 ARDOUR_UI::save_template ()
2770 ArdourPrompter prompter (true);
2772 if (!check_audioengine (_main_window)) {
2776 prompter.set_name (X_("Prompter"));
2777 prompter.set_title (_("Save Template"));
2778 prompter.set_prompt (_("Name for template:"));
2779 prompter.set_initial_text(_session->name() + _("-template"));
2780 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2782 bool finished = false;
2784 switch (prompter.run()) {
2785 case RESPONSE_ACCEPT:
2786 finished = process_save_template_prompter (prompter);
2797 ARDOUR_UI::edit_metadata ()
2799 SessionMetadataEditor dialog;
2800 dialog.set_session (_session);
2801 dialog.grab_focus ();
2806 ARDOUR_UI::import_metadata ()
2808 SessionMetadataImporter dialog;
2809 dialog.set_session (_session);
2814 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2816 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2818 MessageDialog msg (str,
2820 Gtk::MESSAGE_WARNING,
2821 Gtk::BUTTONS_YES_NO,
2825 msg.set_name (X_("OpenExistingDialog"));
2826 msg.set_title (_("Open Existing Session"));
2827 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2828 msg.set_position (Gtk::WIN_POS_CENTER);
2829 pop_back_splash (msg);
2831 switch (msg.run()) {
2840 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2842 BusProfile bus_profile;
2846 bus_profile.master_out_channels = 2;
2847 bus_profile.input_ac = AutoConnectPhysical;
2848 bus_profile.output_ac = AutoConnectMaster;
2849 bus_profile.requested_physical_in = 0; // use all available
2850 bus_profile.requested_physical_out = 0; // use all available
2854 /* get settings from advanced section of NSD */
2856 if (sd.create_master_bus()) {
2857 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2859 bus_profile.master_out_channels = 0;
2862 if (sd.connect_inputs()) {
2863 bus_profile.input_ac = AutoConnectPhysical;
2865 bus_profile.input_ac = AutoConnectOption (0);
2868 bus_profile.output_ac = AutoConnectOption (0);
2870 if (sd.connect_outputs ()) {
2871 if (sd.connect_outs_to_master()) {
2872 bus_profile.output_ac = AutoConnectMaster;
2873 } else if (sd.connect_outs_to_physical()) {
2874 bus_profile.output_ac = AutoConnectPhysical;
2878 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2879 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2882 if (build_session (session_path, session_name, bus_profile)) {
2890 ARDOUR_UI::load_from_application_api (const std::string& path)
2892 ARDOUR_COMMAND_LINE::session_name = path;
2893 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2895 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2897 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2898 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2899 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2900 * -> SessionDialog is not displayed
2903 if (_session_dialog) {
2904 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2905 std::string session_path = path;
2906 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2907 session_path = Glib::path_get_dirname (session_path);
2909 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2910 _session_dialog->set_provided_session (session_name, session_path);
2911 _session_dialog->response (RESPONSE_NONE);
2912 _session_dialog->hide();
2917 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2918 /* /path/to/foo => /path/to/foo, foo */
2919 rv = load_session (path, basename_nosuffix (path));
2921 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2922 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2925 // if load_session fails -> pop up SessionDialog.
2927 ARDOUR_COMMAND_LINE::session_name = "";
2929 if (get_session_parameters (true, false)) {
2935 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2937 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2939 string session_name;
2940 string session_path;
2941 string template_name;
2943 bool likely_new = false;
2944 bool cancel_not_quit;
2946 /* deal with any existing DIRTY session now, rather than later. don't
2947 * treat a non-dirty session this way, so that it stays visible
2948 * as we bring up the new session dialog.
2951 if (_session && ARDOUR_UI::instance()->video_timeline) {
2952 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2955 /* if there is already a session, relabel the button
2956 on the SessionDialog so that we don't Quit directly
2958 cancel_not_quit = (_session != 0);
2960 if (_session && _session->dirty()) {
2961 if (unload_session (false)) {
2962 /* unload cancelled by user */
2965 ARDOUR_COMMAND_LINE::session_name = "";
2968 if (!load_template.empty()) {
2969 should_be_new = true;
2970 template_name = load_template;
2973 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2974 session_path = ARDOUR_COMMAND_LINE::session_name;
2976 if (!session_path.empty()) {
2977 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2978 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2979 /* session/snapshot file, change path to be dir */
2980 session_path = Glib::path_get_dirname (session_path);
2985 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2987 _session_dialog = &session_dialog;
2990 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2992 /* if they named a specific statefile, use it, otherwise they are
2993 just giving a session folder, and we want to use it as is
2994 to find the session.
2997 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2999 if (suffix != string::npos) {
3000 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3001 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3002 session_name = Glib::path_get_basename (session_name);
3004 session_path = ARDOUR_COMMAND_LINE::session_name;
3005 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3010 session_dialog.clear_given ();
3013 if (should_be_new || session_name.empty()) {
3014 /* need the dialog to get info from user */
3016 cerr << "run dialog\n";
3018 switch (session_dialog.run()) {
3019 case RESPONSE_ACCEPT:
3022 /* this is used for async * app->ShouldLoad(). */
3023 continue; // while loop
3026 if (quit_on_cancel) {
3027 // JE - Currently (July 2014) this section can only get reached if the
3028 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3029 // point does NOT indicate an abnormal termination). Therefore, let's
3030 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3032 pthread_cancel_all ();
3040 session_dialog.hide ();
3043 /* if we run the startup dialog again, offer more than just "new session" */
3045 should_be_new = false;
3047 session_name = session_dialog.session_name (likely_new);
3048 session_path = session_dialog.session_folder ();
3054 string::size_type suffix = session_name.find (statefile_suffix);
3056 if (suffix != string::npos) {
3057 session_name = session_name.substr (0, suffix);
3060 /* this shouldn't happen, but we catch it just in case it does */
3062 if (session_name.empty()) {
3066 if (session_dialog.use_session_template()) {
3067 template_name = session_dialog.session_template_name();
3068 _session_is_new = true;
3071 if (session_name[0] == G_DIR_SEPARATOR ||
3072 #ifdef PLATFORM_WINDOWS
3073 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3075 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3076 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3081 /* absolute path or cwd-relative path specified for session name: infer session folder
3082 from what was given.
3085 session_path = Glib::path_get_dirname (session_name);
3086 session_name = Glib::path_get_basename (session_name);
3090 session_path = session_dialog.session_folder();
3092 char illegal = Session::session_name_is_legal (session_name);
3095 MessageDialog msg (session_dialog,
3096 string_compose (_("To ensure compatibility with various systems\n"
3097 "session names may not contain a '%1' character"),
3100 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3105 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3108 if (likely_new && !nsm) {
3110 std::string existing = Glib::build_filename (session_path, session_name);
3112 if (!ask_about_loading_existing_session (existing)) {
3113 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3118 _session_is_new = false;
3123 pop_back_splash (session_dialog);
3124 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3126 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3130 char illegal = Session::session_name_is_legal(session_name);
3133 pop_back_splash (session_dialog);
3134 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3135 "session names may not contain a '%1' character"), illegal));
3137 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3141 _session_is_new = true;
3144 if (likely_new && template_name.empty()) {
3146 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3150 ret = load_session (session_path, session_name, template_name);
3153 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3157 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3158 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3162 /* clear this to avoid endless attempts to load the
3166 ARDOUR_COMMAND_LINE::session_name = "";
3170 _session_dialog = NULL;
3176 ARDOUR_UI::close_session()
3178 if (!check_audioengine (_main_window)) {
3182 if (unload_session (true)) {
3186 ARDOUR_COMMAND_LINE::session_name = "";
3188 if (get_session_parameters (true, false)) {
3193 /** @param snap_name Snapshot name (without .ardour suffix).
3194 * @return -2 if the load failed because we are not connected to the AudioEngine.
3197 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3199 Session *new_session;
3204 unload_status = unload_session ();
3206 if (unload_status < 0) {
3208 } else if (unload_status > 0) {
3214 session_loaded = false;
3216 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3219 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3222 /* this one is special */
3224 catch (AudioEngine::PortRegistrationFailure& err) {
3226 MessageDialog msg (err.what(),
3229 Gtk::BUTTONS_CLOSE);
3231 msg.set_title (_("Port Registration Error"));
3232 msg.set_secondary_text (_("Click the Close button to try again."));
3233 msg.set_position (Gtk::WIN_POS_CENTER);
3234 pop_back_splash (msg);
3237 int response = msg.run ();
3242 case RESPONSE_CANCEL:
3249 catch (SessionException e) {
3250 MessageDialog msg (string_compose(
3251 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3252 path, snap_name, e.what()),
3257 msg.set_title (_("Loading Error"));
3258 msg.set_position (Gtk::WIN_POS_CENTER);
3259 pop_back_splash (msg);
3271 MessageDialog msg (string_compose(
3272 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3278 msg.set_title (_("Loading Error"));
3279 msg.set_position (Gtk::WIN_POS_CENTER);
3280 pop_back_splash (msg);
3292 list<string> const u = new_session->unknown_processors ();
3294 MissingPluginDialog d (_session, u);
3299 if (!new_session->writable()) {
3300 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3305 msg.set_title (_("Read-only Session"));
3306 msg.set_position (Gtk::WIN_POS_CENTER);
3307 pop_back_splash (msg);
3314 /* Now the session been created, add the transport controls */
3315 new_session->add_controllable(roll_controllable);
3316 new_session->add_controllable(stop_controllable);
3317 new_session->add_controllable(goto_start_controllable);
3318 new_session->add_controllable(goto_end_controllable);
3319 new_session->add_controllable(auto_loop_controllable);
3320 new_session->add_controllable(play_selection_controllable);
3321 new_session->add_controllable(rec_controllable);
3323 set_session (new_session);
3325 session_loaded = true;
3328 _session->set_clean ();
3331 #ifdef WINDOWS_VST_SUPPORT
3332 fst_stop_threading();
3336 Timers::TimerSuspender t;
3340 #ifdef WINDOWS_VST_SUPPORT
3341 fst_start_threading();
3350 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3352 Session *new_session;
3355 session_loaded = false;
3356 x = unload_session ();
3364 _session_is_new = true;
3367 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3370 catch (SessionException e) {
3372 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3373 msg.set_title (_("Loading Error"));
3374 msg.set_position (Gtk::WIN_POS_CENTER);
3375 pop_back_splash (msg);
3381 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3382 msg.set_title (_("Loading Error"));
3383 msg.set_position (Gtk::WIN_POS_CENTER);
3384 pop_back_splash (msg);
3389 /* Give the new session the default GUI state, if such things exist */
3392 n = Config->instant_xml (X_("Editor"));
3394 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3395 new_session->add_instant_xml (*n, false);
3397 n = Config->instant_xml (X_("Mixer"));
3399 new_session->add_instant_xml (*n, false);
3402 /* Put the playhead at 0 and scroll fully left */
3403 n = new_session->instant_xml (X_("Editor"));
3405 n->add_property (X_("playhead"), X_("0"));
3406 n->add_property (X_("left-frame"), X_("0"));
3409 set_session (new_session);
3411 session_loaded = true;
3413 new_session->save_state(new_session->name());
3419 ARDOUR_UI::launch_chat ()
3421 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3423 dialog.set_title (_("About the Chat"));
3424 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."));
3426 switch (dialog.run()) {
3429 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3430 #elif defined PLATFORM_WINDOWS
3431 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3433 open_uri("http://webchat.freenode.net/?channels=ardour");
3442 ARDOUR_UI::launch_manual ()
3444 PBD::open_uri (Config->get_tutorial_manual_url());
3448 ARDOUR_UI::launch_reference ()
3450 PBD::open_uri (Config->get_reference_manual_url());
3454 ARDOUR_UI::launch_tracker ()
3456 PBD::open_uri ("http://tracker.ardour.org");
3460 ARDOUR_UI::launch_subscribe ()
3462 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3466 ARDOUR_UI::launch_cheat_sheet ()
3469 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3471 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3476 ARDOUR_UI::launch_website ()
3478 PBD::open_uri ("http://ardour.org");
3482 ARDOUR_UI::launch_website_dev ()
3484 PBD::open_uri ("http://ardour.org/development.html");
3488 ARDOUR_UI::launch_forums ()
3490 PBD::open_uri ("https://community.ardour.org/forums");
3494 ARDOUR_UI::launch_howto_report ()
3496 PBD::open_uri ("http://ardour.org/reporting_bugs");
3500 ARDOUR_UI::loading_message (const std::string& msg)
3502 if (ARDOUR_COMMAND_LINE::no_splash) {
3510 splash->message (msg);
3514 ARDOUR_UI::show_splash ()
3518 splash = new Splash;
3528 ARDOUR_UI::hide_splash ()
3535 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3539 removed = rep.paths.size();
3542 MessageDialog msgd (_main_window,
3543 _("No files were ready for clean-up"),
3547 msgd.set_title (_("Clean-up"));
3548 msgd.set_secondary_text (_("If this seems suprising, \n\
3549 check for any existing snapshots.\n\
3550 These may still include regions that\n\
3551 require some unused files to continue to exist."));
3557 ArdourDialog results (_("Clean-up"), true, false);
3559 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3560 CleanupResultsModelColumns() {
3564 Gtk::TreeModelColumn<std::string> visible_name;
3565 Gtk::TreeModelColumn<std::string> fullpath;
3569 CleanupResultsModelColumns results_columns;
3570 Glib::RefPtr<Gtk::ListStore> results_model;
3571 Gtk::TreeView results_display;
3573 results_model = ListStore::create (results_columns);
3574 results_display.set_model (results_model);
3575 results_display.append_column (list_title, results_columns.visible_name);
3577 results_display.set_name ("CleanupResultsList");
3578 results_display.set_headers_visible (true);
3579 results_display.set_headers_clickable (false);
3580 results_display.set_reorderable (false);
3582 Gtk::ScrolledWindow list_scroller;
3585 Gtk::HBox dhbox; // the hbox for the image and text
3586 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3587 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3589 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3591 const string dead_directory = _session->session_directory().dead_path();
3594 %1 - number of files removed
3595 %2 - location of "dead"
3596 %3 - size of files affected
3597 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3600 const char* bprefix;
3601 double space_adjusted = 0;
3603 if (rep.space < 1000) {
3605 space_adjusted = rep.space;
3606 } else if (rep.space < 1000000) {
3607 bprefix = _("kilo");
3608 space_adjusted = floorf((float)rep.space / 1000.0);
3609 } else if (rep.space < 1000000 * 1000) {
3610 bprefix = _("mega");
3611 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3613 bprefix = _("giga");
3614 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3618 txt.set_markup (string_compose (P_("\
3619 The following file was deleted from %2,\n\
3620 releasing %3 %4bytes of disk space", "\
3621 The following %1 files were deleted from %2,\n\
3622 releasing %3 %4bytes of disk space", removed),
3623 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3625 txt.set_markup (string_compose (P_("\
3626 The following file was not in use and \n\
3627 has been moved to: %2\n\n\
3628 After a restart of %5\n\n\
3629 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3630 will release an additional %3 %4bytes of disk space.\n", "\
3631 The following %1 files were not in use and \n\
3632 have been moved to: %2\n\n\
3633 After a restart of %5\n\n\
3634 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3635 will release an additional %3 %4bytes of disk space.\n", removed),
3636 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3639 dhbox.pack_start (*dimage, true, false, 5);
3640 dhbox.pack_start (txt, true, false, 5);
3642 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3643 TreeModel::Row row = *(results_model->append());
3644 row[results_columns.visible_name] = *i;
3645 row[results_columns.fullpath] = *i;
3648 list_scroller.add (results_display);
3649 list_scroller.set_size_request (-1, 150);
3650 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3652 dvbox.pack_start (dhbox, true, false, 5);
3653 dvbox.pack_start (list_scroller, true, false, 5);
3654 ddhbox.pack_start (dvbox, true, false, 5);
3656 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3657 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3658 results.set_default_response (RESPONSE_CLOSE);
3659 results.set_position (Gtk::WIN_POS_MOUSE);
3661 results_display.show();
3662 list_scroller.show();
3669 //results.get_vbox()->show();
3670 results.set_resizable (false);
3677 ARDOUR_UI::cleanup ()
3679 if (_session == 0) {
3680 /* shouldn't happen: menu item is insensitive */
3685 MessageDialog checker (_("Are you sure you want to clean-up?"),
3687 Gtk::MESSAGE_QUESTION,
3690 checker.set_title (_("Clean-up"));
3692 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3693 ALL undo/redo information will be lost if you clean-up.\n\
3694 Clean-up will move all unused files to a \"dead\" location."));
3696 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3697 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3698 checker.set_default_response (RESPONSE_CANCEL);
3700 checker.set_name (_("CleanupDialog"));
3701 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3702 checker.set_position (Gtk::WIN_POS_MOUSE);
3704 switch (checker.run()) {
3705 case RESPONSE_ACCEPT:
3711 ARDOUR::CleanupReport rep;
3713 editor->prepare_for_cleanup ();
3715 /* do not allow flush until a session is reloaded */
3717 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3719 act->set_sensitive (false);
3722 if (_session->cleanup_sources (rep)) {
3723 editor->finish_cleanup ();
3727 editor->finish_cleanup ();
3730 display_cleanup_results (rep, _("Cleaned Files"), false);
3734 ARDOUR_UI::flush_trash ()
3736 if (_session == 0) {
3737 /* shouldn't happen: menu item is insensitive */
3741 ARDOUR::CleanupReport rep;
3743 if (_session->cleanup_trash_sources (rep)) {
3747 display_cleanup_results (rep, _("deleted file"), true);
3751 ARDOUR_UI::cleanup_peakfiles ()
3753 if (_session == 0) {
3754 /* shouldn't happen: menu item is insensitive */
3758 if (! _session->can_cleanup_peakfiles ()) {
3762 // get all region-views in this session
3764 TrackViewList empty;
3766 editor->get_regions_after(rs, (framepos_t) 0, empty);
3767 std::list<RegionView*> views = rs.by_layer();
3769 // remove displayed audio-region-views waveforms
3770 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3771 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3772 if (!arv) { continue ; }
3773 arv->delete_waves();
3776 // cleanup peak files:
3777 // - stop pending peakfile threads
3778 // - close peakfiles if any
3779 // - remove peak dir in session
3780 // - setup peakfiles (background thread)
3781 _session->cleanup_peakfiles ();
3783 // re-add waves to ARV
3784 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3785 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3786 if (!arv) { continue ; }
3787 arv->create_waves();
3792 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3794 uint32_t order_hint = UINT32_MAX;
3796 if (editor->get_selection().tracks.empty()) {
3801 we want the new routes to have their order keys set starting from
3802 the highest order key in the selection + 1 (if available).
3805 if (place == AddRouteDialog::AfterSelection) {
3806 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3808 order_hint = rtav->route()->order_key();
3811 } else if (place == AddRouteDialog::BeforeSelection) {
3812 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3814 order_hint = rtav->route()->order_key();
3816 } else if (place == AddRouteDialog::First) {
3819 /* leave order_hint at UINT32_MAX */
3822 if (order_hint == UINT32_MAX) {
3823 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3824 * not setting an order hint will place new routes last.
3829 _session->set_order_hint (order_hint);
3831 /* create a gap in the existing route order keys to accomodate new routes.*/
3832 boost::shared_ptr <RouteList> rd = _session->get_routes();
3833 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3834 boost::shared_ptr<Route> rt (*ri);
3836 if (rt->is_monitor()) {
3840 if (rt->order_key () >= order_hint) {
3841 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3847 ARDOUR_UI::start_duplicate_routes ()
3849 if (!duplicate_routes_dialog) {
3850 duplicate_routes_dialog = new DuplicateRouteDialog;
3853 if (duplicate_routes_dialog->restart (_session)) {
3857 duplicate_routes_dialog->present ();
3861 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3869 if (add_route_dialog->is_visible()) {
3870 /* we're already doing this */
3874 ResponseType r = (ResponseType) add_route_dialog->run ();
3876 add_route_dialog->hide();
3879 case RESPONSE_ACCEPT:
3886 if ((count = add_route_dialog->count()) <= 0) {
3890 setup_order_hint(add_route_dialog->insert_at());
3892 string template_path = add_route_dialog->track_template();
3893 DisplaySuspender ds;
3895 if (!template_path.empty()) {
3896 if (add_route_dialog->name_template_is_default()) {
3897 _session->new_route_from_template (count, template_path, string());
3899 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3904 ChanCount input_chan= add_route_dialog->channels ();
3905 ChanCount output_chan;
3906 string name_template = add_route_dialog->name_template ();
3907 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3908 RouteGroup* route_group = add_route_dialog->route_group ();
3909 AutoConnectOption oac = Config->get_output_auto_connect();
3911 if (oac & AutoConnectMaster) {
3912 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3913 output_chan.set (DataType::MIDI, 0);
3915 output_chan = input_chan;
3918 /* XXX do something with name template */
3920 switch (add_route_dialog->type_wanted()) {
3921 case AddRouteDialog::AudioTrack:
3922 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3924 case AddRouteDialog::MidiTrack:
3925 session_add_midi_track (route_group, count, name_template, instrument);
3927 case AddRouteDialog::MixedTrack:
3928 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3930 case AddRouteDialog::AudioBus:
3931 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3937 ARDOUR_UI::add_lua_script ()
3943 LuaScriptInfoPtr spi;
3944 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
3945 switch (ss.run ()) {
3946 case Gtk::RESPONSE_ACCEPT:
3953 std::string script = "";
3956 script = Glib::file_get_contents (spi->path);
3957 } catch (Glib::FileError e) {
3958 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
3959 MessageDialog am (msg);
3964 LuaScriptParamList lsp = LuaScripting::session_script_params (spi);
3965 std::vector<std::string> reg = _session->registered_lua_functions ();
3967 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
3968 switch (spd.run ()) {
3969 case Gtk::RESPONSE_ACCEPT:
3976 _session->register_lua_function (spd.name(), script, lsp);
3977 } catch (luabridge::LuaException const& e) {
3978 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
3979 MessageDialog am (msg);
3981 } catch (SessionException e) {
3982 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
3983 MessageDialog am (msg);
3989 ARDOUR_UI::remove_lua_script ()
3994 if (_session->registered_lua_function_count () == 0) {
3995 string msg = _("There are no active Lua session scripts present in this session.");
3996 MessageDialog am (msg);
4001 std::vector<std::string> reg = _session->registered_lua_functions ();
4002 SessionScriptManager sm ("Remove Lua Session Script", reg);
4003 switch (sm.run ()) {
4004 case Gtk::RESPONSE_ACCEPT:
4010 _session->unregister_lua_function (sm.name());
4011 } catch (luabridge::LuaException const& e) {
4012 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4013 MessageDialog am (msg);
4019 ARDOUR_UI::stop_video_server (bool ask_confirm)
4021 if (!video_server_process && ask_confirm) {
4022 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4024 if (video_server_process) {
4026 ArdourDialog confirm (_("Stop Video-Server"), true);
4027 Label m (_("Do you really want to stop the Video Server?"));
4028 confirm.get_vbox()->pack_start (m, true, true);
4029 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4030 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4031 confirm.show_all ();
4032 if (confirm.run() == RESPONSE_CANCEL) {
4036 delete video_server_process;
4037 video_server_process =0;
4042 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4044 ARDOUR_UI::start_video_server( float_window, true);
4048 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4054 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4055 if (video_server_process) {
4056 popup_error(_("The Video Server is already started."));
4058 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4064 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4066 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4068 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4070 video_server_dialog->set_transient_for (*float_window);
4073 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4074 video_server_dialog->hide();
4076 ResponseType r = (ResponseType) video_server_dialog->run ();
4077 video_server_dialog->hide();
4078 if (r != RESPONSE_ACCEPT) { return false; }
4079 if (video_server_dialog->show_again()) {
4080 Config->set_show_video_server_dialog(false);
4084 std::string icsd_exec = video_server_dialog->get_exec_path();
4085 std::string icsd_docroot = video_server_dialog->get_docroot();
4086 if (icsd_docroot.empty()) {
4087 #ifndef PLATFORM_WINDOWS
4088 icsd_docroot = X_("/");
4090 icsd_docroot = X_("C:\\");
4095 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4096 warning << _("Specified docroot is not an existing directory.") << endmsg;
4099 #ifndef PLATFORM_WINDOWS
4100 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4101 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4102 warning << _("Given Video Server is not an executable file.") << endmsg;
4106 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4107 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4108 warning << _("Given Video Server is not an executable file.") << endmsg;
4114 argp=(char**) calloc(9,sizeof(char*));
4115 argp[0] = strdup(icsd_exec.c_str());
4116 argp[1] = strdup("-P");
4117 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4118 argp[3] = strdup("-p");
4119 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4120 argp[5] = strdup("-C");
4121 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4122 argp[7] = strdup(icsd_docroot.c_str());
4124 stop_video_server();
4126 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4127 Config->set_video_advanced_setup(false);
4129 std::ostringstream osstream;
4130 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4131 Config->set_video_server_url(osstream.str());
4132 Config->set_video_server_docroot(icsd_docroot);
4133 Config->set_video_advanced_setup(true);
4136 if (video_server_process) {
4137 delete video_server_process;
4140 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4141 if (video_server_process->start()) {
4142 warning << _("Cannot launch the video-server") << endmsg;
4145 int timeout = 120; // 6 sec
4146 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4147 Glib::usleep (50000);
4149 if (--timeout <= 0 || !video_server_process->is_running()) break;
4152 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4154 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4155 delete video_server_process;
4156 video_server_process = 0;
4164 ARDOUR_UI::add_video (Gtk::Window* float_window)
4170 if (!start_video_server(float_window, false)) {
4171 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4176 add_video_dialog->set_transient_for (*float_window);
4179 if (add_video_dialog->is_visible()) {
4180 /* we're already doing this */
4184 ResponseType r = (ResponseType) add_video_dialog->run ();
4185 add_video_dialog->hide();
4186 if (r != RESPONSE_ACCEPT) { return; }
4188 bool local_file, orig_local_file;
4189 std::string path = add_video_dialog->file_name(local_file);
4191 std::string orig_path = path;
4192 orig_local_file = local_file;
4194 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4196 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4197 warning << string_compose(_("could not open %1"), path) << endmsg;
4200 if (!local_file && path.length() == 0) {
4201 warning << _("no video-file selected") << endmsg;
4205 std::string audio_from_video;
4206 bool detect_ltc = false;
4208 switch (add_video_dialog->import_option()) {
4209 case VTL_IMPORT_TRANSCODE:
4211 TranscodeVideoDialog *transcode_video_dialog;
4212 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4213 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4214 transcode_video_dialog->hide();
4215 if (r != RESPONSE_ACCEPT) {
4216 delete transcode_video_dialog;
4220 audio_from_video = transcode_video_dialog->get_audiofile();
4222 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4225 else if (!audio_from_video.empty()) {
4226 editor->embed_audio_from_video(
4228 video_timeline->get_offset(),
4229 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4232 switch (transcode_video_dialog->import_option()) {
4233 case VTL_IMPORT_TRANSCODED:
4234 path = transcode_video_dialog->get_filename();
4237 case VTL_IMPORT_REFERENCE:
4240 delete transcode_video_dialog;
4243 delete transcode_video_dialog;
4247 case VTL_IMPORT_NONE:
4251 /* strip _session->session_directory().video_path() from video file if possible */
4252 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4253 path=path.substr(_session->session_directory().video_path().size());
4254 if (path.at(0) == G_DIR_SEPARATOR) {
4255 path=path.substr(1);
4259 video_timeline->set_update_session_fps(auto_set_session_fps);
4261 if (video_timeline->video_file_info(path, local_file)) {
4262 XMLNode* node = new XMLNode(X_("Videotimeline"));
4263 node->add_property (X_("Filename"), path);
4264 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4265 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4266 if (orig_local_file) {
4267 node->add_property (X_("OriginalVideoFile"), orig_path);
4269 node->remove_property (X_("OriginalVideoFile"));
4271 _session->add_extra_xml (*node);
4272 _session->set_dirty ();
4274 if (!audio_from_video.empty() && detect_ltc) {
4275 std::vector<LTCFileReader::LTCMap> ltc_seq;
4278 /* TODO ask user about TV standard (LTC alignment if any) */
4279 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4280 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4282 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4284 /* TODO seek near end of file, and read LTC until end.
4285 * if it fails to find any LTC frames, scan complete file
4287 * calculate drift of LTC compared to video-duration,
4288 * ask user for reference (timecode from start/mid/end)
4291 // LTCFileReader will have written error messages
4294 ::g_unlink(audio_from_video.c_str());
4296 if (ltc_seq.size() == 0) {
4297 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4299 /* the very first TC in the file is somteimes not aligned properly */
4300 int i = ltc_seq.size() -1;
4301 ARDOUR::frameoffset_t video_start_offset =
4302 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4303 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4304 video_timeline->set_offset(video_start_offset);
4308 _session->maybe_update_session_range(
4309 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4310 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4313 if (add_video_dialog->launch_xjadeo() && local_file) {
4314 editor->set_xjadeo_sensitive(true);
4315 editor->toggle_xjadeo_proc(1);
4317 editor->toggle_xjadeo_proc(0);
4319 editor->toggle_ruler_video(true);
4324 ARDOUR_UI::remove_video ()
4326 video_timeline->close_session();
4327 editor->toggle_ruler_video(false);
4330 video_timeline->set_offset_locked(false);
4331 video_timeline->set_offset(0);
4333 /* delete session state */
4334 XMLNode* node = new XMLNode(X_("Videotimeline"));
4335 _session->add_extra_xml(*node);
4336 node = new XMLNode(X_("Videomonitor"));
4337 _session->add_extra_xml(*node);
4338 node = new XMLNode(X_("Videoexport"));
4339 _session->add_extra_xml(*node);
4340 stop_video_server();
4344 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4346 if (localcacheonly) {
4347 video_timeline->vmon_update();
4349 video_timeline->flush_cache();
4351 editor->queue_visual_videotimeline_update();
4355 ARDOUR_UI::export_video (bool range)
4357 if (ARDOUR::Config->get_show_video_export_info()) {
4358 ExportVideoInfobox infobox (_session);
4359 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4360 if (infobox.show_again()) {
4361 ARDOUR::Config->set_show_video_export_info(false);
4364 case GTK_RESPONSE_YES:
4365 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4371 export_video_dialog->set_session (_session);
4372 export_video_dialog->apply_state(editor->get_selection().time, range);
4373 export_video_dialog->run ();
4374 export_video_dialog->hide ();
4378 ARDOUR_UI::mixer_settings () const
4383 node = _session->instant_xml(X_("Mixer"));
4385 node = Config->instant_xml(X_("Mixer"));
4389 node = new XMLNode (X_("Mixer"));
4396 ARDOUR_UI::main_window_settings () const
4401 node = _session->instant_xml(X_("Main"));
4403 node = Config->instant_xml(X_("Main"));
4407 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4408 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4413 node = new XMLNode (X_("Main"));
4420 ARDOUR_UI::editor_settings () const
4425 node = _session->instant_xml(X_("Editor"));
4427 node = Config->instant_xml(X_("Editor"));
4431 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4432 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4437 node = new XMLNode (X_("Editor"));
4444 ARDOUR_UI::keyboard_settings () const
4448 node = Config->extra_xml(X_("Keyboard"));
4451 node = new XMLNode (X_("Keyboard"));
4458 ARDOUR_UI::create_xrun_marker (framepos_t where)
4461 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4462 _session->locations()->add (location);
4467 ARDOUR_UI::halt_on_xrun_message ()
4469 cerr << "HALT on xrun\n";
4470 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4475 ARDOUR_UI::xrun_handler (framepos_t where)
4481 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4483 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4484 create_xrun_marker(where);
4487 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4488 halt_on_xrun_message ();
4493 ARDOUR_UI::disk_overrun_handler ()
4495 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4497 if (!have_disk_speed_dialog_displayed) {
4498 have_disk_speed_dialog_displayed = true;
4499 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4500 The disk system on your computer\n\
4501 was not able to keep up with %1.\n\
4503 Specifically, it failed to write data to disk\n\
4504 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4505 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4511 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4512 static MessageDialog *scan_dlg = NULL;
4513 static ProgressBar *scan_pbar = NULL;
4514 static HBox *scan_tbox = NULL;
4515 static Gtk::Button *scan_timeout_button;
4518 ARDOUR_UI::cancel_plugin_scan ()
4520 PluginManager::instance().cancel_plugin_scan();
4524 ARDOUR_UI::cancel_plugin_timeout ()
4526 PluginManager::instance().cancel_plugin_timeout();
4527 scan_timeout_button->set_sensitive (false);
4531 ARDOUR_UI::plugin_scan_timeout (int timeout)
4533 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4537 scan_pbar->set_sensitive (false);
4538 scan_timeout_button->set_sensitive (true);
4539 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4542 scan_pbar->set_sensitive (false);
4543 scan_timeout_button->set_sensitive (false);
4549 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4551 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4555 const bool cancelled = PluginManager::instance().cancelled();
4556 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4557 if (cancelled && scan_dlg->is_mapped()) {
4562 if (cancelled || !can_cancel) {
4567 static Gtk::Button *cancel_button;
4569 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4570 VBox* vbox = scan_dlg->get_vbox();
4571 vbox->set_size_request(400,-1);
4572 scan_dlg->set_title (_("Scanning for plugins"));
4574 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4575 cancel_button->set_name ("EditorGTKButton");
4576 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4577 cancel_button->show();
4579 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4581 scan_tbox = manage( new HBox() );
4583 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4584 scan_timeout_button->set_name ("EditorGTKButton");
4585 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4586 scan_timeout_button->show();
4588 scan_pbar = manage(new ProgressBar());
4589 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4590 scan_pbar->set_text(_("Scan Timeout"));
4593 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4594 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4596 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4599 assert(scan_dlg && scan_tbox && cancel_button);
4601 if (type == X_("closeme")) {
4605 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4608 if (!can_cancel || !cancelled) {
4609 scan_timeout_button->set_sensitive(false);
4611 cancel_button->set_sensitive(can_cancel && !cancelled);
4617 ARDOUR_UI::gui_idle_handler ()
4620 /* due to idle calls, gtk_events_pending() may always return true */
4621 while (gtk_events_pending() && --timeout) {
4622 gtk_main_iteration ();
4627 ARDOUR_UI::disk_underrun_handler ()
4629 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4631 if (!have_disk_speed_dialog_displayed) {
4632 have_disk_speed_dialog_displayed = true;
4633 MessageDialog* msg = new MessageDialog (
4634 _main_window, string_compose (_("The disk system on your computer\n\
4635 was not able to keep up with %1.\n\
4637 Specifically, it failed to read data from disk\n\
4638 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4639 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4645 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4647 have_disk_speed_dialog_displayed = false;
4652 ARDOUR_UI::session_dialog (std::string msg)
4654 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4658 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4665 ARDOUR_UI::pending_state_dialog ()
4667 HBox* hbox = manage (new HBox());
4668 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4669 ArdourDialog dialog (_("Crash Recovery"), true);
4670 Label message (string_compose (_("\
4671 This session appears to have been in the\n\
4672 middle of recording when %1 or\n\
4673 the computer was shutdown.\n\
4675 %1 can recover any captured audio for\n\
4676 you, or it can ignore it. Please decide\n\
4677 what you would like to do.\n"), PROGRAM_NAME));
4678 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4679 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4680 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4681 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4682 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4683 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4684 dialog.set_default_response (RESPONSE_ACCEPT);
4685 dialog.set_position (WIN_POS_CENTER);
4690 switch (dialog.run ()) {
4691 case RESPONSE_ACCEPT:
4699 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4701 HBox* hbox = new HBox();
4702 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4703 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4704 Label message (string_compose (_("\
4705 This session was created with a sample rate of %1 Hz, but\n\
4706 %2 is currently running at %3 Hz. If you load this session,\n\
4707 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4709 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4710 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4711 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4712 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4713 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4714 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4715 dialog.set_default_response (RESPONSE_ACCEPT);
4716 dialog.set_position (WIN_POS_CENTER);
4721 switch (dialog.run()) {
4722 case RESPONSE_ACCEPT:
4732 ARDOUR_UI::use_config ()
4734 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4736 set_transport_controllable_state (*node);
4741 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4743 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4744 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4746 primary_clock->set (pos);
4749 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4750 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4752 secondary_clock->set (pos);
4755 if (big_clock_window) {
4756 big_clock->set (pos);
4758 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4762 ARDOUR_UI::step_edit_status_change (bool yn)
4764 // XXX should really store pre-step edit status of things
4765 // we make insensitive
4768 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4769 rec_button.set_sensitive (false);
4771 rec_button.unset_active_state ();;
4772 rec_button.set_sensitive (true);
4777 ARDOUR_UI::record_state_changed ()
4779 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4781 if (!_session || !big_clock_window) {
4782 /* why bother - the clock isn't visible */
4786 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4787 big_clock->set_active (true);
4789 big_clock->set_active (false);
4794 ARDOUR_UI::first_idle ()
4797 _session->allow_auto_play (true);
4801 editor->first_idle();
4804 Keyboard::set_can_save_keybindings (true);
4809 ARDOUR_UI::store_clock_modes ()
4811 XMLNode* node = new XMLNode(X_("ClockModes"));
4813 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4814 XMLNode* child = new XMLNode (X_("Clock"));
4816 child->add_property (X_("name"), (*x)->name());
4817 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4818 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4820 node->add_child_nocopy (*child);
4823 _session->add_extra_xml (*node);
4824 _session->set_dirty ();
4827 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4828 : Controllable (name), ui (u), type(tp)
4834 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4837 /* do nothing: these are radio-style actions */
4841 const char *action = 0;
4845 action = X_("Roll");
4848 action = X_("Stop");
4851 action = X_("GotoStart");
4854 action = X_("GotoEnd");
4857 action = X_("Loop");
4860 action = X_("PlaySelection");
4863 action = X_("Record");
4873 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4881 ARDOUR_UI::TransportControllable::get_value (void) const
4908 ARDOUR_UI::setup_profile ()
4910 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4911 Profile->set_small_screen ();
4914 if (g_getenv ("TRX")) {
4915 Profile->set_trx ();
4918 if (g_getenv ("MIXBUS")) {
4919 Profile->set_mixbus ();
4924 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4926 MissingFileDialog dialog (s, str, type);
4931 int result = dialog.run ();
4938 return 1; // quit entire session load
4941 result = dialog.get_action ();
4947 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4949 AmbiguousFileDialog dialog (file, hits);
4956 return dialog.get_which ();
4959 /** Allocate our thread-local buffers */
4961 ARDOUR_UI::get_process_buffers ()
4963 _process_thread->get_buffers ();
4966 /** Drop our thread-local buffers */
4968 ARDOUR_UI::drop_process_buffers ()
4970 _process_thread->drop_buffers ();
4974 ARDOUR_UI::feedback_detected ()
4976 _feedback_exists = true;
4980 ARDOUR_UI::successful_graph_sort ()
4982 _feedback_exists = false;
4986 ARDOUR_UI::midi_panic ()
4989 _session->midi_panic();
4994 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4996 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4997 const char* end_big = "</span>";
4998 const char* start_mono = "<tt>";
4999 const char* end_mono = "</tt>";
5001 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5002 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5003 "From now on, use the -2000 version with older versions of %3"),
5004 xml_path, backup_path, PROGRAM_NAME,
5006 start_mono, end_mono), true);
5013 ARDOUR_UI::reset_peak_display ()
5015 if (!_session || !_session->master_out() || !editor_meter) return;
5016 editor_meter->clear_meters();
5017 editor_meter_max_peak = -INFINITY;
5018 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5022 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5024 if (!_session || !_session->master_out()) return;
5025 if (group == _session->master_out()->route_group()) {
5026 reset_peak_display ();
5031 ARDOUR_UI::reset_route_peak_display (Route* route)
5033 if (!_session || !_session->master_out()) return;
5034 if (_session->master_out().get() == route) {
5035 reset_peak_display ();
5040 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5042 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5043 audio_midi_setup->set_position (WIN_POS_CENTER);
5048 response = audio_midi_setup->run();
5050 case Gtk::RESPONSE_OK:
5051 if (!AudioEngine::instance()->running()) {
5065 ARDOUR_UI::transport_numpad_timeout ()
5067 _numpad_locate_happening = false;
5068 if (_numpad_timeout_connection.connected() )
5069 _numpad_timeout_connection.disconnect();
5074 ARDOUR_UI::transport_numpad_decimal ()
5076 _numpad_timeout_connection.disconnect();
5078 if (_numpad_locate_happening) {
5079 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5080 _numpad_locate_happening = false;
5082 _pending_locate_num = 0;
5083 _numpad_locate_happening = true;
5084 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5089 ARDOUR_UI::transport_numpad_event (int num)
5091 if ( _numpad_locate_happening ) {
5092 _pending_locate_num = _pending_locate_num*10 + num;
5095 case 0: toggle_roll(false, false); break;
5096 case 1: transport_rewind(1); break;
5097 case 2: transport_forward(1); break;
5098 case 3: transport_record(true); break;
5099 case 4: toggle_session_auto_loop(); break;
5100 case 5: transport_record(false); toggle_session_auto_loop(); break;
5101 case 6: toggle_punch(); break;
5102 case 7: toggle_click(); break;
5103 case 8: toggle_auto_return(); break;
5104 case 9: toggle_follow_edits(); break;
5110 ARDOUR_UI::set_flat_buttons ()
5112 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5116 ARDOUR_UI::audioengine_became_silent ()
5118 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5120 Gtk::MESSAGE_WARNING,
5124 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5126 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5127 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5128 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5129 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5130 Gtk::HBox pay_button_box;
5131 Gtk::HBox subscribe_button_box;
5133 pay_button_box.pack_start (pay_button, true, false);
5134 subscribe_button_box.pack_start (subscribe_button, true, false);
5136 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 */
5138 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5139 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5141 msg.get_vbox()->pack_start (pay_label);
5142 msg.get_vbox()->pack_start (pay_button_box);
5143 msg.get_vbox()->pack_start (subscribe_label);
5144 msg.get_vbox()->pack_start (subscribe_button_box);
5146 msg.get_vbox()->show_all ();
5148 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5149 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5150 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5155 case Gtk::RESPONSE_YES:
5156 AudioEngine::instance()->reset_silence_countdown ();
5159 case Gtk::RESPONSE_NO:
5161 save_state_canfail ("");
5165 case Gtk::RESPONSE_CANCEL:
5167 /* don't reset, save session and exit */
5173 ARDOUR_UI::hide_application ()
5175 Application::instance ()-> hide ();
5179 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5181 /* icons, titles, WM stuff */
5183 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5185 if (window_icons.empty()) {
5186 Glib::RefPtr<Gdk::Pixbuf> icon;
5187 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5188 window_icons.push_back (icon);
5190 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5191 window_icons.push_back (icon);
5193 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5194 window_icons.push_back (icon);
5196 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5197 window_icons.push_back (icon);
5201 if (!window_icons.empty()) {
5202 window.set_default_icon_list (window_icons);
5205 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5207 if (!name.empty()) {
5211 window.set_title (title.get_string());
5212 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5214 window.set_flags (CAN_FOCUS);
5215 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5217 /* This is a hack to ensure that GTK-accelerators continue to
5218 * work. Once we switch over to entirely native bindings, this will be
5219 * unnecessary and should be removed
5221 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5223 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5224 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5225 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5226 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5230 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5232 Gtkmm2ext::Bindings* bindings = 0;
5233 Gtk::Window* window = 0;
5235 /* until we get ardour bindings working, we are not handling key
5239 if (ev->type != GDK_KEY_PRESS) {
5243 if (event_window == &_main_window) {
5245 window = event_window;
5247 /* find current tab contents */
5249 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5251 /* see if it uses the ardour binding system */
5254 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5257 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5261 window = event_window;
5263 /* see if window uses ardour binding system */
5265 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5268 /* An empty binding set is treated as if it doesn't exist */
5270 if (bindings && bindings->empty()) {
5274 return key_press_focus_accelerator_handler (*window, ev, bindings);
5278 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5280 GtkWindow* win = window.gobj();
5281 GtkWidget* focus = gtk_window_get_focus (win);
5282 bool special_handling_of_unmodified_accelerators = false;
5283 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5287 /* some widget has keyboard focus */
5289 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5291 /* A particular kind of focusable widget currently has keyboard
5292 * focus. All unmodified key events should go to that widget
5293 * first and not be used as an accelerator by default
5296 special_handling_of_unmodified_accelerators = true;
5300 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",
5303 show_gdk_event_state (ev->state),
5304 special_handling_of_unmodified_accelerators,
5305 Keyboard::some_magic_widget_has_focus(),
5307 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5308 ((ev->state & mask) ? "yes" : "no")));
5310 /* This exists to allow us to override the way GTK handles
5311 key events. The normal sequence is:
5313 a) event is delivered to a GtkWindow
5314 b) accelerators/mnemonics are activated
5315 c) if (b) didn't handle the event, propagate to
5316 the focus widget and/or focus chain
5318 The problem with this is that if the accelerators include
5319 keys without modifiers, such as the space bar or the
5320 letter "e", then pressing the key while typing into
5321 a text entry widget results in the accelerator being
5322 activated, instead of the desired letter appearing
5325 There is no good way of fixing this, but this
5326 represents a compromise. The idea is that
5327 key events involving modifiers (not Shift)
5328 get routed into the activation pathway first, then
5329 get propagated to the focus widget if necessary.
5331 If the key event doesn't involve modifiers,
5332 we deliver to the focus widget first, thus allowing
5333 it to get "normal text" without interference
5336 Of course, this can also be problematic: if there
5337 is a widget with focus, then it will swallow
5338 all "normal text" accelerators.
5342 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5344 /* no special handling or there are modifiers in effect: accelerate first */
5346 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5347 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5348 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5350 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5351 KeyboardKey k (ev->state, ev->keyval);
5355 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5357 if (bindings->activate (k, Bindings::Press)) {
5358 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5363 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5365 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5366 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5370 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5372 if (gtk_window_propagate_key_event (win, ev)) {
5373 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5379 /* no modifiers, propagate first */
5381 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5383 if (gtk_window_propagate_key_event (win, ev)) {
5384 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5388 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5389 KeyboardKey k (ev->state, ev->keyval);
5393 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5396 if (bindings->activate (k, Bindings::Press)) {
5397 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5403 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5405 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5406 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5411 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5416 ARDOUR_UI::load_bindings ()
5418 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5419 error << _("Global keybindings are missing") << endmsg;
5424 ARDOUR_UI::cancel_solo ()
5427 if (_session->soloing()) {
5428 _session->set_solo (_session->get_routes(), false);
5429 } else if (_session->listening()) {
5430 _session->set_listen (_session->get_routes(), false);
5433 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window