2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #include "LuaBridge/LuaBridge.h"
96 #ifdef WINDOWS_VST_SUPPORT
99 #ifdef AUDIOUNIT_SUPPORT
100 #include "ardour/audio_unit.h"
103 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
108 #include "timecode/time.h"
110 typedef uint64_t microseconds_t;
115 #include "add_route_dialog.h"
116 #include "ambiguous_file_dialog.h"
117 #include "ardour_ui.h"
118 #include "audio_clock.h"
119 #include "audio_region_view.h"
120 #include "big_clock_window.h"
121 #include "bundle_manager.h"
122 #include "duplicate_routes_dialog.h"
124 #include "engine_dialog.h"
125 #include "export_video_dialog.h"
126 #include "export_video_infobox.h"
127 #include "gain_meter.h"
128 #include "global_port_matrix.h"
129 #include "gui_object.h"
130 #include "gui_thread.h"
131 #include "keyboard.h"
132 #include "keyeditor.h"
133 #include "location_ui.h"
134 #include "luawindow.h"
135 #include "main_clock.h"
136 #include "missing_file_dialog.h"
137 #include "missing_plugin_dialog.h"
138 #include "mixer_ui.h"
139 #include "meterbridge.h"
140 #include "mouse_cursors.h"
143 #include "pingback.h"
144 #include "processor_box.h"
145 #include "prompter.h"
146 #include "public_editor.h"
147 #include "rc_option_editor.h"
148 #include "route_time_axis.h"
149 #include "route_params_ui.h"
150 #include "save_as_dialog.h"
151 #include "script_selector.h"
152 #include "session_dialog.h"
153 #include "session_metadata_dialog.h"
154 #include "session_option_editor.h"
155 #include "shuttle_control.h"
156 #include "speaker_dialog.h"
159 #include "theme_manager.h"
160 #include "time_axis_view_item.h"
163 #include "video_server_dialog.h"
164 #include "add_video_dialog.h"
165 #include "transcode_video_dialog.h"
169 using namespace ARDOUR;
170 using namespace ARDOUR_UI_UTILS;
172 using namespace Gtkmm2ext;
175 using namespace Editing;
177 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
179 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
180 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
183 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
185 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
186 "Would you like these files to be copied and used for %1 %2.x?\n\n"
187 "(This will require you to restart %1.)"),
188 PROGRAM_NAME, PROGRAM_VERSION, version),
189 false, /* no markup */
192 true /* modal, though it hardly matters since it is the only window */
195 msg.set_default_response (Gtk::RESPONSE_YES);
198 return (msg.run() == Gtk::RESPONSE_YES);
202 libxml_generic_error_func (void* /* parsing_context*/,
210 vsnprintf (buf, sizeof (buf), msg, ap);
211 error << buf << endmsg;
216 libxml_structured_error_func (void* /* parsing_context*/,
224 replace_all (msg, "\n", "");
226 if (err->file && err->line) {
227 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
230 error << ':' << err->int2;
237 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
238 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
239 , session_loaded (false)
240 , gui_object_state (new GUIObjectState)
241 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
242 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
243 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
245 , global_actions (X_("global"))
246 , ignore_dual_punch (false)
251 , _mixer_on_top (false)
252 , _initial_verbose_plugin_scan (false)
253 , first_time_engine_run (true)
254 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
255 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
256 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
257 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
258 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
259 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
260 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
261 , auto_return_button (ArdourButton::led_default_elements)
262 , follow_edits_button (ArdourButton::led_default_elements)
263 , auto_input_button (ArdourButton::led_default_elements)
264 , auditioning_alert_button (_("Audition"))
265 , solo_alert_button (_("Solo"))
266 , feedback_alert_button (_("Feedback"))
267 , error_alert_button ( ArdourButton::just_led_default_elements )
269 , editor_meter_peak_display()
270 , _numpad_locate_happening (false)
271 , _session_is_new (false)
272 , last_key_press_time (0)
276 , rc_option_editor (0)
277 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
278 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
279 , about (X_("about"), _("About"))
280 , location_ui (X_("locations"), _("Locations"))
281 , route_params (X_("inspector"), _("Tracks and Busses"))
282 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
283 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
284 , lua_script_window (X_("script-manager"), _("Script Manager"))
285 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
286 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
287 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
288 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
289 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
290 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
291 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
292 , video_server_process (0)
294 , have_configure_timeout (false)
295 , last_configure_time (0)
297 , have_disk_speed_dialog_displayed (false)
298 , _status_bar_visibility (X_("status-bar"))
299 , _feedback_exists (false)
300 , _log_not_acknowledged (LogLevelNone)
301 , duplicate_routes_dialog (0)
302 , editor_visibility_button (S_("Window|Editor"))
303 , mixer_visibility_button (S_("Window|Mixer"))
304 , prefs_visibility_button (S_("Window|Preferences"))
306 Gtkmm2ext::init (localedir);
308 UIConfiguration::instance().post_gui_init ();
310 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
311 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
313 /* configuration was modified, exit immediately */
317 if (theArdourUI == 0) {
321 /* stop libxml from spewing to stdout/stderr */
323 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
324 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
326 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
327 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
328 UIConfiguration::instance().map_parameters (pc);
330 roll_button.set_controllable (roll_controllable);
331 stop_button.set_controllable (stop_controllable);
332 goto_start_button.set_controllable (goto_start_controllable);
333 goto_end_button.set_controllable (goto_end_controllable);
334 auto_loop_button.set_controllable (auto_loop_controllable);
335 play_selection_button.set_controllable (play_selection_controllable);
336 rec_button.set_controllable (rec_controllable);
338 roll_button.set_name ("transport button");
339 stop_button.set_name ("transport button");
340 goto_start_button.set_name ("transport button");
341 goto_end_button.set_name ("transport button");
342 auto_loop_button.set_name ("transport button");
343 play_selection_button.set_name ("transport button");
344 rec_button.set_name ("transport recenable button");
345 midi_panic_button.set_name ("transport button");
347 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
348 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
350 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
352 /* handle dialog requests */
354 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
356 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
358 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
360 /* handle Audio/MIDI setup when session requires it */
362 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
364 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
366 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
368 /* handle requests to quit (coming from JACK session) */
370 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
372 /* tell the user about feedback */
374 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
375 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
377 /* handle requests to deal with missing files */
379 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
381 /* and ambiguous files */
383 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
385 /* also plugin scan messages */
386 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
387 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
389 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
391 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
394 /* lets get this party started */
396 setup_gtk_ardour_enums ();
399 SessionEvent::create_per_thread_pool ("GUI", 4096);
401 /* we like keyboards */
403 keyboard = new ArdourKeyboard(*this);
405 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
407 keyboard->set_state (*node, Stateful::loading_state_version);
410 UIConfiguration::instance().reset_dpi ();
412 TimeAxisViewItem::set_constant_heights ();
414 /* Set this up so that our window proxies can register actions */
416 ActionManager::init ();
418 /* The following must happen after ARDOUR::init() so that Config is set up */
420 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
423 key_editor.set_state (*ui_xml, 0);
424 session_option_editor.set_state (*ui_xml, 0);
425 speaker_config_window.set_state (*ui_xml, 0);
426 about.set_state (*ui_xml, 0);
427 add_route_dialog.set_state (*ui_xml, 0);
428 add_video_dialog.set_state (*ui_xml, 0);
429 route_params.set_state (*ui_xml, 0);
430 bundle_manager.set_state (*ui_xml, 0);
431 location_ui.set_state (*ui_xml, 0);
432 big_clock_window.set_state (*ui_xml, 0);
433 audio_port_matrix.set_state (*ui_xml, 0);
434 midi_port_matrix.set_state (*ui_xml, 0);
435 export_video_dialog.set_state (*ui_xml, 0);
436 lua_script_window.set_state (*ui_xml, 0);
439 /* Separate windows */
441 WM::Manager::instance().register_window (&key_editor);
442 WM::Manager::instance().register_window (&session_option_editor);
443 WM::Manager::instance().register_window (&speaker_config_window);
444 WM::Manager::instance().register_window (&about);
445 WM::Manager::instance().register_window (&add_route_dialog);
446 WM::Manager::instance().register_window (&add_video_dialog);
447 WM::Manager::instance().register_window (&route_params);
448 WM::Manager::instance().register_window (&audio_midi_setup);
449 WM::Manager::instance().register_window (&export_video_dialog);
450 WM::Manager::instance().register_window (&lua_script_window);
451 WM::Manager::instance().register_window (&bundle_manager);
452 WM::Manager::instance().register_window (&location_ui);
453 WM::Manager::instance().register_window (&big_clock_window);
454 WM::Manager::instance().register_window (&audio_port_matrix);
455 WM::Manager::instance().register_window (&midi_port_matrix);
457 /* Trigger setting up the color scheme and loading the GTK RC file */
459 UIConfiguration::instance().load_rc_file (false);
461 _process_thread = new ProcessThread ();
462 _process_thread->init ();
464 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
469 GlobalPortMatrixWindow*
470 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
475 return new GlobalPortMatrixWindow (_session, type);
479 ARDOUR_UI::attach_to_engine ()
481 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
482 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
486 ARDOUR_UI::engine_stopped ()
488 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
489 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
490 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
491 update_sample_rate (0);
496 ARDOUR_UI::engine_running ()
498 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
499 if (first_time_engine_run) {
501 first_time_engine_run = false;
505 _session->reset_xrun_count ();
507 update_disk_space ();
509 update_xrun_count ();
510 update_sample_rate (AudioEngine::instance()->sample_rate());
511 update_timecode_format ();
512 update_peak_thread_work ();
513 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
514 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
518 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
520 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
521 /* we can't rely on the original string continuing to exist when we are called
522 again in the GUI thread, so make a copy and note that we need to
525 char *copy = strdup (reason);
526 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
530 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
531 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
533 update_sample_rate (0);
537 /* if the reason is a non-empty string, it means that the backend was shutdown
538 rather than just Ardour.
541 if (strlen (reason)) {
542 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
544 msgstr = string_compose (_("\
545 The audio backend has either been shutdown or it\n\
546 disconnected %1 because %1\n\
547 was not fast enough. Try to restart\n\
548 the audio backend and save the session."), PROGRAM_NAME);
551 MessageDialog msg (_main_window, msgstr);
552 pop_back_splash (msg);
556 free (const_cast<char*> (reason));
561 ARDOUR_UI::post_engine ()
563 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
565 #ifdef AUDIOUNIT_SUPPORT
567 if (AUPluginInfo::au_get_crashlog(au_msg)) {
568 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
569 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
570 info << au_msg << endmsg;
574 ARDOUR::init_post_engine ();
576 /* connect to important signals */
578 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
579 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
580 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
581 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
582 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
584 if (setup_windows ()) {
585 throw failed_constructor ();
588 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
589 XMLNode* n = Config->extra_xml (X_("UI"));
591 _status_bar_visibility.set_state (*n);
594 check_memory_locking();
596 /* this is the first point at which all the possible actions are
597 * available, because some of the available actions are dependent on
598 * aspects of the engine/backend.
601 if (ARDOUR_COMMAND_LINE::show_key_actions) {
604 vector<string> paths;
605 vector<string> labels;
606 vector<string> tooltips;
608 vector<Glib::RefPtr<Gtk::Action> > actions;
610 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
612 vector<string>::iterator k;
613 vector<string>::iterator p;
615 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
620 cout << *p << " => " << *k << endl;
624 halt_connection.disconnect ();
625 AudioEngine::instance()->stop ();
629 /* this being a GUI and all, we want peakfiles */
631 AudioFileSource::set_build_peakfiles (true);
632 AudioFileSource::set_build_missing_peakfiles (true);
634 /* set default clock modes */
636 primary_clock->set_mode (AudioClock::Timecode);
637 secondary_clock->set_mode (AudioClock::BBT);
639 /* start the time-of-day-clock */
642 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
643 update_wall_clock ();
644 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
649 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
650 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
651 Config->map_parameters (pc);
653 UIConfiguration::instance().map_parameters (pc);
657 ARDOUR_UI::~ARDOUR_UI ()
659 UIConfiguration::instance().save_state();
663 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
664 // don't bother at 'real' exit. the OS cleans up for us.
666 delete primary_clock;
667 delete secondary_clock;
668 delete _process_thread;
674 delete gui_object_state;
675 FastMeter::flush_pattern_cache ();
676 PixFader::flush_pattern_cache ();
680 /* Small trick to flush main-thread event pool.
681 * Other thread-pools are destroyed at pthread_exit(),
682 * but tmain thread termination is too late to trigger Pool::~Pool()
684 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.
685 delete ev->event_pool();
690 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
692 if (Splash::instance()) {
693 Splash::instance()->pop_back_for (win);
698 ARDOUR_UI::configure_timeout ()
700 if (last_configure_time == 0) {
701 /* no configure events yet */
705 /* force a gap of 0.5 seconds since the last configure event
708 if (get_microseconds() - last_configure_time < 500000) {
711 have_configure_timeout = false;
712 save_ardour_state ();
718 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
720 if (have_configure_timeout) {
721 last_configure_time = get_microseconds();
723 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
724 have_configure_timeout = true;
731 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
733 const XMLProperty* prop;
735 if ((prop = node.property ("roll")) != 0) {
736 roll_controllable->set_id (prop->value());
738 if ((prop = node.property ("stop")) != 0) {
739 stop_controllable->set_id (prop->value());
741 if ((prop = node.property ("goto-start")) != 0) {
742 goto_start_controllable->set_id (prop->value());
744 if ((prop = node.property ("goto-end")) != 0) {
745 goto_end_controllable->set_id (prop->value());
747 if ((prop = node.property ("auto-loop")) != 0) {
748 auto_loop_controllable->set_id (prop->value());
750 if ((prop = node.property ("play-selection")) != 0) {
751 play_selection_controllable->set_id (prop->value());
753 if ((prop = node.property ("rec")) != 0) {
754 rec_controllable->set_id (prop->value());
756 if ((prop = node.property ("shuttle")) != 0) {
757 shuttle_box->controllable()->set_id (prop->value());
762 ARDOUR_UI::get_transport_controllable_state ()
764 XMLNode* node = new XMLNode(X_("TransportControllables"));
767 roll_controllable->id().print (buf, sizeof (buf));
768 node->add_property (X_("roll"), buf);
769 stop_controllable->id().print (buf, sizeof (buf));
770 node->add_property (X_("stop"), buf);
771 goto_start_controllable->id().print (buf, sizeof (buf));
772 node->add_property (X_("goto_start"), buf);
773 goto_end_controllable->id().print (buf, sizeof (buf));
774 node->add_property (X_("goto_end"), buf);
775 auto_loop_controllable->id().print (buf, sizeof (buf));
776 node->add_property (X_("auto_loop"), buf);
777 play_selection_controllable->id().print (buf, sizeof (buf));
778 node->add_property (X_("play_selection"), buf);
779 rec_controllable->id().print (buf, sizeof (buf));
780 node->add_property (X_("rec"), buf);
781 shuttle_box->controllable()->id().print (buf, sizeof (buf));
782 node->add_property (X_("shuttle"), buf);
788 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
791 _session->save_state (snapshot_name);
796 ARDOUR_UI::autosave_session ()
798 if (g_main_depth() > 1) {
799 /* inside a recursive main loop,
800 give up because we may not be able to
806 if (!Config->get_periodic_safety_backups()) {
811 _session->maybe_write_autosave();
818 ARDOUR_UI::session_dirty_changed ()
825 ARDOUR_UI::update_autosave ()
827 if (_session && _session->dirty()) {
828 if (_autosave_connection.connected()) {
829 _autosave_connection.disconnect();
832 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
833 Config->get_periodic_safety_backup_interval() * 1000);
836 if (_autosave_connection.connected()) {
837 _autosave_connection.disconnect();
843 ARDOUR_UI::check_announcements ()
846 string _annc_filename;
849 _annc_filename = PROGRAM_NAME "_announcements_osx_";
850 #elif defined PLATFORM_WINDOWS
851 _annc_filename = PROGRAM_NAME "_announcements_windows_";
853 _annc_filename = PROGRAM_NAME "_announcements_linux_";
855 _annc_filename.append (VERSIONSTRING);
857 _announce_string = "";
859 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
860 FILE* fin = g_fopen (path.c_str(), "rb");
862 while (!feof (fin)) {
865 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
868 _announce_string.append (tmp, len);
873 pingback (VERSIONSTRING, path);
878 _hide_splash (gpointer arg)
880 ((ARDOUR_UI*)arg)->hide_splash();
885 ARDOUR_UI::starting ()
887 Application* app = Application::instance ();
889 bool brand_new_user = ArdourStartup::required ();
891 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
892 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
894 if (ARDOUR_COMMAND_LINE::check_announcements) {
895 check_announcements ();
900 /* we need to create this early because it may need to set the
901 * audio backend end up.
905 audio_midi_setup.get (true);
907 std::cerr << "audio-midi engine setup failed."<< std::endl;
911 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
912 nsm = new NSM_Client;
913 if (!nsm->init (nsm_url)) {
914 /* the ardour executable may have different names:
916 * waf's obj.target for distro versions: eg ardour4, ardourvst4
917 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
918 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
920 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
922 const char *process_name = g_getenv ("ARDOUR_SELF");
923 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
926 // wait for announce reply from nsm server
927 for ( i = 0; i < 5000; ++i) {
931 if (nsm->is_active()) {
936 error << _("NSM server did not announce itself") << endmsg;
939 // wait for open command from nsm server
940 for ( i = 0; i < 5000; ++i) {
943 if (nsm->client_id ()) {
949 error << _("NSM: no client ID provided") << endmsg;
953 if (_session && nsm) {
954 _session->set_nsm_state( nsm->is_active() );
956 error << _("NSM: no session created") << endmsg;
960 // nsm requires these actions disabled
961 vector<string> action_names;
962 action_names.push_back("SaveAs");
963 action_names.push_back("Rename");
964 action_names.push_back("New");
965 action_names.push_back("Open");
966 action_names.push_back("Recent");
967 action_names.push_back("Close");
969 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
970 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
972 act->set_sensitive (false);
979 error << _("NSM: initialization failed") << endmsg;
985 if (brand_new_user) {
986 _initial_verbose_plugin_scan = true;
991 _initial_verbose_plugin_scan = false;
992 switch (s.response ()) {
993 case Gtk::RESPONSE_OK:
1000 #ifdef NO_PLUGIN_STATE
1002 ARDOUR::RecentSessions rs;
1003 ARDOUR::read_recent_sessions (rs);
1005 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1007 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1009 /* already used Ardour, have sessions ... warn about plugin state */
1011 ArdourDialog d (_("Free/Demo Version Warning"), true);
1013 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1014 CheckButton c (_("Don't warn me about this again"));
1016 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"),
1017 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1018 _("It will not restore OR save any plugin settings"),
1019 _("If you load an existing session with plugin settings\n"
1020 "they will not be used and will be lost."),
1021 _("To get full access to updates without this limitation\n"
1022 "consider becoming a subscriber for a low cost every month.")));
1023 l.set_justify (JUSTIFY_CENTER);
1025 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1027 d.get_vbox()->pack_start (l, true, true);
1028 d.get_vbox()->pack_start (b, false, false, 12);
1029 d.get_vbox()->pack_start (c, false, false, 12);
1031 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1032 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1036 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1038 if (d.run () != RESPONSE_OK) {
1044 /* go get a session */
1046 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1048 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1049 std::cerr << "Cannot get session parameters."<< std::endl;
1056 WM::Manager::instance().show_visible ();
1058 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1059 * editor window, and we may want stuff to be hidden.
1061 _status_bar_visibility.update ();
1063 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1065 if (splash && splash->is_visible()) {
1066 // in 1 second, hide the splash screen
1067 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1070 /* all other dialogs are created conditionally */
1076 ARDOUR_UI::check_memory_locking ()
1078 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1079 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1083 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1085 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1087 struct rlimit limits;
1089 long pages, page_size;
1091 size_t pages_len=sizeof(pages);
1092 if ((page_size = getpagesize()) < 0 ||
1093 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1095 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1100 ram = (int64_t) pages * (int64_t) page_size;
1103 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1107 if (limits.rlim_cur != RLIM_INFINITY) {
1109 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1113 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1114 "This might cause %1 to run out of memory before your system "
1115 "runs out of memory. \n\n"
1116 "You can view the memory limit with 'ulimit -l', "
1117 "and it is normally controlled by %2"),
1120 X_("/etc/login.conf")
1122 X_(" /etc/security/limits.conf")
1126 msg.set_default_response (RESPONSE_OK);
1128 VBox* vbox = msg.get_vbox();
1130 CheckButton cb (_("Do not show this window again"));
1131 hbox.pack_start (cb, true, false);
1132 vbox->pack_start (hbox);
1137 pop_back_splash (msg);
1141 if (cb.get_active()) {
1142 XMLNode node (X_("no-memory-warning"));
1143 Config->add_instant_xml (node);
1148 #endif // !__APPLE__
1153 ARDOUR_UI::queue_finish ()
1155 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1159 ARDOUR_UI::idle_finish ()
1162 return false; /* do not call again */
1169 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1171 if (_session->dirty()) {
1172 vector<string> actions;
1173 actions.push_back (_("Don't quit"));
1174 actions.push_back (_("Just quit"));
1175 actions.push_back (_("Save and quit"));
1176 switch (ask_about_saving_session(actions)) {
1181 /* use the default name */
1182 if (save_state_canfail ("")) {
1183 /* failed - don't quit */
1184 MessageDialog msg (_main_window,
1185 string_compose (_("\
1186 %1 was unable to save your session.\n\n\
1187 If you still wish to quit, please use the\n\n\
1188 \"Just quit\" option."), PROGRAM_NAME));
1189 pop_back_splash(msg);
1199 second_connection.disconnect ();
1200 point_one_second_connection.disconnect ();
1201 point_zero_something_second_connection.disconnect();
1202 fps_connection.disconnect();
1205 delete ARDOUR_UI::instance()->video_timeline;
1206 ARDOUR_UI::instance()->video_timeline = NULL;
1207 stop_video_server();
1209 /* Save state before deleting the session, as that causes some
1210 windows to be destroyed before their visible state can be
1213 save_ardour_state ();
1215 close_all_dialogs ();
1218 _session->set_clean ();
1219 _session->remove_pending_capture_state ();
1224 halt_connection.disconnect ();
1225 AudioEngine::instance()->stop ();
1226 #ifdef WINDOWS_VST_SUPPORT
1227 fst_stop_threading();
1233 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1235 ArdourDialog window (_("Unsaved Session"));
1236 Gtk::HBox dhbox; // the hbox for the image and text
1237 Gtk::Label prompt_label;
1238 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1242 assert (actions.size() >= 3);
1244 window.add_button (actions[0], RESPONSE_REJECT);
1245 window.add_button (actions[1], RESPONSE_APPLY);
1246 window.add_button (actions[2], RESPONSE_ACCEPT);
1248 window.set_default_response (RESPONSE_ACCEPT);
1250 Gtk::Button noquit_button (msg);
1251 noquit_button.set_name ("EditorGTKButton");
1255 if (_session->snap_name() == _session->name()) {
1256 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?"),
1257 _session->snap_name());
1259 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?"),
1260 _session->snap_name());
1263 prompt_label.set_text (prompt);
1264 prompt_label.set_name (X_("PrompterLabel"));
1265 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1267 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1268 dhbox.set_homogeneous (false);
1269 dhbox.pack_start (*dimage, false, false, 5);
1270 dhbox.pack_start (prompt_label, true, false, 5);
1271 window.get_vbox()->pack_start (dhbox);
1273 window.set_name (_("Prompter"));
1274 window.set_modal (true);
1275 window.set_resizable (false);
1278 prompt_label.show();
1283 ResponseType r = (ResponseType) window.run();
1288 case RESPONSE_ACCEPT: // save and get out of here
1290 case RESPONSE_APPLY: // get out of here
1301 ARDOUR_UI::every_second ()
1304 update_xrun_count ();
1305 update_buffer_load ();
1306 update_disk_space ();
1307 update_timecode_format ();
1308 update_peak_thread_work ();
1310 if (nsm && nsm->is_active ()) {
1313 if (!_was_dirty && _session->dirty ()) {
1317 else if (_was_dirty && !_session->dirty ()){
1325 ARDOUR_UI::every_point_one_seconds ()
1327 // TODO get rid of this..
1328 // ShuttleControl is updated directly via TransportStateChange signal
1332 ARDOUR_UI::every_point_zero_something_seconds ()
1334 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1336 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1337 float mpeak = editor_meter->update_meters();
1338 if (mpeak > editor_meter_max_peak) {
1339 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1340 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1347 ARDOUR_UI::set_fps_timeout_connection ()
1349 unsigned int interval = 40;
1350 if (!_session) return;
1351 if (_session->timecode_frames_per_second() != 0) {
1352 /* ideally we'll use a select() to sleep and not accumulate
1353 * idle time to provide a regular periodic signal.
1354 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1355 * However, that'll require a dedicated thread and cross-thread
1356 * signals to the GUI Thread..
1358 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1359 * _session->frame_rate() / _session->nominal_frame_rate()
1360 / _session->timecode_frames_per_second()
1362 #ifdef PLATFORM_WINDOWS
1363 // the smallest windows scheduler time-slice is ~15ms.
1364 // periodic GUI timeouts shorter than that will cause
1365 // WaitForSingleObject to spinlock (100% of one CPU Core)
1366 // and gtk never enters idle mode.
1367 // also changing timeBeginPeriod(1) does not affect that in
1368 // any beneficial way, so we just limit the max rate for now.
1369 interval = std::max(30u, interval); // at most ~33Hz.
1371 interval = std::max(8u, interval); // at most 120Hz.
1374 fps_connection.disconnect();
1375 Timers::set_fps_interval (interval);
1379 ARDOUR_UI::update_sample_rate (framecnt_t)
1383 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1385 if (!AudioEngine::instance()->connected()) {
1387 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1391 framecnt_t rate = AudioEngine::instance()->sample_rate();
1394 /* no sample rate available */
1395 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1398 if (fmod (rate, 1000.0) != 0.0) {
1399 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1400 (float) rate / 1000.0f,
1401 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1403 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1405 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1409 sample_rate_label.set_markup (buf);
1413 ARDOUR_UI::update_format ()
1416 format_label.set_text ("");
1421 s << _("File:") << X_(" <span foreground=\"green\">");
1423 switch (_session->config.get_native_file_header_format ()) {
1455 switch (_session->config.get_native_file_data_format ()) {
1469 format_label.set_markup (s.str ());
1473 ARDOUR_UI::update_xrun_count ()
1477 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1478 should also be changed.
1482 const unsigned int x = _session->get_xrun_count ();
1484 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1486 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1489 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1491 xrun_label.set_markup (buf);
1492 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1496 ARDOUR_UI::update_cpu_load ()
1500 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1501 should also be changed.
1504 double const c = AudioEngine::instance()->get_dsp_load ();
1505 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1506 cpu_load_label.set_markup (buf);
1510 ARDOUR_UI::update_peak_thread_work ()
1513 const int c = SourceFactory::peak_work_queue_length ();
1515 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1516 peak_thread_work_label.set_markup (buf);
1518 peak_thread_work_label.set_markup (X_(""));
1523 ARDOUR_UI::update_buffer_load ()
1527 uint32_t const playback = _session ? _session->playback_load () : 100;
1528 uint32_t const capture = _session ? _session->capture_load () : 100;
1530 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1531 should also be changed.
1537 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1538 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1539 playback <= 5 ? X_("red") : X_("green"),
1541 capture <= 5 ? X_("red") : X_("green"),
1545 buffer_load_label.set_markup (buf);
1547 buffer_load_label.set_text ("");
1552 ARDOUR_UI::count_recenabled_streams (Route& route)
1554 Track* track = dynamic_cast<Track*>(&route);
1555 if (track && track->record_enabled()) {
1556 rec_enabled_streams += track->n_inputs().n_total();
1561 ARDOUR_UI::update_disk_space()
1563 if (_session == 0) {
1567 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1569 framecnt_t fr = _session->frame_rate();
1572 /* skip update - no SR available */
1577 /* Available space is unknown */
1578 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1579 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1580 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1582 rec_enabled_streams = 0;
1583 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1585 framecnt_t frames = opt_frames.get_value_or (0);
1587 if (rec_enabled_streams) {
1588 frames /= rec_enabled_streams;
1595 hrs = frames / (fr * 3600);
1598 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1600 frames -= hrs * fr * 3600;
1601 mins = frames / (fr * 60);
1602 frames -= mins * fr * 60;
1605 bool const low = (hrs == 0 && mins <= 30);
1609 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1610 low ? X_("red") : X_("green"),
1616 disk_space_label.set_markup (buf);
1620 ARDOUR_UI::update_timecode_format ()
1626 TimecodeSlave* tcslave;
1627 SyncSource sync_src = Config->get_sync_source();
1629 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1630 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1635 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1636 matching ? X_("green") : X_("red"),
1637 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1639 snprintf (buf, sizeof (buf), "TC: n/a");
1642 timecode_format_label.set_markup (buf);
1646 ARDOUR_UI::update_wall_clock ()
1650 static int last_min = -1;
1653 tm_now = localtime (&now);
1654 if (last_min != tm_now->tm_min) {
1656 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1657 wall_clock_label.set_text (buf);
1658 last_min = tm_now->tm_min;
1665 ARDOUR_UI::open_recent_session ()
1667 bool can_return = (_session != 0);
1669 SessionDialog recent_session_dialog;
1673 ResponseType r = (ResponseType) recent_session_dialog.run ();
1676 case RESPONSE_ACCEPT:
1680 recent_session_dialog.hide();
1687 recent_session_dialog.hide();
1691 std::string path = recent_session_dialog.session_folder();
1692 std::string state = recent_session_dialog.session_name (should_be_new);
1694 if (should_be_new == true) {
1698 _session_is_new = false;
1700 if (load_session (path, state) == 0) {
1709 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1711 if (!AudioEngine::instance()->connected()) {
1712 MessageDialog msg (parent, string_compose (
1713 _("%1 is not connected to any audio backend.\n"
1714 "You cannot open or close sessions in this condition"),
1716 pop_back_splash (msg);
1724 ARDOUR_UI::open_session ()
1726 if (!check_audioengine (_main_window)) {
1730 /* ardour sessions are folders */
1731 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1732 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1733 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1734 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1737 string session_parent_dir = Glib::path_get_dirname(_session->path());
1738 open_session_selector.set_current_folder(session_parent_dir);
1740 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1743 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1745 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1746 string default_session_folder = Config->get_default_session_parent_dir();
1747 open_session_selector.add_shortcut_folder (default_session_folder);
1749 catch (Glib::Error & e) {
1750 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1753 FileFilter session_filter;
1754 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1755 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1756 open_session_selector.add_filter (session_filter);
1757 open_session_selector.set_filter (session_filter);
1759 int response = open_session_selector.run();
1760 open_session_selector.hide ();
1762 if (response == Gtk::RESPONSE_CANCEL) {
1766 string session_path = open_session_selector.get_filename();
1770 if (session_path.length() > 0) {
1771 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1772 _session_is_new = isnew;
1773 load_session (path, name);
1780 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1781 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1783 list<boost::shared_ptr<MidiTrack> > tracks;
1785 if (_session == 0) {
1786 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1791 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1793 if (tracks.size() != how_many) {
1794 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1799 MessageDialog msg (_main_window,
1800 string_compose (_("There are insufficient ports available\n\
1801 to create a new track or bus.\n\
1802 You should save %1, exit and\n\
1803 restart with more ports."), PROGRAM_NAME));
1810 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1812 ChanCount one_midi_channel;
1813 one_midi_channel.set (DataType::MIDI, 1);
1816 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1821 ARDOUR_UI::session_add_audio_route (
1823 int32_t input_channels,
1824 int32_t output_channels,
1825 ARDOUR::TrackMode mode,
1826 RouteGroup* route_group,
1828 string const & name_template
1831 list<boost::shared_ptr<AudioTrack> > tracks;
1834 if (_session == 0) {
1835 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1841 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1843 if (tracks.size() != how_many) {
1844 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1850 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1852 if (routes.size() != how_many) {
1853 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1860 MessageDialog msg (_main_window,
1861 string_compose (_("There are insufficient ports available\n\
1862 to create a new track or bus.\n\
1863 You should save %1, exit and\n\
1864 restart with more ports."), PROGRAM_NAME));
1865 pop_back_splash (msg);
1871 ARDOUR_UI::transport_goto_start ()
1874 _session->goto_start();
1876 /* force displayed area in editor to start no matter
1877 what "follow playhead" setting is.
1881 editor->center_screen (_session->current_start_frame ());
1887 ARDOUR_UI::transport_goto_zero ()
1890 _session->request_locate (0);
1892 /* force displayed area in editor to start no matter
1893 what "follow playhead" setting is.
1897 editor->reset_x_origin (0);
1903 ARDOUR_UI::transport_goto_wallclock ()
1905 if (_session && editor) {
1912 localtime_r (&now, &tmnow);
1914 framecnt_t frame_rate = _session->frame_rate();
1916 if (frame_rate == 0) {
1917 /* no frame rate available */
1921 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1922 frames += tmnow.tm_min * (60 * frame_rate);
1923 frames += tmnow.tm_sec * frame_rate;
1925 _session->request_locate (frames, _session->transport_rolling ());
1927 /* force displayed area in editor to start no matter
1928 what "follow playhead" setting is.
1932 editor->center_screen (frames);
1938 ARDOUR_UI::transport_goto_end ()
1941 framepos_t const frame = _session->current_end_frame();
1942 _session->request_locate (frame);
1944 /* force displayed area in editor to start no matter
1945 what "follow playhead" setting is.
1949 editor->center_screen (frame);
1955 ARDOUR_UI::transport_stop ()
1961 if (_session->is_auditioning()) {
1962 _session->cancel_audition ();
1966 _session->request_stop (false, true);
1969 /** Check if any tracks are record enabled. If none are, record enable all of them.
1970 * @return true if track record-enabled status was changed, false otherwise.
1973 ARDOUR_UI::trx_record_enable_all_tracks ()
1979 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1980 bool none_record_enabled = true;
1982 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1983 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1986 if (t->record_enabled()) {
1987 none_record_enabled = false;
1992 if (none_record_enabled) {
1993 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1996 return none_record_enabled;
2000 ARDOUR_UI::transport_record (bool roll)
2003 switch (_session->record_status()) {
2004 case Session::Disabled:
2005 if (_session->ntracks() == 0) {
2006 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."));
2010 if (Profile->get_trx()) {
2011 roll = trx_record_enable_all_tracks ();
2013 _session->maybe_enable_record ();
2018 case Session::Recording:
2020 _session->request_stop();
2022 _session->disable_record (false, true);
2026 case Session::Enabled:
2027 _session->disable_record (false, true);
2033 ARDOUR_UI::transport_roll ()
2039 if (_session->is_auditioning()) {
2044 if (_session->config.get_external_sync()) {
2045 switch (Config->get_sync_source()) {
2049 /* transport controlled by the master */
2055 bool rolling = _session->transport_rolling();
2057 if (_session->get_play_loop()) {
2059 /* If loop playback is not a mode, then we should cancel
2060 it when this action is requested. If it is a mode
2061 we just leave it in place.
2064 if (!Config->get_loop_is_mode()) {
2065 /* XXX it is not possible to just leave seamless loop and keep
2066 playing at present (nov 4th 2009)
2068 if (!Config->get_seamless_loop()) {
2069 /* stop loop playback and stop rolling */
2070 _session->request_play_loop (false, true);
2071 } else if (rolling) {
2072 /* stop loop playback but keep rolling */
2073 _session->request_play_loop (false, false);
2077 } else if (_session->get_play_range () ) {
2078 /* stop playing a range if we currently are */
2079 _session->request_play_range (0, true);
2083 _session->request_transport_speed (1.0f);
2088 ARDOUR_UI::get_smart_mode() const
2090 return ( editor->get_smart_mode() );
2095 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2101 if (_session->is_auditioning()) {
2102 _session->cancel_audition ();
2106 if (_session->config.get_external_sync()) {
2107 switch (Config->get_sync_source()) {
2111 /* transport controlled by the master */
2116 bool rolling = _session->transport_rolling();
2117 bool affect_transport = true;
2119 if (rolling && roll_out_of_bounded_mode) {
2120 /* drop out of loop/range playback but leave transport rolling */
2121 if (_session->get_play_loop()) {
2122 if (_session->actively_recording()) {
2124 /* just stop using the loop, then actually stop
2127 _session->request_play_loop (false, affect_transport);
2130 if (Config->get_seamless_loop()) {
2131 /* the disk buffers contain copies of the loop - we can't
2132 just keep playing, so stop the transport. the user
2133 can restart as they wish.
2135 affect_transport = true;
2137 /* disk buffers are normal, so we can keep playing */
2138 affect_transport = false;
2140 _session->request_play_loop (false, affect_transport);
2142 } else if (_session->get_play_range ()) {
2143 affect_transport = false;
2144 _session->request_play_range (0, true);
2148 if (affect_transport) {
2150 _session->request_stop (with_abort, true);
2152 /* the only external sync condition we can be in here
2153 * would be Engine (JACK) sync, in which case we still
2157 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
2158 _session->request_play_range (&editor->get_selection().time, true);
2159 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2161 _session->request_transport_speed (1.0f);
2167 ARDOUR_UI::toggle_session_auto_loop ()
2173 Location * looploc = _session->locations()->auto_loop_location();
2179 if (_session->get_play_loop()) {
2181 /* looping enabled, our job is to disable it */
2183 _session->request_play_loop (false);
2187 /* looping not enabled, our job is to enable it.
2189 loop-is-NOT-mode: this action always starts the transport rolling.
2190 loop-IS-mode: this action simply sets the loop play mechanism, but
2191 does not start transport.
2193 if (Config->get_loop_is_mode()) {
2194 _session->request_play_loop (true, false);
2196 _session->request_play_loop (true, true);
2200 //show the loop markers
2201 looploc->set_hidden (false, this);
2205 ARDOUR_UI::transport_play_selection ()
2211 editor->play_selection ();
2215 ARDOUR_UI::transport_play_preroll ()
2220 editor->play_with_preroll ();
2224 ARDOUR_UI::transport_rewind (int option)
2226 float current_transport_speed;
2229 current_transport_speed = _session->transport_speed();
2231 if (current_transport_speed >= 0.0f) {
2234 _session->request_transport_speed (-1.0f);
2237 _session->request_transport_speed (-4.0f);
2240 _session->request_transport_speed (-0.5f);
2245 _session->request_transport_speed (current_transport_speed * 1.5f);
2251 ARDOUR_UI::transport_forward (int option)
2257 float current_transport_speed = _session->transport_speed();
2259 if (current_transport_speed <= 0.0f) {
2262 _session->request_transport_speed (1.0f);
2265 _session->request_transport_speed (4.0f);
2268 _session->request_transport_speed (0.5f);
2273 _session->request_transport_speed (current_transport_speed * 1.5f);
2278 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2284 boost::shared_ptr<Route> r;
2286 if ((r = _session->route_by_remote_id (rid)) != 0) {
2288 boost::shared_ptr<Track> t;
2290 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2291 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2297 ARDOUR_UI::map_transport_state ()
2300 auto_loop_button.unset_active_state ();
2301 play_selection_button.unset_active_state ();
2302 roll_button.unset_active_state ();
2303 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2307 shuttle_box->map_transport_state ();
2309 float sp = _session->transport_speed();
2315 if (_session->get_play_range()) {
2317 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2318 roll_button.unset_active_state ();
2319 auto_loop_button.unset_active_state ();
2321 } else if (_session->get_play_loop ()) {
2323 auto_loop_button.set_active (true);
2324 play_selection_button.set_active (false);
2325 if (Config->get_loop_is_mode()) {
2326 roll_button.set_active (true);
2328 roll_button.set_active (false);
2333 roll_button.set_active (true);
2334 play_selection_button.set_active (false);
2335 auto_loop_button.set_active (false);
2338 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2339 /* light up both roll and play-selection if they are joined */
2340 roll_button.set_active (true);
2341 play_selection_button.set_active (true);
2344 stop_button.set_active (false);
2348 stop_button.set_active (true);
2349 roll_button.set_active (false);
2350 play_selection_button.set_active (false);
2351 if (Config->get_loop_is_mode ()) {
2352 auto_loop_button.set_active (_session->get_play_loop());
2354 auto_loop_button.set_active (false);
2356 update_disk_space ();
2361 ARDOUR_UI::blink_handler (bool blink_on)
2363 transport_rec_enable_blink (blink_on);
2364 solo_blink (blink_on);
2365 sync_blink (blink_on);
2366 audition_blink (blink_on);
2367 feedback_blink (blink_on);
2368 error_blink (blink_on);
2372 ARDOUR_UI::update_clocks ()
2374 if (!_session) return;
2376 if (editor && !editor->dragging_playhead()) {
2377 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2382 ARDOUR_UI::start_clocking ()
2384 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2385 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2387 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2392 ARDOUR_UI::stop_clocking ()
2394 clock_signal_connection.disconnect ();
2398 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2402 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2404 label->set_text (buf);
2405 bar->set_fraction (fraction);
2407 /* process events, redraws, etc. */
2409 while (gtk_events_pending()) {
2410 gtk_main_iteration ();
2413 return true; /* continue with save-as */
2417 ARDOUR_UI::save_session_as ()
2423 if (!save_as_dialog) {
2424 save_as_dialog = new SaveAsDialog;
2427 save_as_dialog->set_name (_session->name());
2429 int response = save_as_dialog->run ();
2431 save_as_dialog->hide ();
2434 case Gtk::RESPONSE_OK:
2443 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2444 sa.new_name = save_as_dialog->new_name ();
2445 sa.switch_to = save_as_dialog->switch_to();
2446 sa.copy_media = save_as_dialog->copy_media();
2447 sa.copy_external = save_as_dialog->copy_external();
2448 sa.include_media = save_as_dialog->include_media ();
2450 /* Only bother with a progress dialog if we're going to copy
2451 media into the save-as target. Without that choice, this
2452 will be very fast because we're only talking about a few kB's to
2453 perhaps a couple of MB's of data.
2456 ArdourDialog progress_dialog (_("Save As"), true);
2458 if (sa.include_media && sa.copy_media) {
2461 Gtk::ProgressBar progress_bar;
2463 progress_dialog.get_vbox()->pack_start (label);
2464 progress_dialog.get_vbox()->pack_start (progress_bar);
2466 progress_bar.show ();
2468 /* this signal will be emitted from within this, the calling thread,
2469 * after every file is copied. It provides information on percentage
2470 * complete (in terms of total data to copy), the number of files
2471 * copied so far, and the total number to copy.
2476 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2478 progress_dialog.show_all ();
2479 progress_dialog.present ();
2482 if (_session->save_as (sa)) {
2484 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2488 if (!sa.include_media) {
2489 unload_session (false);
2490 load_session (sa.final_session_folder_name, sa.new_name);
2495 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2499 struct tm local_time;
2502 localtime_r (&n, &local_time);
2503 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2505 save_state (timebuf, switch_to_it);
2510 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2514 prompter.get_result (snapname);
2516 bool do_save = (snapname.length() != 0);
2519 char illegal = Session::session_name_is_legal(snapname);
2521 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2522 "snapshot names may not contain a '%1' character"), illegal));
2528 vector<std::string> p;
2529 get_state_files_in_directory (_session->session_directory().root_path(), p);
2530 vector<string> n = get_file_names_no_extension (p);
2532 if (find (n.begin(), n.end(), snapname) != n.end()) {
2534 do_save = overwrite_file_dialog (prompter,
2535 _("Confirm Snapshot Overwrite"),
2536 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2540 save_state (snapname, switch_to_it);
2550 /** Ask the user for the name of a new snapshot and then take it.
2554 ARDOUR_UI::snapshot_session (bool switch_to_it)
2556 ArdourPrompter prompter (true);
2558 prompter.set_name ("Prompter");
2559 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2561 prompter.set_title (_("Save as..."));
2562 prompter.set_prompt (_("New session name"));
2564 prompter.set_title (_("Take Snapshot"));
2565 prompter.set_prompt (_("Name of new snapshot"));
2569 prompter.set_initial_text (_session->snap_name());
2573 struct tm local_time;
2576 localtime_r (&n, &local_time);
2577 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2578 prompter.set_initial_text (timebuf);
2581 bool finished = false;
2583 switch (prompter.run()) {
2584 case RESPONSE_ACCEPT:
2586 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2597 /** Ask the user for a new session name and then rename the session to it.
2601 ARDOUR_UI::rename_session ()
2607 ArdourPrompter prompter (true);
2610 prompter.set_name ("Prompter");
2611 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2612 prompter.set_title (_("Rename Session"));
2613 prompter.set_prompt (_("New session name"));
2616 switch (prompter.run()) {
2617 case RESPONSE_ACCEPT:
2619 prompter.get_result (name);
2621 bool do_rename = (name.length() != 0);
2624 char illegal = Session::session_name_is_legal (name);
2627 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2628 "session names may not contain a '%1' character"), illegal));
2633 switch (_session->rename (name)) {
2635 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2636 msg.set_position (WIN_POS_MOUSE);
2644 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2645 msg.set_position (WIN_POS_MOUSE);
2661 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2663 if (!_session || _session->deletion_in_progress()) {
2667 XMLNode* node = new XMLNode (X_("UI"));
2669 WM::Manager::instance().add_state (*node);
2671 node->add_child_nocopy (gui_object_state->get_state());
2673 _session->add_extra_xml (*node);
2675 if (export_video_dialog) {
2676 _session->add_extra_xml (export_video_dialog->get_state());
2679 save_state_canfail (name, switch_to_it);
2683 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2688 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2693 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2698 ARDOUR_UI::primary_clock_value_changed ()
2701 _session->request_locate (primary_clock->current_time ());
2706 ARDOUR_UI::big_clock_value_changed ()
2709 _session->request_locate (big_clock->current_time ());
2714 ARDOUR_UI::secondary_clock_value_changed ()
2717 _session->request_locate (secondary_clock->current_time ());
2722 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2724 if (_session == 0) {
2728 if (_session->step_editing()) {
2732 Session::RecordState const r = _session->record_status ();
2733 bool const h = _session->have_rec_enabled_track ();
2735 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2737 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2739 rec_button.set_active_state (Gtkmm2ext::Off);
2741 } else if (r == Session::Recording && h) {
2742 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2744 rec_button.unset_active_state ();
2749 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2753 prompter.get_result (name);
2755 if (name.length()) {
2756 int failed = _session->save_template (name);
2758 if (failed == -2) { /* file already exists. */
2759 bool overwrite = overwrite_file_dialog (prompter,
2760 _("Confirm Template Overwrite"),
2761 _("A template already exists with that name. Do you want to overwrite it?"));
2764 _session->save_template (name, true);
2776 ARDOUR_UI::save_template ()
2778 ArdourPrompter prompter (true);
2780 if (!check_audioengine (_main_window)) {
2784 prompter.set_name (X_("Prompter"));
2785 prompter.set_title (_("Save Template"));
2786 prompter.set_prompt (_("Name for template:"));
2787 prompter.set_initial_text(_session->name() + _("-template"));
2788 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2790 bool finished = false;
2792 switch (prompter.run()) {
2793 case RESPONSE_ACCEPT:
2794 finished = process_save_template_prompter (prompter);
2805 ARDOUR_UI::edit_metadata ()
2807 SessionMetadataEditor dialog;
2808 dialog.set_session (_session);
2809 dialog.grab_focus ();
2814 ARDOUR_UI::import_metadata ()
2816 SessionMetadataImporter dialog;
2817 dialog.set_session (_session);
2822 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2824 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2826 MessageDialog msg (str,
2828 Gtk::MESSAGE_WARNING,
2829 Gtk::BUTTONS_YES_NO,
2833 msg.set_name (X_("OpenExistingDialog"));
2834 msg.set_title (_("Open Existing Session"));
2835 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2836 msg.set_position (Gtk::WIN_POS_CENTER);
2837 pop_back_splash (msg);
2839 switch (msg.run()) {
2848 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2850 BusProfile bus_profile;
2854 bus_profile.master_out_channels = 2;
2855 bus_profile.input_ac = AutoConnectPhysical;
2856 bus_profile.output_ac = AutoConnectMaster;
2857 bus_profile.requested_physical_in = 0; // use all available
2858 bus_profile.requested_physical_out = 0; // use all available
2862 /* get settings from advanced section of NSD */
2864 if (sd.create_master_bus()) {
2865 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2867 bus_profile.master_out_channels = 0;
2870 if (sd.connect_inputs()) {
2871 bus_profile.input_ac = AutoConnectPhysical;
2873 bus_profile.input_ac = AutoConnectOption (0);
2876 bus_profile.output_ac = AutoConnectOption (0);
2878 if (sd.connect_outputs ()) {
2879 if (sd.connect_outs_to_master()) {
2880 bus_profile.output_ac = AutoConnectMaster;
2881 } else if (sd.connect_outs_to_physical()) {
2882 bus_profile.output_ac = AutoConnectPhysical;
2886 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2887 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2890 if (build_session (session_path, session_name, bus_profile)) {
2898 ARDOUR_UI::load_from_application_api (const std::string& path)
2900 ARDOUR_COMMAND_LINE::session_name = path;
2901 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2903 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2905 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2906 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2907 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2908 * -> SessionDialog is not displayed
2911 if (_session_dialog) {
2912 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2913 std::string session_path = path;
2914 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2915 session_path = Glib::path_get_dirname (session_path);
2917 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2918 _session_dialog->set_provided_session (session_name, session_path);
2919 _session_dialog->response (RESPONSE_NONE);
2920 _session_dialog->hide();
2925 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2926 /* /path/to/foo => /path/to/foo, foo */
2927 rv = load_session (path, basename_nosuffix (path));
2929 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2930 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2933 // if load_session fails -> pop up SessionDialog.
2935 ARDOUR_COMMAND_LINE::session_name = "";
2937 if (get_session_parameters (true, false)) {
2943 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2945 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2947 string session_name;
2948 string session_path;
2949 string template_name;
2951 bool likely_new = false;
2952 bool cancel_not_quit;
2954 /* deal with any existing DIRTY session now, rather than later. don't
2955 * treat a non-dirty session this way, so that it stays visible
2956 * as we bring up the new session dialog.
2959 if (_session && ARDOUR_UI::instance()->video_timeline) {
2960 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2963 /* if there is already a session, relabel the button
2964 on the SessionDialog so that we don't Quit directly
2966 cancel_not_quit = (_session != 0);
2968 if (_session && _session->dirty()) {
2969 if (unload_session (false)) {
2970 /* unload cancelled by user */
2973 ARDOUR_COMMAND_LINE::session_name = "";
2976 if (!load_template.empty()) {
2977 should_be_new = true;
2978 template_name = load_template;
2981 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2982 session_path = ARDOUR_COMMAND_LINE::session_name;
2984 if (!session_path.empty()) {
2985 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2986 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2987 /* session/snapshot file, change path to be dir */
2988 session_path = Glib::path_get_dirname (session_path);
2993 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2995 _session_dialog = &session_dialog;
2998 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3000 /* if they named a specific statefile, use it, otherwise they are
3001 just giving a session folder, and we want to use it as is
3002 to find the session.
3005 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3007 if (suffix != string::npos) {
3008 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3009 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3010 session_name = Glib::path_get_basename (session_name);
3012 session_path = ARDOUR_COMMAND_LINE::session_name;
3013 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3018 session_dialog.clear_given ();
3021 if (should_be_new || session_name.empty()) {
3022 /* need the dialog to get info from user */
3024 cerr << "run dialog\n";
3026 switch (session_dialog.run()) {
3027 case RESPONSE_ACCEPT:
3030 /* this is used for async * app->ShouldLoad(). */
3031 continue; // while loop
3034 if (quit_on_cancel) {
3035 // JE - Currently (July 2014) this section can only get reached if the
3036 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3037 // point does NOT indicate an abnormal termination). Therefore, let's
3038 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3040 pthread_cancel_all ();
3048 session_dialog.hide ();
3051 /* if we run the startup dialog again, offer more than just "new session" */
3053 should_be_new = false;
3055 session_name = session_dialog.session_name (likely_new);
3056 session_path = session_dialog.session_folder ();
3062 string::size_type suffix = session_name.find (statefile_suffix);
3064 if (suffix != string::npos) {
3065 session_name = session_name.substr (0, suffix);
3068 /* this shouldn't happen, but we catch it just in case it does */
3070 if (session_name.empty()) {
3074 if (session_dialog.use_session_template()) {
3075 template_name = session_dialog.session_template_name();
3076 _session_is_new = true;
3079 if (session_name[0] == G_DIR_SEPARATOR ||
3080 #ifdef PLATFORM_WINDOWS
3081 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3083 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3084 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3089 /* absolute path or cwd-relative path specified for session name: infer session folder
3090 from what was given.
3093 session_path = Glib::path_get_dirname (session_name);
3094 session_name = Glib::path_get_basename (session_name);
3098 session_path = session_dialog.session_folder();
3100 char illegal = Session::session_name_is_legal (session_name);
3103 MessageDialog msg (session_dialog,
3104 string_compose (_("To ensure compatibility with various systems\n"
3105 "session names may not contain a '%1' character"),
3108 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3113 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3116 if (likely_new && !nsm) {
3118 std::string existing = Glib::build_filename (session_path, session_name);
3120 if (!ask_about_loading_existing_session (existing)) {
3121 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3126 _session_is_new = false;
3131 pop_back_splash (session_dialog);
3132 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3134 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3138 char illegal = Session::session_name_is_legal(session_name);
3141 pop_back_splash (session_dialog);
3142 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3143 "session names may not contain a '%1' character"), illegal));
3145 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3149 _session_is_new = true;
3152 if (likely_new && template_name.empty()) {
3154 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3158 ret = load_session (session_path, session_name, template_name);
3161 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3165 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3166 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3170 /* clear this to avoid endless attempts to load the
3174 ARDOUR_COMMAND_LINE::session_name = "";
3178 _session_dialog = NULL;
3184 ARDOUR_UI::close_session()
3186 if (!check_audioengine (_main_window)) {
3190 if (unload_session (true)) {
3194 ARDOUR_COMMAND_LINE::session_name = "";
3196 if (get_session_parameters (true, false)) {
3201 /** @param snap_name Snapshot name (without .ardour suffix).
3202 * @return -2 if the load failed because we are not connected to the AudioEngine.
3205 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3207 Session *new_session;
3212 unload_status = unload_session ();
3214 if (unload_status < 0) {
3216 } else if (unload_status > 0) {
3222 session_loaded = false;
3224 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3227 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3230 /* this one is special */
3232 catch (AudioEngine::PortRegistrationFailure& err) {
3234 MessageDialog msg (err.what(),
3237 Gtk::BUTTONS_CLOSE);
3239 msg.set_title (_("Port Registration Error"));
3240 msg.set_secondary_text (_("Click the Close button to try again."));
3241 msg.set_position (Gtk::WIN_POS_CENTER);
3242 pop_back_splash (msg);
3245 int response = msg.run ();
3250 case RESPONSE_CANCEL:
3257 catch (SessionException e) {
3258 MessageDialog msg (string_compose(
3259 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3260 path, snap_name, e.what()),
3265 msg.set_title (_("Loading Error"));
3266 msg.set_position (Gtk::WIN_POS_CENTER);
3267 pop_back_splash (msg);
3279 MessageDialog msg (string_compose(
3280 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3286 msg.set_title (_("Loading Error"));
3287 msg.set_position (Gtk::WIN_POS_CENTER);
3288 pop_back_splash (msg);
3300 list<string> const u = new_session->unknown_processors ();
3302 MissingPluginDialog d (_session, u);
3307 if (!new_session->writable()) {
3308 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3313 msg.set_title (_("Read-only Session"));
3314 msg.set_position (Gtk::WIN_POS_CENTER);
3315 pop_back_splash (msg);
3322 /* Now the session been created, add the transport controls */
3323 new_session->add_controllable(roll_controllable);
3324 new_session->add_controllable(stop_controllable);
3325 new_session->add_controllable(goto_start_controllable);
3326 new_session->add_controllable(goto_end_controllable);
3327 new_session->add_controllable(auto_loop_controllable);
3328 new_session->add_controllable(play_selection_controllable);
3329 new_session->add_controllable(rec_controllable);
3331 set_session (new_session);
3333 session_loaded = true;
3336 _session->set_clean ();
3339 #ifdef WINDOWS_VST_SUPPORT
3340 fst_stop_threading();
3344 Timers::TimerSuspender t;
3348 #ifdef WINDOWS_VST_SUPPORT
3349 fst_start_threading();
3358 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3360 Session *new_session;
3363 session_loaded = false;
3364 x = unload_session ();
3372 _session_is_new = true;
3375 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3378 catch (SessionException e) {
3380 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3381 msg.set_title (_("Loading Error"));
3382 msg.set_position (Gtk::WIN_POS_CENTER);
3383 pop_back_splash (msg);
3389 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3390 msg.set_title (_("Loading Error"));
3391 msg.set_position (Gtk::WIN_POS_CENTER);
3392 pop_back_splash (msg);
3397 /* Give the new session the default GUI state, if such things exist */
3400 n = Config->instant_xml (X_("Editor"));
3402 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3403 new_session->add_instant_xml (*n, false);
3405 n = Config->instant_xml (X_("Mixer"));
3407 new_session->add_instant_xml (*n, false);
3410 /* Put the playhead at 0 and scroll fully left */
3411 n = new_session->instant_xml (X_("Editor"));
3413 n->add_property (X_("playhead"), X_("0"));
3414 n->add_property (X_("left-frame"), X_("0"));
3417 set_session (new_session);
3419 session_loaded = true;
3421 new_session->save_state(new_session->name());
3427 ARDOUR_UI::launch_chat ()
3429 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3431 dialog.set_title (_("About the Chat"));
3432 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."));
3434 switch (dialog.run()) {
3437 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3438 #elif defined PLATFORM_WINDOWS
3439 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3441 open_uri("http://webchat.freenode.net/?channels=ardour");
3450 ARDOUR_UI::launch_manual ()
3452 PBD::open_uri (Config->get_tutorial_manual_url());
3456 ARDOUR_UI::launch_reference ()
3458 PBD::open_uri (Config->get_reference_manual_url());
3462 ARDOUR_UI::launch_tracker ()
3464 PBD::open_uri ("http://tracker.ardour.org");
3468 ARDOUR_UI::launch_subscribe ()
3470 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3474 ARDOUR_UI::launch_cheat_sheet ()
3477 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3479 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3484 ARDOUR_UI::launch_website ()
3486 PBD::open_uri ("http://ardour.org");
3490 ARDOUR_UI::launch_website_dev ()
3492 PBD::open_uri ("http://ardour.org/development.html");
3496 ARDOUR_UI::launch_forums ()
3498 PBD::open_uri ("https://community.ardour.org/forums");
3502 ARDOUR_UI::launch_howto_report ()
3504 PBD::open_uri ("http://ardour.org/reporting_bugs");
3508 ARDOUR_UI::loading_message (const std::string& msg)
3510 if (ARDOUR_COMMAND_LINE::no_splash) {
3518 splash->message (msg);
3522 ARDOUR_UI::show_splash ()
3526 splash = new Splash;
3536 ARDOUR_UI::hide_splash ()
3543 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3547 removed = rep.paths.size();
3550 MessageDialog msgd (_main_window,
3551 _("No files were ready for clean-up"),
3555 msgd.set_title (_("Clean-up"));
3556 msgd.set_secondary_text (_("If this seems suprising, \n\
3557 check for any existing snapshots.\n\
3558 These may still include regions that\n\
3559 require some unused files to continue to exist."));
3565 ArdourDialog results (_("Clean-up"), true, false);
3567 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3568 CleanupResultsModelColumns() {
3572 Gtk::TreeModelColumn<std::string> visible_name;
3573 Gtk::TreeModelColumn<std::string> fullpath;
3577 CleanupResultsModelColumns results_columns;
3578 Glib::RefPtr<Gtk::ListStore> results_model;
3579 Gtk::TreeView results_display;
3581 results_model = ListStore::create (results_columns);
3582 results_display.set_model (results_model);
3583 results_display.append_column (list_title, results_columns.visible_name);
3585 results_display.set_name ("CleanupResultsList");
3586 results_display.set_headers_visible (true);
3587 results_display.set_headers_clickable (false);
3588 results_display.set_reorderable (false);
3590 Gtk::ScrolledWindow list_scroller;
3593 Gtk::HBox dhbox; // the hbox for the image and text
3594 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3595 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3597 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3599 const string dead_directory = _session->session_directory().dead_path();
3602 %1 - number of files removed
3603 %2 - location of "dead"
3604 %3 - size of files affected
3605 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3608 const char* bprefix;
3609 double space_adjusted = 0;
3611 if (rep.space < 1000) {
3613 space_adjusted = rep.space;
3614 } else if (rep.space < 1000000) {
3615 bprefix = _("kilo");
3616 space_adjusted = floorf((float)rep.space / 1000.0);
3617 } else if (rep.space < 1000000 * 1000) {
3618 bprefix = _("mega");
3619 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3621 bprefix = _("giga");
3622 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3626 txt.set_markup (string_compose (P_("\
3627 The following file was deleted from %2,\n\
3628 releasing %3 %4bytes of disk space", "\
3629 The following %1 files were deleted from %2,\n\
3630 releasing %3 %4bytes of disk space", removed),
3631 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3633 txt.set_markup (string_compose (P_("\
3634 The following file was not in use and \n\
3635 has been moved to: %2\n\n\
3636 After a restart of %5\n\n\
3637 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3638 will release an additional %3 %4bytes of disk space.\n", "\
3639 The following %1 files were not in use and \n\
3640 have been moved to: %2\n\n\
3641 After a restart of %5\n\n\
3642 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3643 will release an additional %3 %4bytes of disk space.\n", removed),
3644 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3647 dhbox.pack_start (*dimage, true, false, 5);
3648 dhbox.pack_start (txt, true, false, 5);
3650 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3651 TreeModel::Row row = *(results_model->append());
3652 row[results_columns.visible_name] = *i;
3653 row[results_columns.fullpath] = *i;
3656 list_scroller.add (results_display);
3657 list_scroller.set_size_request (-1, 150);
3658 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3660 dvbox.pack_start (dhbox, true, false, 5);
3661 dvbox.pack_start (list_scroller, true, false, 5);
3662 ddhbox.pack_start (dvbox, true, false, 5);
3664 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3665 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3666 results.set_default_response (RESPONSE_CLOSE);
3667 results.set_position (Gtk::WIN_POS_MOUSE);
3669 results_display.show();
3670 list_scroller.show();
3677 //results.get_vbox()->show();
3678 results.set_resizable (false);
3685 ARDOUR_UI::cleanup ()
3687 if (_session == 0) {
3688 /* shouldn't happen: menu item is insensitive */
3693 MessageDialog checker (_("Are you sure you want to clean-up?"),
3695 Gtk::MESSAGE_QUESTION,
3698 checker.set_title (_("Clean-up"));
3700 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3701 ALL undo/redo information will be lost if you clean-up.\n\
3702 Clean-up will move all unused files to a \"dead\" location."));
3704 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3705 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3706 checker.set_default_response (RESPONSE_CANCEL);
3708 checker.set_name (_("CleanupDialog"));
3709 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3710 checker.set_position (Gtk::WIN_POS_MOUSE);
3712 switch (checker.run()) {
3713 case RESPONSE_ACCEPT:
3719 ARDOUR::CleanupReport rep;
3721 editor->prepare_for_cleanup ();
3723 /* do not allow flush until a session is reloaded */
3725 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3727 act->set_sensitive (false);
3730 if (_session->cleanup_sources (rep)) {
3731 editor->finish_cleanup ();
3735 editor->finish_cleanup ();
3738 display_cleanup_results (rep, _("Cleaned Files"), false);
3742 ARDOUR_UI::flush_trash ()
3744 if (_session == 0) {
3745 /* shouldn't happen: menu item is insensitive */
3749 ARDOUR::CleanupReport rep;
3751 if (_session->cleanup_trash_sources (rep)) {
3755 display_cleanup_results (rep, _("deleted file"), true);
3759 ARDOUR_UI::cleanup_peakfiles ()
3761 if (_session == 0) {
3762 /* shouldn't happen: menu item is insensitive */
3766 if (! _session->can_cleanup_peakfiles ()) {
3770 // get all region-views in this session
3772 TrackViewList empty;
3774 editor->get_regions_after(rs, (framepos_t) 0, empty);
3775 std::list<RegionView*> views = rs.by_layer();
3777 // remove displayed audio-region-views waveforms
3778 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3779 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3780 if (!arv) { continue ; }
3781 arv->delete_waves();
3784 // cleanup peak files:
3785 // - stop pending peakfile threads
3786 // - close peakfiles if any
3787 // - remove peak dir in session
3788 // - setup peakfiles (background thread)
3789 _session->cleanup_peakfiles ();
3791 // re-add waves to ARV
3792 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3793 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3794 if (!arv) { continue ; }
3795 arv->create_waves();
3800 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3802 uint32_t order_hint = UINT32_MAX;
3804 if (editor->get_selection().tracks.empty()) {
3809 we want the new routes to have their order keys set starting from
3810 the highest order key in the selection + 1 (if available).
3813 if (place == AddRouteDialog::AfterSelection) {
3814 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3816 order_hint = rtav->route()->order_key();
3819 } else if (place == AddRouteDialog::BeforeSelection) {
3820 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3822 order_hint = rtav->route()->order_key();
3824 } else if (place == AddRouteDialog::First) {
3827 /* leave order_hint at UINT32_MAX */
3830 if (order_hint == UINT32_MAX) {
3831 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3832 * not setting an order hint will place new routes last.
3837 _session->set_order_hint (order_hint);
3839 /* create a gap in the existing route order keys to accomodate new routes.*/
3840 boost::shared_ptr <RouteList> rd = _session->get_routes();
3841 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3842 boost::shared_ptr<Route> rt (*ri);
3844 if (rt->is_monitor()) {
3848 if (rt->order_key () >= order_hint) {
3849 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3855 ARDOUR_UI::start_duplicate_routes ()
3857 if (!duplicate_routes_dialog) {
3858 duplicate_routes_dialog = new DuplicateRouteDialog;
3861 if (duplicate_routes_dialog->restart (_session)) {
3865 duplicate_routes_dialog->present ();
3869 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3877 if (add_route_dialog->is_visible()) {
3878 /* we're already doing this */
3882 ResponseType r = (ResponseType) add_route_dialog->run ();
3884 add_route_dialog->hide();
3887 case RESPONSE_ACCEPT:
3894 if ((count = add_route_dialog->count()) <= 0) {
3898 setup_order_hint(add_route_dialog->insert_at());
3900 string template_path = add_route_dialog->track_template();
3901 DisplaySuspender ds;
3903 if (!template_path.empty()) {
3904 if (add_route_dialog->name_template_is_default()) {
3905 _session->new_route_from_template (count, template_path, string());
3907 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3912 ChanCount input_chan= add_route_dialog->channels ();
3913 ChanCount output_chan;
3914 string name_template = add_route_dialog->name_template ();
3915 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3916 RouteGroup* route_group = add_route_dialog->route_group ();
3917 AutoConnectOption oac = Config->get_output_auto_connect();
3919 if (oac & AutoConnectMaster) {
3920 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3921 output_chan.set (DataType::MIDI, 0);
3923 output_chan = input_chan;
3926 /* XXX do something with name template */
3928 switch (add_route_dialog->type_wanted()) {
3929 case AddRouteDialog::AudioTrack:
3930 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3932 case AddRouteDialog::MidiTrack:
3933 session_add_midi_track (route_group, count, name_template, instrument);
3935 case AddRouteDialog::MixedTrack:
3936 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3938 case AddRouteDialog::AudioBus:
3939 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3945 ARDOUR_UI::add_lua_script ()
3951 LuaScriptInfoPtr spi;
3952 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
3953 switch (ss.run ()) {
3954 case Gtk::RESPONSE_ACCEPT:
3961 std::string script = "";
3964 script = Glib::file_get_contents (spi->path);
3965 } catch (Glib::FileError e) {
3966 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
3967 MessageDialog am (msg);
3972 LuaScriptParamList lsp = LuaScripting::session_script_params (spi);
3973 std::vector<std::string> reg = _session->registered_lua_functions ();
3975 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
3976 switch (spd.run ()) {
3977 case Gtk::RESPONSE_ACCEPT:
3984 _session->register_lua_function (spd.name(), script, lsp);
3985 } catch (luabridge::LuaException const& e) {
3986 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
3987 MessageDialog am (msg);
3989 } catch (SessionException e) {
3990 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
3991 MessageDialog am (msg);
3997 ARDOUR_UI::remove_lua_script ()
4002 if (_session->registered_lua_function_count () == 0) {
4003 string msg = _("There are no active Lua session scripts present in this session.");
4004 MessageDialog am (msg);
4009 std::vector<std::string> reg = _session->registered_lua_functions ();
4010 SessionScriptManager sm ("Remove Lua Session Script", reg);
4011 switch (sm.run ()) {
4012 case Gtk::RESPONSE_ACCEPT:
4018 _session->unregister_lua_function (sm.name());
4019 } catch (luabridge::LuaException const& e) {
4020 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4021 MessageDialog am (msg);
4027 ARDOUR_UI::stop_video_server (bool ask_confirm)
4029 if (!video_server_process && ask_confirm) {
4030 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4032 if (video_server_process) {
4034 ArdourDialog confirm (_("Stop Video-Server"), true);
4035 Label m (_("Do you really want to stop the Video Server?"));
4036 confirm.get_vbox()->pack_start (m, true, true);
4037 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4038 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4039 confirm.show_all ();
4040 if (confirm.run() == RESPONSE_CANCEL) {
4044 delete video_server_process;
4045 video_server_process =0;
4050 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4052 ARDOUR_UI::start_video_server( float_window, true);
4056 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4062 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4063 if (video_server_process) {
4064 popup_error(_("The Video Server is already started."));
4066 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4072 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4074 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4076 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4078 video_server_dialog->set_transient_for (*float_window);
4081 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4082 video_server_dialog->hide();
4084 ResponseType r = (ResponseType) video_server_dialog->run ();
4085 video_server_dialog->hide();
4086 if (r != RESPONSE_ACCEPT) { return false; }
4087 if (video_server_dialog->show_again()) {
4088 Config->set_show_video_server_dialog(false);
4092 std::string icsd_exec = video_server_dialog->get_exec_path();
4093 std::string icsd_docroot = video_server_dialog->get_docroot();
4094 if (icsd_docroot.empty()) {
4095 #ifndef PLATFORM_WINDOWS
4096 icsd_docroot = X_("/");
4098 icsd_docroot = X_("C:\\");
4103 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4104 warning << _("Specified docroot is not an existing directory.") << endmsg;
4107 #ifndef PLATFORM_WINDOWS
4108 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4109 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4110 warning << _("Given Video Server is not an executable file.") << endmsg;
4114 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4115 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4116 warning << _("Given Video Server is not an executable file.") << endmsg;
4122 argp=(char**) calloc(9,sizeof(char*));
4123 argp[0] = strdup(icsd_exec.c_str());
4124 argp[1] = strdup("-P");
4125 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4126 argp[3] = strdup("-p");
4127 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4128 argp[5] = strdup("-C");
4129 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4130 argp[7] = strdup(icsd_docroot.c_str());
4132 stop_video_server();
4134 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4135 Config->set_video_advanced_setup(false);
4137 std::ostringstream osstream;
4138 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4139 Config->set_video_server_url(osstream.str());
4140 Config->set_video_server_docroot(icsd_docroot);
4141 Config->set_video_advanced_setup(true);
4144 if (video_server_process) {
4145 delete video_server_process;
4148 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4149 if (video_server_process->start()) {
4150 warning << _("Cannot launch the video-server") << endmsg;
4153 int timeout = 120; // 6 sec
4154 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4155 Glib::usleep (50000);
4157 if (--timeout <= 0 || !video_server_process->is_running()) break;
4160 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4162 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4163 delete video_server_process;
4164 video_server_process = 0;
4172 ARDOUR_UI::add_video (Gtk::Window* float_window)
4178 if (!start_video_server(float_window, false)) {
4179 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4184 add_video_dialog->set_transient_for (*float_window);
4187 if (add_video_dialog->is_visible()) {
4188 /* we're already doing this */
4192 ResponseType r = (ResponseType) add_video_dialog->run ();
4193 add_video_dialog->hide();
4194 if (r != RESPONSE_ACCEPT) { return; }
4196 bool local_file, orig_local_file;
4197 std::string path = add_video_dialog->file_name(local_file);
4199 std::string orig_path = path;
4200 orig_local_file = local_file;
4202 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4204 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4205 warning << string_compose(_("could not open %1"), path) << endmsg;
4208 if (!local_file && path.length() == 0) {
4209 warning << _("no video-file selected") << endmsg;
4213 std::string audio_from_video;
4214 bool detect_ltc = false;
4216 switch (add_video_dialog->import_option()) {
4217 case VTL_IMPORT_TRANSCODE:
4219 TranscodeVideoDialog *transcode_video_dialog;
4220 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4221 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4222 transcode_video_dialog->hide();
4223 if (r != RESPONSE_ACCEPT) {
4224 delete transcode_video_dialog;
4228 audio_from_video = transcode_video_dialog->get_audiofile();
4230 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4233 else if (!audio_from_video.empty()) {
4234 editor->embed_audio_from_video(
4236 video_timeline->get_offset(),
4237 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4240 switch (transcode_video_dialog->import_option()) {
4241 case VTL_IMPORT_TRANSCODED:
4242 path = transcode_video_dialog->get_filename();
4245 case VTL_IMPORT_REFERENCE:
4248 delete transcode_video_dialog;
4251 delete transcode_video_dialog;
4255 case VTL_IMPORT_NONE:
4259 /* strip _session->session_directory().video_path() from video file if possible */
4260 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4261 path=path.substr(_session->session_directory().video_path().size());
4262 if (path.at(0) == G_DIR_SEPARATOR) {
4263 path=path.substr(1);
4267 video_timeline->set_update_session_fps(auto_set_session_fps);
4269 if (video_timeline->video_file_info(path, local_file)) {
4270 XMLNode* node = new XMLNode(X_("Videotimeline"));
4271 node->add_property (X_("Filename"), path);
4272 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4273 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4274 if (orig_local_file) {
4275 node->add_property (X_("OriginalVideoFile"), orig_path);
4277 node->remove_property (X_("OriginalVideoFile"));
4279 _session->add_extra_xml (*node);
4280 _session->set_dirty ();
4282 if (!audio_from_video.empty() && detect_ltc) {
4283 std::vector<LTCFileReader::LTCMap> ltc_seq;
4286 /* TODO ask user about TV standard (LTC alignment if any) */
4287 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4288 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4290 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4292 /* TODO seek near end of file, and read LTC until end.
4293 * if it fails to find any LTC frames, scan complete file
4295 * calculate drift of LTC compared to video-duration,
4296 * ask user for reference (timecode from start/mid/end)
4299 // LTCFileReader will have written error messages
4302 ::g_unlink(audio_from_video.c_str());
4304 if (ltc_seq.size() == 0) {
4305 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4307 /* the very first TC in the file is somteimes not aligned properly */
4308 int i = ltc_seq.size() -1;
4309 ARDOUR::frameoffset_t video_start_offset =
4310 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4311 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4312 video_timeline->set_offset(video_start_offset);
4316 _session->maybe_update_session_range(
4317 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4318 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4321 if (add_video_dialog->launch_xjadeo() && local_file) {
4322 editor->set_xjadeo_sensitive(true);
4323 editor->toggle_xjadeo_proc(1);
4325 editor->toggle_xjadeo_proc(0);
4327 editor->toggle_ruler_video(true);
4332 ARDOUR_UI::remove_video ()
4334 video_timeline->close_session();
4335 editor->toggle_ruler_video(false);
4338 video_timeline->set_offset_locked(false);
4339 video_timeline->set_offset(0);
4341 /* delete session state */
4342 XMLNode* node = new XMLNode(X_("Videotimeline"));
4343 _session->add_extra_xml(*node);
4344 node = new XMLNode(X_("Videomonitor"));
4345 _session->add_extra_xml(*node);
4346 node = new XMLNode(X_("Videoexport"));
4347 _session->add_extra_xml(*node);
4348 stop_video_server();
4352 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4354 if (localcacheonly) {
4355 video_timeline->vmon_update();
4357 video_timeline->flush_cache();
4359 editor->queue_visual_videotimeline_update();
4363 ARDOUR_UI::export_video (bool range)
4365 if (ARDOUR::Config->get_show_video_export_info()) {
4366 ExportVideoInfobox infobox (_session);
4367 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4368 if (infobox.show_again()) {
4369 ARDOUR::Config->set_show_video_export_info(false);
4372 case GTK_RESPONSE_YES:
4373 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4379 export_video_dialog->set_session (_session);
4380 export_video_dialog->apply_state(editor->get_selection().time, range);
4381 export_video_dialog->run ();
4382 export_video_dialog->hide ();
4386 ARDOUR_UI::mixer_settings () const
4391 node = _session->instant_xml(X_("Mixer"));
4393 node = Config->instant_xml(X_("Mixer"));
4397 node = new XMLNode (X_("Mixer"));
4404 ARDOUR_UI::main_window_settings () const
4409 node = _session->instant_xml(X_("Main"));
4411 node = Config->instant_xml(X_("Main"));
4415 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4416 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4421 node = new XMLNode (X_("Main"));
4428 ARDOUR_UI::editor_settings () const
4433 node = _session->instant_xml(X_("Editor"));
4435 node = Config->instant_xml(X_("Editor"));
4439 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4440 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4445 node = new XMLNode (X_("Editor"));
4452 ARDOUR_UI::keyboard_settings () const
4456 node = Config->extra_xml(X_("Keyboard"));
4459 node = new XMLNode (X_("Keyboard"));
4466 ARDOUR_UI::create_xrun_marker (framepos_t where)
4469 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4470 _session->locations()->add (location);
4475 ARDOUR_UI::halt_on_xrun_message ()
4477 cerr << "HALT on xrun\n";
4478 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4483 ARDOUR_UI::xrun_handler (framepos_t where)
4489 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4491 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4492 create_xrun_marker(where);
4495 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4496 halt_on_xrun_message ();
4501 ARDOUR_UI::disk_overrun_handler ()
4503 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4505 if (!have_disk_speed_dialog_displayed) {
4506 have_disk_speed_dialog_displayed = true;
4507 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4508 The disk system on your computer\n\
4509 was not able to keep up with %1.\n\
4511 Specifically, it failed to write data to disk\n\
4512 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4513 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4519 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4520 static MessageDialog *scan_dlg = NULL;
4521 static ProgressBar *scan_pbar = NULL;
4522 static HBox *scan_tbox = NULL;
4523 static Gtk::Button *scan_timeout_button;
4526 ARDOUR_UI::cancel_plugin_scan ()
4528 PluginManager::instance().cancel_plugin_scan();
4532 ARDOUR_UI::cancel_plugin_timeout ()
4534 PluginManager::instance().cancel_plugin_timeout();
4535 scan_timeout_button->set_sensitive (false);
4539 ARDOUR_UI::plugin_scan_timeout (int timeout)
4541 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4545 scan_pbar->set_sensitive (false);
4546 scan_timeout_button->set_sensitive (true);
4547 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4550 scan_pbar->set_sensitive (false);
4551 scan_timeout_button->set_sensitive (false);
4557 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4559 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4563 const bool cancelled = PluginManager::instance().cancelled();
4564 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4565 if (cancelled && scan_dlg->is_mapped()) {
4570 if (cancelled || !can_cancel) {
4575 static Gtk::Button *cancel_button;
4577 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4578 VBox* vbox = scan_dlg->get_vbox();
4579 vbox->set_size_request(400,-1);
4580 scan_dlg->set_title (_("Scanning for plugins"));
4582 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4583 cancel_button->set_name ("EditorGTKButton");
4584 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4585 cancel_button->show();
4587 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4589 scan_tbox = manage( new HBox() );
4591 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4592 scan_timeout_button->set_name ("EditorGTKButton");
4593 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4594 scan_timeout_button->show();
4596 scan_pbar = manage(new ProgressBar());
4597 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4598 scan_pbar->set_text(_("Scan Timeout"));
4601 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4602 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4604 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4607 assert(scan_dlg && scan_tbox && cancel_button);
4609 if (type == X_("closeme")) {
4613 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4616 if (!can_cancel || !cancelled) {
4617 scan_timeout_button->set_sensitive(false);
4619 cancel_button->set_sensitive(can_cancel && !cancelled);
4625 ARDOUR_UI::gui_idle_handler ()
4628 /* due to idle calls, gtk_events_pending() may always return true */
4629 while (gtk_events_pending() && --timeout) {
4630 gtk_main_iteration ();
4635 ARDOUR_UI::disk_underrun_handler ()
4637 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4639 if (!have_disk_speed_dialog_displayed) {
4640 have_disk_speed_dialog_displayed = true;
4641 MessageDialog* msg = new MessageDialog (
4642 _main_window, string_compose (_("The disk system on your computer\n\
4643 was not able to keep up with %1.\n\
4645 Specifically, it failed to read data from disk\n\
4646 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4647 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4653 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4655 have_disk_speed_dialog_displayed = false;
4660 ARDOUR_UI::session_dialog (std::string msg)
4662 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4666 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4673 ARDOUR_UI::pending_state_dialog ()
4675 HBox* hbox = manage (new HBox());
4676 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4677 ArdourDialog dialog (_("Crash Recovery"), true);
4678 Label message (string_compose (_("\
4679 This session appears to have been in the\n\
4680 middle of recording when %1 or\n\
4681 the computer was shutdown.\n\
4683 %1 can recover any captured audio for\n\
4684 you, or it can ignore it. Please decide\n\
4685 what you would like to do.\n"), PROGRAM_NAME));
4686 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4687 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4688 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4689 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4690 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4691 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4692 dialog.set_default_response (RESPONSE_ACCEPT);
4693 dialog.set_position (WIN_POS_CENTER);
4698 switch (dialog.run ()) {
4699 case RESPONSE_ACCEPT:
4707 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4709 HBox* hbox = new HBox();
4710 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4711 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4712 Label message (string_compose (_("\
4713 This session was created with a sample rate of %1 Hz, but\n\
4714 %2 is currently running at %3 Hz. If you load this session,\n\
4715 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4717 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4718 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4719 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4720 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4721 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4722 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4723 dialog.set_default_response (RESPONSE_ACCEPT);
4724 dialog.set_position (WIN_POS_CENTER);
4729 switch (dialog.run()) {
4730 case RESPONSE_ACCEPT:
4740 ARDOUR_UI::use_config ()
4742 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4744 set_transport_controllable_state (*node);
4749 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4751 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4752 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4754 primary_clock->set (pos);
4757 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4758 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4760 secondary_clock->set (pos);
4763 if (big_clock_window) {
4764 big_clock->set (pos);
4766 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4770 ARDOUR_UI::step_edit_status_change (bool yn)
4772 // XXX should really store pre-step edit status of things
4773 // we make insensitive
4776 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4777 rec_button.set_sensitive (false);
4779 rec_button.unset_active_state ();;
4780 rec_button.set_sensitive (true);
4785 ARDOUR_UI::record_state_changed ()
4787 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4789 if (!_session || !big_clock_window) {
4790 /* why bother - the clock isn't visible */
4794 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4795 big_clock->set_active (true);
4797 big_clock->set_active (false);
4802 ARDOUR_UI::first_idle ()
4805 _session->allow_auto_play (true);
4809 editor->first_idle();
4812 Keyboard::set_can_save_keybindings (true);
4817 ARDOUR_UI::store_clock_modes ()
4819 XMLNode* node = new XMLNode(X_("ClockModes"));
4821 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4822 XMLNode* child = new XMLNode (X_("Clock"));
4824 child->add_property (X_("name"), (*x)->name());
4825 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4826 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4828 node->add_child_nocopy (*child);
4831 _session->add_extra_xml (*node);
4832 _session->set_dirty ();
4835 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4836 : Controllable (name), ui (u), type(tp)
4842 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4845 /* do nothing: these are radio-style actions */
4849 const char *action = 0;
4853 action = X_("Roll");
4856 action = X_("Stop");
4859 action = X_("GotoStart");
4862 action = X_("GotoEnd");
4865 action = X_("Loop");
4868 action = X_("PlaySelection");
4871 action = X_("Record");
4881 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4889 ARDOUR_UI::TransportControllable::get_value (void) const
4916 ARDOUR_UI::setup_profile ()
4918 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4919 Profile->set_small_screen ();
4922 if (g_getenv ("TRX")) {
4923 Profile->set_trx ();
4926 if (g_getenv ("MIXBUS")) {
4927 Profile->set_mixbus ();
4932 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4934 MissingFileDialog dialog (s, str, type);
4939 int result = dialog.run ();
4946 return 1; // quit entire session load
4949 result = dialog.get_action ();
4955 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4957 AmbiguousFileDialog dialog (file, hits);
4964 return dialog.get_which ();
4967 /** Allocate our thread-local buffers */
4969 ARDOUR_UI::get_process_buffers ()
4971 _process_thread->get_buffers ();
4974 /** Drop our thread-local buffers */
4976 ARDOUR_UI::drop_process_buffers ()
4978 _process_thread->drop_buffers ();
4982 ARDOUR_UI::feedback_detected ()
4984 _feedback_exists = true;
4988 ARDOUR_UI::successful_graph_sort ()
4990 _feedback_exists = false;
4994 ARDOUR_UI::midi_panic ()
4997 _session->midi_panic();
5002 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5004 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5005 const char* end_big = "</span>";
5006 const char* start_mono = "<tt>";
5007 const char* end_mono = "</tt>";
5009 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5010 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5011 "From now on, use the -2000 version with older versions of %3"),
5012 xml_path, backup_path, PROGRAM_NAME,
5014 start_mono, end_mono), true);
5021 ARDOUR_UI::reset_peak_display ()
5023 if (!_session || !_session->master_out() || !editor_meter) return;
5024 editor_meter->clear_meters();
5025 editor_meter_max_peak = -INFINITY;
5026 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5030 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5032 if (!_session || !_session->master_out()) return;
5033 if (group == _session->master_out()->route_group()) {
5034 reset_peak_display ();
5039 ARDOUR_UI::reset_route_peak_display (Route* route)
5041 if (!_session || !_session->master_out()) return;
5042 if (_session->master_out().get() == route) {
5043 reset_peak_display ();
5048 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5050 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5051 audio_midi_setup->set_position (WIN_POS_CENTER);
5056 response = audio_midi_setup->run();
5058 case Gtk::RESPONSE_OK:
5059 if (!AudioEngine::instance()->running()) {
5073 ARDOUR_UI::transport_numpad_timeout ()
5075 _numpad_locate_happening = false;
5076 if (_numpad_timeout_connection.connected() )
5077 _numpad_timeout_connection.disconnect();
5082 ARDOUR_UI::transport_numpad_decimal ()
5084 _numpad_timeout_connection.disconnect();
5086 if (_numpad_locate_happening) {
5087 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5088 _numpad_locate_happening = false;
5090 _pending_locate_num = 0;
5091 _numpad_locate_happening = true;
5092 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5097 ARDOUR_UI::transport_numpad_event (int num)
5099 if ( _numpad_locate_happening ) {
5100 _pending_locate_num = _pending_locate_num*10 + num;
5103 case 0: toggle_roll(false, false); break;
5104 case 1: transport_rewind(1); break;
5105 case 2: transport_forward(1); break;
5106 case 3: transport_record(true); break;
5107 case 4: toggle_session_auto_loop(); break;
5108 case 5: transport_record(false); toggle_session_auto_loop(); break;
5109 case 6: toggle_punch(); break;
5110 case 7: toggle_click(); break;
5111 case 8: toggle_auto_return(); break;
5112 case 9: toggle_follow_edits(); break;
5118 ARDOUR_UI::set_flat_buttons ()
5120 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5124 ARDOUR_UI::audioengine_became_silent ()
5126 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5128 Gtk::MESSAGE_WARNING,
5132 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5134 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5135 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5136 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5137 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5138 Gtk::HBox pay_button_box;
5139 Gtk::HBox subscribe_button_box;
5141 pay_button_box.pack_start (pay_button, true, false);
5142 subscribe_button_box.pack_start (subscribe_button, true, false);
5144 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 */
5146 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5147 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5149 msg.get_vbox()->pack_start (pay_label);
5150 msg.get_vbox()->pack_start (pay_button_box);
5151 msg.get_vbox()->pack_start (subscribe_label);
5152 msg.get_vbox()->pack_start (subscribe_button_box);
5154 msg.get_vbox()->show_all ();
5156 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5157 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5158 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5163 case Gtk::RESPONSE_YES:
5164 AudioEngine::instance()->reset_silence_countdown ();
5167 case Gtk::RESPONSE_NO:
5169 save_state_canfail ("");
5173 case Gtk::RESPONSE_CANCEL:
5175 /* don't reset, save session and exit */
5181 ARDOUR_UI::hide_application ()
5183 Application::instance ()-> hide ();
5187 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5189 /* icons, titles, WM stuff */
5191 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5193 if (window_icons.empty()) {
5194 Glib::RefPtr<Gdk::Pixbuf> icon;
5195 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5196 window_icons.push_back (icon);
5198 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5199 window_icons.push_back (icon);
5201 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5202 window_icons.push_back (icon);
5204 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5205 window_icons.push_back (icon);
5209 if (!window_icons.empty()) {
5210 window.set_default_icon_list (window_icons);
5213 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5215 if (!name.empty()) {
5219 window.set_title (title.get_string());
5220 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5222 window.set_flags (CAN_FOCUS);
5223 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5225 /* This is a hack to ensure that GTK-accelerators continue to
5226 * work. Once we switch over to entirely native bindings, this will be
5227 * unnecessary and should be removed
5229 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5231 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5232 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5233 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5234 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5238 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5240 Gtkmm2ext::Bindings* bindings = 0;
5241 Gtk::Window* window = 0;
5243 /* until we get ardour bindings working, we are not handling key
5247 if (ev->type != GDK_KEY_PRESS) {
5251 if (event_window == &_main_window) {
5253 window = event_window;
5255 /* find current tab contents */
5257 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5259 /* see if it uses the ardour binding system */
5262 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5265 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5269 window = event_window;
5271 /* see if window uses ardour binding system */
5273 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5276 /* An empty binding set is treated as if it doesn't exist */
5278 if (bindings && bindings->empty()) {
5282 return key_press_focus_accelerator_handler (*window, ev, bindings);
5286 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5288 GtkWindow* win = window.gobj();
5289 GtkWidget* focus = gtk_window_get_focus (win);
5290 bool special_handling_of_unmodified_accelerators = false;
5291 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5295 /* some widget has keyboard focus */
5297 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5299 /* A particular kind of focusable widget currently has keyboard
5300 * focus. All unmodified key events should go to that widget
5301 * first and not be used as an accelerator by default
5304 special_handling_of_unmodified_accelerators = true;
5308 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",
5311 show_gdk_event_state (ev->state),
5312 special_handling_of_unmodified_accelerators,
5313 Keyboard::some_magic_widget_has_focus(),
5315 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5316 ((ev->state & mask) ? "yes" : "no")));
5318 /* This exists to allow us to override the way GTK handles
5319 key events. The normal sequence is:
5321 a) event is delivered to a GtkWindow
5322 b) accelerators/mnemonics are activated
5323 c) if (b) didn't handle the event, propagate to
5324 the focus widget and/or focus chain
5326 The problem with this is that if the accelerators include
5327 keys without modifiers, such as the space bar or the
5328 letter "e", then pressing the key while typing into
5329 a text entry widget results in the accelerator being
5330 activated, instead of the desired letter appearing
5333 There is no good way of fixing this, but this
5334 represents a compromise. The idea is that
5335 key events involving modifiers (not Shift)
5336 get routed into the activation pathway first, then
5337 get propagated to the focus widget if necessary.
5339 If the key event doesn't involve modifiers,
5340 we deliver to the focus widget first, thus allowing
5341 it to get "normal text" without interference
5344 Of course, this can also be problematic: if there
5345 is a widget with focus, then it will swallow
5346 all "normal text" accelerators.
5350 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5352 /* no special handling or there are modifiers in effect: accelerate first */
5354 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5355 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5356 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5358 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5359 KeyboardKey k (ev->state, ev->keyval);
5363 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5365 if (bindings->activate (k, Bindings::Press)) {
5366 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5371 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5373 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5374 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5378 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5380 if (gtk_window_propagate_key_event (win, ev)) {
5381 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5387 /* no modifiers, propagate first */
5389 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5391 if (gtk_window_propagate_key_event (win, ev)) {
5392 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5396 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5397 KeyboardKey k (ev->state, ev->keyval);
5401 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5404 if (bindings->activate (k, Bindings::Press)) {
5405 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5411 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5413 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5414 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5419 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5424 ARDOUR_UI::load_bindings ()
5426 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5427 error << _("Global keybindings are missing") << endmsg;
5432 ARDOUR_UI::cancel_solo ()
5435 if (_session->soloing()) {
5436 _session->set_solo (_session->get_routes(), false);
5437 } else if (_session->listening()) {
5438 _session->set_listen (_session->get_routes(), false);
5441 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window