2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #ifdef WINDOWS_VST_SUPPORT
97 #ifdef AUDIOUNIT_SUPPORT
98 #include "ardour/audio_unit.h"
101 #include "timecode/time.h"
103 typedef uint64_t microseconds_t;
108 #include "add_route_dialog.h"
109 #include "ambiguous_file_dialog.h"
110 #include "ardour_ui.h"
111 #include "audio_clock.h"
112 #include "audio_region_view.h"
113 #include "big_clock_window.h"
114 #include "bundle_manager.h"
115 #include "duplicate_routes_dialog.h"
117 #include "engine_dialog.h"
118 #include "export_video_dialog.h"
119 #include "export_video_infobox.h"
120 #include "gain_meter.h"
121 #include "global_port_matrix.h"
122 #include "gui_object.h"
123 #include "gui_thread.h"
124 #include "keyboard.h"
125 #include "keyeditor.h"
126 #include "location_ui.h"
127 #include "luawindow.h"
128 #include "main_clock.h"
129 #include "missing_file_dialog.h"
130 #include "missing_plugin_dialog.h"
131 #include "mixer_ui.h"
132 #include "meterbridge.h"
133 #include "mouse_cursors.h"
136 #include "pingback.h"
137 #include "processor_box.h"
138 #include "prompter.h"
139 #include "public_editor.h"
140 #include "rc_option_editor.h"
141 #include "route_time_axis.h"
142 #include "route_params_ui.h"
143 #include "save_as_dialog.h"
144 #include "session_dialog.h"
145 #include "session_metadata_dialog.h"
146 #include "session_option_editor.h"
147 #include "shuttle_control.h"
148 #include "speaker_dialog.h"
151 #include "theme_manager.h"
152 #include "time_axis_view_item.h"
155 #include "video_server_dialog.h"
156 #include "add_video_dialog.h"
157 #include "transcode_video_dialog.h"
161 using namespace ARDOUR;
162 using namespace ARDOUR_UI_UTILS;
164 using namespace Gtkmm2ext;
167 using namespace Editing;
169 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
171 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
172 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
175 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
177 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
178 "Would you like these files to be copied and used for %1 %2.x?\n\n"
179 "(This will require you to restart %1.)"),
180 PROGRAM_NAME, PROGRAM_VERSION, version),
181 false, /* no markup */
184 true /* modal, though it hardly matters since it is the only window */
187 msg.set_default_response (Gtk::RESPONSE_YES);
190 return (msg.run() == Gtk::RESPONSE_YES);
194 libxml_generic_error_func (void* /* parsing_context*/,
202 vsnprintf (buf, sizeof (buf), msg, ap);
203 error << buf << endmsg;
208 libxml_structured_error_func (void* /* parsing_context*/,
216 replace_all (msg, "\n", "");
218 if (err->file && err->line) {
219 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
222 error << ':' << err->int2;
229 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
230 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
231 , session_loaded (false)
232 , gui_object_state (new GUIObjectState)
233 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
234 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
235 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
237 , global_actions (X_("global"))
238 , ignore_dual_punch (false)
243 , _mixer_on_top (false)
244 , _initial_verbose_plugin_scan (false)
245 , first_time_engine_run (true)
246 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
247 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
248 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
249 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
250 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
251 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
252 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
253 , auto_return_button (ArdourButton::led_default_elements)
254 , follow_edits_button (ArdourButton::led_default_elements)
255 , auto_input_button (ArdourButton::led_default_elements)
256 , auditioning_alert_button (_("Audition"))
257 , solo_alert_button (_("Solo"))
258 , feedback_alert_button (_("Feedback"))
259 , error_alert_button ( ArdourButton::just_led_default_elements )
261 , editor_meter_peak_display()
262 , _numpad_locate_happening (false)
263 , _session_is_new (false)
264 , last_key_press_time (0)
268 , rc_option_editor (0)
269 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
270 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
271 , about (X_("about"), _("About"))
272 , location_ui (X_("locations"), _("Locations"))
273 , route_params (X_("inspector"), _("Tracks and Busses"))
274 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
275 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
276 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
277 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
278 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
279 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
280 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
281 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
282 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
283 , video_server_process (0)
285 , have_configure_timeout (false)
286 , last_configure_time (0)
288 , have_disk_speed_dialog_displayed (false)
289 , _status_bar_visibility (X_("status-bar"))
290 , _feedback_exists (false)
291 , _log_not_acknowledged (LogLevelNone)
292 , duplicate_routes_dialog (0)
293 , editor_visibility_button (S_("Window|Editor"))
294 , mixer_visibility_button (S_("Window|Mixer"))
295 , prefs_visibility_button (S_("Window|Preferences"))
297 Gtkmm2ext::init (localedir);
299 UIConfiguration::instance().post_gui_init ();
301 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
302 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
304 /* configuration was modified, exit immediately */
308 if (theArdourUI == 0) {
312 /* stop libxml from spewing to stdout/stderr */
314 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
315 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
317 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
318 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
319 UIConfiguration::instance().map_parameters (pc);
321 roll_button.set_controllable (roll_controllable);
322 stop_button.set_controllable (stop_controllable);
323 goto_start_button.set_controllable (goto_start_controllable);
324 goto_end_button.set_controllable (goto_end_controllable);
325 auto_loop_button.set_controllable (auto_loop_controllable);
326 play_selection_button.set_controllable (play_selection_controllable);
327 rec_button.set_controllable (rec_controllable);
329 roll_button.set_name ("transport button");
330 stop_button.set_name ("transport button");
331 goto_start_button.set_name ("transport button");
332 goto_end_button.set_name ("transport button");
333 auto_loop_button.set_name ("transport button");
334 play_selection_button.set_name ("transport button");
335 rec_button.set_name ("transport recenable button");
336 midi_panic_button.set_name ("transport button");
338 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
339 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
341 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
343 /* handle dialog requests */
345 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
347 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
349 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
351 /* handle Audio/MIDI setup when session requires it */
353 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
355 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
357 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
359 /* handle requests to quit (coming from JACK session) */
361 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
363 /* tell the user about feedback */
365 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
366 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
368 /* handle requests to deal with missing files */
370 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
372 /* and ambiguous files */
374 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
376 /* also plugin scan messages */
377 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
378 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
380 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
382 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
385 /* lets get this party started */
387 setup_gtk_ardour_enums ();
390 SessionEvent::create_per_thread_pool ("GUI", 4096);
392 /* we like keyboards */
394 keyboard = new ArdourKeyboard(*this);
396 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
398 keyboard->set_state (*node, Stateful::loading_state_version);
401 UIConfiguration::instance().reset_dpi ();
403 TimeAxisViewItem::set_constant_heights ();
405 /* Set this up so that our window proxies can register actions */
407 ActionManager::init ();
409 /* The following must happen after ARDOUR::init() so that Config is set up */
411 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
414 key_editor.set_state (*ui_xml, 0);
415 session_option_editor.set_state (*ui_xml, 0);
416 speaker_config_window.set_state (*ui_xml, 0);
417 about.set_state (*ui_xml, 0);
418 add_route_dialog.set_state (*ui_xml, 0);
419 add_video_dialog.set_state (*ui_xml, 0);
420 route_params.set_state (*ui_xml, 0);
421 bundle_manager.set_state (*ui_xml, 0);
422 location_ui.set_state (*ui_xml, 0);
423 big_clock_window.set_state (*ui_xml, 0);
424 audio_port_matrix.set_state (*ui_xml, 0);
425 midi_port_matrix.set_state (*ui_xml, 0);
426 export_video_dialog.set_state (*ui_xml, 0);
429 /* Separate windows */
431 WM::Manager::instance().register_window (&key_editor);
432 WM::Manager::instance().register_window (&session_option_editor);
433 WM::Manager::instance().register_window (&speaker_config_window);
434 WM::Manager::instance().register_window (&about);
435 WM::Manager::instance().register_window (&add_route_dialog);
436 WM::Manager::instance().register_window (&add_video_dialog);
437 WM::Manager::instance().register_window (&route_params);
438 WM::Manager::instance().register_window (&audio_midi_setup);
439 WM::Manager::instance().register_window (&export_video_dialog);
440 WM::Manager::instance().register_window (&bundle_manager);
441 WM::Manager::instance().register_window (&location_ui);
442 WM::Manager::instance().register_window (&big_clock_window);
443 WM::Manager::instance().register_window (&audio_port_matrix);
444 WM::Manager::instance().register_window (&midi_port_matrix);
446 /* Trigger setting up the color scheme and loading the GTK RC file */
448 UIConfiguration::instance().load_rc_file (false);
450 _process_thread = new ProcessThread ();
451 _process_thread->init ();
453 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
458 GlobalPortMatrixWindow*
459 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
464 return new GlobalPortMatrixWindow (_session, type);
468 ARDOUR_UI::attach_to_engine ()
470 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
471 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
475 ARDOUR_UI::engine_stopped ()
477 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
478 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
479 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
480 update_sample_rate (0);
485 ARDOUR_UI::engine_running ()
487 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
488 if (first_time_engine_run) {
490 first_time_engine_run = false;
494 _session->reset_xrun_count ();
496 update_disk_space ();
498 update_xrun_count ();
499 update_sample_rate (AudioEngine::instance()->sample_rate());
500 update_timecode_format ();
501 update_peak_thread_work ();
502 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
503 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
507 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
509 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
510 /* we can't rely on the original string continuing to exist when we are called
511 again in the GUI thread, so make a copy and note that we need to
514 char *copy = strdup (reason);
515 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
519 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
520 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
522 update_sample_rate (0);
526 /* if the reason is a non-empty string, it means that the backend was shutdown
527 rather than just Ardour.
530 if (strlen (reason)) {
531 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
533 msgstr = string_compose (_("\
534 The audio backend has either been shutdown or it\n\
535 disconnected %1 because %1\n\
536 was not fast enough. Try to restart\n\
537 the audio backend and save the session."), PROGRAM_NAME);
540 MessageDialog msg (_main_window, msgstr);
541 pop_back_splash (msg);
545 free (const_cast<char*> (reason));
550 ARDOUR_UI::post_engine ()
552 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
554 #ifdef AUDIOUNIT_SUPPORT
556 if (AUPluginInfo::au_get_crashlog(au_msg)) {
557 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
558 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
559 info << au_msg << endmsg;
563 ARDOUR::init_post_engine ();
565 /* connect to important signals */
567 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
568 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
569 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
570 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
571 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
573 if (setup_windows ()) {
574 throw failed_constructor ();
577 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
578 XMLNode* n = Config->extra_xml (X_("UI"));
580 _status_bar_visibility.set_state (*n);
583 check_memory_locking();
585 /* this is the first point at which all the possible actions are
586 * available, because some of the available actions are dependent on
587 * aspects of the engine/backend.
590 if (ARDOUR_COMMAND_LINE::show_key_actions) {
593 vector<string> paths;
594 vector<string> labels;
595 vector<string> tooltips;
597 vector<Glib::RefPtr<Gtk::Action> > actions;
599 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
601 vector<string>::iterator k;
602 vector<string>::iterator p;
604 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
609 cout << *p << " => " << *k << endl;
613 halt_connection.disconnect ();
614 AudioEngine::instance()->stop ();
618 /* this being a GUI and all, we want peakfiles */
620 AudioFileSource::set_build_peakfiles (true);
621 AudioFileSource::set_build_missing_peakfiles (true);
623 /* set default clock modes */
625 primary_clock->set_mode (AudioClock::Timecode);
626 secondary_clock->set_mode (AudioClock::BBT);
628 /* start the time-of-day-clock */
631 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
632 update_wall_clock ();
633 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
638 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
639 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
640 Config->map_parameters (pc);
642 UIConfiguration::instance().map_parameters (pc);
646 ARDOUR_UI::~ARDOUR_UI ()
648 UIConfiguration::instance().save_state();
652 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
653 // don't bother at 'real' exit. the OS cleans up for us.
655 delete primary_clock;
656 delete secondary_clock;
657 delete _process_thread;
663 delete gui_object_state;
664 FastMeter::flush_pattern_cache ();
665 PixFader::flush_pattern_cache ();
669 /* Small trick to flush main-thread event pool.
670 * Other thread-pools are destroyed at pthread_exit(),
671 * but tmain thread termination is too late to trigger Pool::~Pool()
673 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.
674 delete ev->event_pool();
679 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
681 if (Splash::instance()) {
682 Splash::instance()->pop_back_for (win);
687 ARDOUR_UI::configure_timeout ()
689 if (last_configure_time == 0) {
690 /* no configure events yet */
694 /* force a gap of 0.5 seconds since the last configure event
697 if (get_microseconds() - last_configure_time < 500000) {
700 have_configure_timeout = false;
701 save_ardour_state ();
707 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
709 if (have_configure_timeout) {
710 last_configure_time = get_microseconds();
712 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
713 have_configure_timeout = true;
720 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
722 const XMLProperty* prop;
724 if ((prop = node.property ("roll")) != 0) {
725 roll_controllable->set_id (prop->value());
727 if ((prop = node.property ("stop")) != 0) {
728 stop_controllable->set_id (prop->value());
730 if ((prop = node.property ("goto-start")) != 0) {
731 goto_start_controllable->set_id (prop->value());
733 if ((prop = node.property ("goto-end")) != 0) {
734 goto_end_controllable->set_id (prop->value());
736 if ((prop = node.property ("auto-loop")) != 0) {
737 auto_loop_controllable->set_id (prop->value());
739 if ((prop = node.property ("play-selection")) != 0) {
740 play_selection_controllable->set_id (prop->value());
742 if ((prop = node.property ("rec")) != 0) {
743 rec_controllable->set_id (prop->value());
745 if ((prop = node.property ("shuttle")) != 0) {
746 shuttle_box->controllable()->set_id (prop->value());
751 ARDOUR_UI::get_transport_controllable_state ()
753 XMLNode* node = new XMLNode(X_("TransportControllables"));
756 roll_controllable->id().print (buf, sizeof (buf));
757 node->add_property (X_("roll"), buf);
758 stop_controllable->id().print (buf, sizeof (buf));
759 node->add_property (X_("stop"), buf);
760 goto_start_controllable->id().print (buf, sizeof (buf));
761 node->add_property (X_("goto_start"), buf);
762 goto_end_controllable->id().print (buf, sizeof (buf));
763 node->add_property (X_("goto_end"), buf);
764 auto_loop_controllable->id().print (buf, sizeof (buf));
765 node->add_property (X_("auto_loop"), buf);
766 play_selection_controllable->id().print (buf, sizeof (buf));
767 node->add_property (X_("play_selection"), buf);
768 rec_controllable->id().print (buf, sizeof (buf));
769 node->add_property (X_("rec"), buf);
770 shuttle_box->controllable()->id().print (buf, sizeof (buf));
771 node->add_property (X_("shuttle"), buf);
777 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
780 _session->save_state (snapshot_name);
785 ARDOUR_UI::autosave_session ()
787 if (g_main_depth() > 1) {
788 /* inside a recursive main loop,
789 give up because we may not be able to
795 if (!Config->get_periodic_safety_backups()) {
800 _session->maybe_write_autosave();
807 ARDOUR_UI::session_dirty_changed ()
814 ARDOUR_UI::update_autosave ()
816 if (_session && _session->dirty()) {
817 if (_autosave_connection.connected()) {
818 _autosave_connection.disconnect();
821 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
822 Config->get_periodic_safety_backup_interval() * 1000);
825 if (_autosave_connection.connected()) {
826 _autosave_connection.disconnect();
832 ARDOUR_UI::check_announcements ()
835 string _annc_filename;
838 _annc_filename = PROGRAM_NAME "_announcements_osx_";
839 #elif defined PLATFORM_WINDOWS
840 _annc_filename = PROGRAM_NAME "_announcements_windows_";
842 _annc_filename = PROGRAM_NAME "_announcements_linux_";
844 _annc_filename.append (VERSIONSTRING);
846 _announce_string = "";
848 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
849 FILE* fin = g_fopen (path.c_str(), "rb");
851 while (!feof (fin)) {
854 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
857 _announce_string.append (tmp, len);
862 pingback (VERSIONSTRING, path);
867 _hide_splash (gpointer arg)
869 ((ARDOUR_UI*)arg)->hide_splash();
874 ARDOUR_UI::starting ()
876 Application* app = Application::instance ();
878 bool brand_new_user = ArdourStartup::required ();
880 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
881 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
883 if (ARDOUR_COMMAND_LINE::check_announcements) {
884 check_announcements ();
889 /* we need to create this early because it may need to set the
890 * audio backend end up.
894 audio_midi_setup.get (true);
896 std::cerr << "audio-midi engine setup failed."<< std::endl;
900 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
901 nsm = new NSM_Client;
902 if (!nsm->init (nsm_url)) {
903 /* the ardour executable may have different names:
905 * waf's obj.target for distro versions: eg ardour4, ardourvst4
906 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
907 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
909 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
911 const char *process_name = g_getenv ("ARDOUR_SELF");
912 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
915 // wait for announce reply from nsm server
916 for ( i = 0; i < 5000; ++i) {
920 if (nsm->is_active()) {
925 error << _("NSM server did not announce itself") << endmsg;
928 // wait for open command from nsm server
929 for ( i = 0; i < 5000; ++i) {
932 if (nsm->client_id ()) {
938 error << _("NSM: no client ID provided") << endmsg;
942 if (_session && nsm) {
943 _session->set_nsm_state( nsm->is_active() );
945 error << _("NSM: no session created") << endmsg;
949 // nsm requires these actions disabled
950 vector<string> action_names;
951 action_names.push_back("SaveAs");
952 action_names.push_back("Rename");
953 action_names.push_back("New");
954 action_names.push_back("Open");
955 action_names.push_back("Recent");
956 action_names.push_back("Close");
958 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
959 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
961 act->set_sensitive (false);
968 error << _("NSM: initialization failed") << endmsg;
974 if (brand_new_user) {
975 _initial_verbose_plugin_scan = true;
980 _initial_verbose_plugin_scan = false;
981 switch (s.response ()) {
982 case Gtk::RESPONSE_OK:
989 #ifdef NO_PLUGIN_STATE
991 ARDOUR::RecentSessions rs;
992 ARDOUR::read_recent_sessions (rs);
994 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
996 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
998 /* already used Ardour, have sessions ... warn about plugin state */
1000 ArdourDialog d (_("Free/Demo Version Warning"), true);
1002 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1003 CheckButton c (_("Don't warn me about this again"));
1005 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"),
1006 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1007 _("It will not restore OR save any plugin settings"),
1008 _("If you load an existing session with plugin settings\n"
1009 "they will not be used and will be lost."),
1010 _("To get full access to updates without this limitation\n"
1011 "consider becoming a subscriber for a low cost every month.")));
1012 l.set_justify (JUSTIFY_CENTER);
1014 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1016 d.get_vbox()->pack_start (l, true, true);
1017 d.get_vbox()->pack_start (b, false, false, 12);
1018 d.get_vbox()->pack_start (c, false, false, 12);
1020 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1021 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1025 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1027 if (d.run () != RESPONSE_OK) {
1033 /* go get a session */
1035 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1037 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1038 std::cerr << "Cannot get session parameters."<< std::endl;
1045 WM::Manager::instance().show_visible ();
1047 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1048 * editor window, and we may want stuff to be hidden.
1050 _status_bar_visibility.update ();
1052 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1054 if (splash && splash->is_visible()) {
1055 // in 1 second, hide the splash screen
1056 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1059 /* all other dialogs are created conditionally */
1065 ARDOUR_UI::check_memory_locking ()
1067 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1068 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1072 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1074 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1076 struct rlimit limits;
1078 long pages, page_size;
1080 size_t pages_len=sizeof(pages);
1081 if ((page_size = getpagesize()) < 0 ||
1082 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1084 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1089 ram = (int64_t) pages * (int64_t) page_size;
1092 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1096 if (limits.rlim_cur != RLIM_INFINITY) {
1098 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1102 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1103 "This might cause %1 to run out of memory before your system "
1104 "runs out of memory. \n\n"
1105 "You can view the memory limit with 'ulimit -l', "
1106 "and it is normally controlled by %2"),
1109 X_("/etc/login.conf")
1111 X_(" /etc/security/limits.conf")
1115 msg.set_default_response (RESPONSE_OK);
1117 VBox* vbox = msg.get_vbox();
1119 CheckButton cb (_("Do not show this window again"));
1120 hbox.pack_start (cb, true, false);
1121 vbox->pack_start (hbox);
1126 pop_back_splash (msg);
1130 if (cb.get_active()) {
1131 XMLNode node (X_("no-memory-warning"));
1132 Config->add_instant_xml (node);
1137 #endif // !__APPLE__
1142 ARDOUR_UI::queue_finish ()
1144 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1148 ARDOUR_UI::idle_finish ()
1151 return false; /* do not call again */
1158 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1160 if (_session->dirty()) {
1161 vector<string> actions;
1162 actions.push_back (_("Don't quit"));
1163 actions.push_back (_("Just quit"));
1164 actions.push_back (_("Save and quit"));
1165 switch (ask_about_saving_session(actions)) {
1170 /* use the default name */
1171 if (save_state_canfail ("")) {
1172 /* failed - don't quit */
1173 MessageDialog msg (_main_window,
1174 string_compose (_("\
1175 %1 was unable to save your session.\n\n\
1176 If you still wish to quit, please use the\n\n\
1177 \"Just quit\" option."), PROGRAM_NAME));
1178 pop_back_splash(msg);
1188 second_connection.disconnect ();
1189 point_one_second_connection.disconnect ();
1190 point_zero_something_second_connection.disconnect();
1191 fps_connection.disconnect();
1194 delete ARDOUR_UI::instance()->video_timeline;
1195 ARDOUR_UI::instance()->video_timeline = NULL;
1196 stop_video_server();
1198 /* Save state before deleting the session, as that causes some
1199 windows to be destroyed before their visible state can be
1202 save_ardour_state ();
1204 close_all_dialogs ();
1207 _session->set_clean ();
1208 _session->remove_pending_capture_state ();
1213 halt_connection.disconnect ();
1214 AudioEngine::instance()->stop ();
1215 #ifdef WINDOWS_VST_SUPPORT
1216 fst_stop_threading();
1222 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1224 ArdourDialog window (_("Unsaved Session"));
1225 Gtk::HBox dhbox; // the hbox for the image and text
1226 Gtk::Label prompt_label;
1227 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1231 assert (actions.size() >= 3);
1233 window.add_button (actions[0], RESPONSE_REJECT);
1234 window.add_button (actions[1], RESPONSE_APPLY);
1235 window.add_button (actions[2], RESPONSE_ACCEPT);
1237 window.set_default_response (RESPONSE_ACCEPT);
1239 Gtk::Button noquit_button (msg);
1240 noquit_button.set_name ("EditorGTKButton");
1244 if (_session->snap_name() == _session->name()) {
1245 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?"),
1246 _session->snap_name());
1248 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?"),
1249 _session->snap_name());
1252 prompt_label.set_text (prompt);
1253 prompt_label.set_name (X_("PrompterLabel"));
1254 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1256 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1257 dhbox.set_homogeneous (false);
1258 dhbox.pack_start (*dimage, false, false, 5);
1259 dhbox.pack_start (prompt_label, true, false, 5);
1260 window.get_vbox()->pack_start (dhbox);
1262 window.set_name (_("Prompter"));
1263 window.set_modal (true);
1264 window.set_resizable (false);
1267 prompt_label.show();
1272 ResponseType r = (ResponseType) window.run();
1277 case RESPONSE_ACCEPT: // save and get out of here
1279 case RESPONSE_APPLY: // get out of here
1290 ARDOUR_UI::every_second ()
1293 update_xrun_count ();
1294 update_buffer_load ();
1295 update_disk_space ();
1296 update_timecode_format ();
1297 update_peak_thread_work ();
1299 if (nsm && nsm->is_active ()) {
1302 if (!_was_dirty && _session->dirty ()) {
1306 else if (_was_dirty && !_session->dirty ()){
1314 ARDOUR_UI::every_point_one_seconds ()
1316 // TODO get rid of this..
1317 // ShuttleControl is updated directly via TransportStateChange signal
1321 ARDOUR_UI::every_point_zero_something_seconds ()
1323 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1325 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1326 float mpeak = editor_meter->update_meters();
1327 if (mpeak > editor_meter_max_peak) {
1328 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1329 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1336 ARDOUR_UI::set_fps_timeout_connection ()
1338 unsigned int interval = 40;
1339 if (!_session) return;
1340 if (_session->timecode_frames_per_second() != 0) {
1341 /* ideally we'll use a select() to sleep and not accumulate
1342 * idle time to provide a regular periodic signal.
1343 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1344 * However, that'll require a dedicated thread and cross-thread
1345 * signals to the GUI Thread..
1347 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1348 * _session->frame_rate() / _session->nominal_frame_rate()
1349 / _session->timecode_frames_per_second()
1351 #ifdef PLATFORM_WINDOWS
1352 // the smallest windows scheduler time-slice is ~15ms.
1353 // periodic GUI timeouts shorter than that will cause
1354 // WaitForSingleObject to spinlock (100% of one CPU Core)
1355 // and gtk never enters idle mode.
1356 // also changing timeBeginPeriod(1) does not affect that in
1357 // any beneficial way, so we just limit the max rate for now.
1358 interval = std::max(30u, interval); // at most ~33Hz.
1360 interval = std::max(8u, interval); // at most 120Hz.
1363 fps_connection.disconnect();
1364 Timers::set_fps_interval (interval);
1368 ARDOUR_UI::update_sample_rate (framecnt_t)
1372 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1374 if (!AudioEngine::instance()->connected()) {
1376 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1380 framecnt_t rate = AudioEngine::instance()->sample_rate();
1383 /* no sample rate available */
1384 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1387 if (fmod (rate, 1000.0) != 0.0) {
1388 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1389 (float) rate / 1000.0f,
1390 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1392 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1394 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1398 sample_rate_label.set_markup (buf);
1402 ARDOUR_UI::update_format ()
1405 format_label.set_text ("");
1410 s << _("File:") << X_(" <span foreground=\"green\">");
1412 switch (_session->config.get_native_file_header_format ()) {
1444 switch (_session->config.get_native_file_data_format ()) {
1458 format_label.set_markup (s.str ());
1462 ARDOUR_UI::update_xrun_count ()
1466 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1467 should also be changed.
1471 const unsigned int x = _session->get_xrun_count ();
1473 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1475 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1478 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1480 xrun_label.set_markup (buf);
1481 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1485 ARDOUR_UI::update_cpu_load ()
1489 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1490 should also be changed.
1493 double const c = AudioEngine::instance()->get_dsp_load ();
1494 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1495 cpu_load_label.set_markup (buf);
1499 ARDOUR_UI::update_peak_thread_work ()
1502 const int c = SourceFactory::peak_work_queue_length ();
1504 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1505 peak_thread_work_label.set_markup (buf);
1507 peak_thread_work_label.set_markup (X_(""));
1512 ARDOUR_UI::update_buffer_load ()
1516 uint32_t const playback = _session ? _session->playback_load () : 100;
1517 uint32_t const capture = _session ? _session->capture_load () : 100;
1519 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1520 should also be changed.
1526 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1527 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1528 playback <= 5 ? X_("red") : X_("green"),
1530 capture <= 5 ? X_("red") : X_("green"),
1534 buffer_load_label.set_markup (buf);
1536 buffer_load_label.set_text ("");
1541 ARDOUR_UI::count_recenabled_streams (Route& route)
1543 Track* track = dynamic_cast<Track*>(&route);
1544 if (track && track->record_enabled()) {
1545 rec_enabled_streams += track->n_inputs().n_total();
1550 ARDOUR_UI::update_disk_space()
1552 if (_session == 0) {
1556 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1558 framecnt_t fr = _session->frame_rate();
1561 /* skip update - no SR available */
1566 /* Available space is unknown */
1567 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1568 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1569 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1571 rec_enabled_streams = 0;
1572 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1574 framecnt_t frames = opt_frames.get_value_or (0);
1576 if (rec_enabled_streams) {
1577 frames /= rec_enabled_streams;
1584 hrs = frames / (fr * 3600);
1587 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1589 frames -= hrs * fr * 3600;
1590 mins = frames / (fr * 60);
1591 frames -= mins * fr * 60;
1594 bool const low = (hrs == 0 && mins <= 30);
1598 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1599 low ? X_("red") : X_("green"),
1605 disk_space_label.set_markup (buf);
1609 ARDOUR_UI::update_timecode_format ()
1615 TimecodeSlave* tcslave;
1616 SyncSource sync_src = Config->get_sync_source();
1618 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1619 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1624 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1625 matching ? X_("green") : X_("red"),
1626 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1628 snprintf (buf, sizeof (buf), "TC: n/a");
1631 timecode_format_label.set_markup (buf);
1635 ARDOUR_UI::update_wall_clock ()
1639 static int last_min = -1;
1642 tm_now = localtime (&now);
1643 if (last_min != tm_now->tm_min) {
1645 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1646 wall_clock_label.set_text (buf);
1647 last_min = tm_now->tm_min;
1654 ARDOUR_UI::open_recent_session ()
1656 bool can_return = (_session != 0);
1658 SessionDialog recent_session_dialog;
1662 ResponseType r = (ResponseType) recent_session_dialog.run ();
1665 case RESPONSE_ACCEPT:
1669 recent_session_dialog.hide();
1676 recent_session_dialog.hide();
1680 std::string path = recent_session_dialog.session_folder();
1681 std::string state = recent_session_dialog.session_name (should_be_new);
1683 if (should_be_new == true) {
1687 _session_is_new = false;
1689 if (load_session (path, state) == 0) {
1698 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1700 if (!AudioEngine::instance()->connected()) {
1701 MessageDialog msg (parent, string_compose (
1702 _("%1 is not connected to any audio backend.\n"
1703 "You cannot open or close sessions in this condition"),
1705 pop_back_splash (msg);
1713 ARDOUR_UI::open_session ()
1715 if (!check_audioengine (_main_window)) {
1719 /* ardour sessions are folders */
1720 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1721 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1722 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1723 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1726 string session_parent_dir = Glib::path_get_dirname(_session->path());
1727 open_session_selector.set_current_folder(session_parent_dir);
1729 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1732 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1734 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1735 string default_session_folder = Config->get_default_session_parent_dir();
1736 open_session_selector.add_shortcut_folder (default_session_folder);
1738 catch (Glib::Error & e) {
1739 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1742 FileFilter session_filter;
1743 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1744 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1745 open_session_selector.add_filter (session_filter);
1746 open_session_selector.set_filter (session_filter);
1748 int response = open_session_selector.run();
1749 open_session_selector.hide ();
1751 if (response == Gtk::RESPONSE_CANCEL) {
1755 string session_path = open_session_selector.get_filename();
1759 if (session_path.length() > 0) {
1760 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1761 _session_is_new = isnew;
1762 load_session (path, name);
1769 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1770 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1772 list<boost::shared_ptr<MidiTrack> > tracks;
1774 if (_session == 0) {
1775 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1780 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1782 if (tracks.size() != how_many) {
1783 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1788 MessageDialog msg (_main_window,
1789 string_compose (_("There are insufficient ports available\n\
1790 to create a new track or bus.\n\
1791 You should save %1, exit and\n\
1792 restart with more ports."), PROGRAM_NAME));
1799 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1801 ChanCount one_midi_channel;
1802 one_midi_channel.set (DataType::MIDI, 1);
1805 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1810 ARDOUR_UI::session_add_audio_route (
1812 int32_t input_channels,
1813 int32_t output_channels,
1814 ARDOUR::TrackMode mode,
1815 RouteGroup* route_group,
1817 string const & name_template
1820 list<boost::shared_ptr<AudioTrack> > tracks;
1823 if (_session == 0) {
1824 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1830 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1832 if (tracks.size() != how_many) {
1833 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1839 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1841 if (routes.size() != how_many) {
1842 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1849 MessageDialog msg (_main_window,
1850 string_compose (_("There are insufficient ports available\n\
1851 to create a new track or bus.\n\
1852 You should save %1, exit and\n\
1853 restart with more ports."), PROGRAM_NAME));
1854 pop_back_splash (msg);
1860 ARDOUR_UI::transport_goto_start ()
1863 _session->goto_start();
1865 /* force displayed area in editor to start no matter
1866 what "follow playhead" setting is.
1870 editor->center_screen (_session->current_start_frame ());
1876 ARDOUR_UI::transport_goto_zero ()
1879 _session->request_locate (0);
1881 /* force displayed area in editor to start no matter
1882 what "follow playhead" setting is.
1886 editor->reset_x_origin (0);
1892 ARDOUR_UI::transport_goto_wallclock ()
1894 if (_session && editor) {
1901 localtime_r (&now, &tmnow);
1903 framecnt_t frame_rate = _session->frame_rate();
1905 if (frame_rate == 0) {
1906 /* no frame rate available */
1910 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1911 frames += tmnow.tm_min * (60 * frame_rate);
1912 frames += tmnow.tm_sec * frame_rate;
1914 _session->request_locate (frames, _session->transport_rolling ());
1916 /* force displayed area in editor to start no matter
1917 what "follow playhead" setting is.
1921 editor->center_screen (frames);
1927 ARDOUR_UI::transport_goto_end ()
1930 framepos_t const frame = _session->current_end_frame();
1931 _session->request_locate (frame);
1933 /* force displayed area in editor to start no matter
1934 what "follow playhead" setting is.
1938 editor->center_screen (frame);
1944 ARDOUR_UI::transport_stop ()
1950 if (_session->is_auditioning()) {
1951 _session->cancel_audition ();
1955 _session->request_stop (false, true);
1958 /** Check if any tracks are record enabled. If none are, record enable all of them.
1959 * @return true if track record-enabled status was changed, false otherwise.
1962 ARDOUR_UI::trx_record_enable_all_tracks ()
1968 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1969 bool none_record_enabled = true;
1971 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1972 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1975 if (t->record_enabled()) {
1976 none_record_enabled = false;
1981 if (none_record_enabled) {
1982 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1985 return none_record_enabled;
1989 ARDOUR_UI::transport_record (bool roll)
1992 switch (_session->record_status()) {
1993 case Session::Disabled:
1994 if (_session->ntracks() == 0) {
1995 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."));
1999 if (Profile->get_trx()) {
2000 roll = trx_record_enable_all_tracks ();
2002 _session->maybe_enable_record ();
2007 case Session::Recording:
2009 _session->request_stop();
2011 _session->disable_record (false, true);
2015 case Session::Enabled:
2016 _session->disable_record (false, true);
2022 ARDOUR_UI::transport_roll ()
2028 if (_session->is_auditioning()) {
2033 if (_session->config.get_external_sync()) {
2034 switch (Config->get_sync_source()) {
2038 /* transport controlled by the master */
2044 bool rolling = _session->transport_rolling();
2046 if (_session->get_play_loop()) {
2048 /* If loop playback is not a mode, then we should cancel
2049 it when this action is requested. If it is a mode
2050 we just leave it in place.
2053 if (!Config->get_loop_is_mode()) {
2054 /* XXX it is not possible to just leave seamless loop and keep
2055 playing at present (nov 4th 2009)
2057 if (!Config->get_seamless_loop()) {
2058 /* stop loop playback and stop rolling */
2059 _session->request_play_loop (false, true);
2060 } else if (rolling) {
2061 /* stop loop playback but keep rolling */
2062 _session->request_play_loop (false, false);
2066 } else if (_session->get_play_range () ) {
2067 /* stop playing a range if we currently are */
2068 _session->request_play_range (0, true);
2072 _session->request_transport_speed (1.0f);
2077 ARDOUR_UI::get_smart_mode() const
2079 return ( editor->get_smart_mode() );
2084 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2090 if (_session->is_auditioning()) {
2091 _session->cancel_audition ();
2095 if (_session->config.get_external_sync()) {
2096 switch (Config->get_sync_source()) {
2100 /* transport controlled by the master */
2105 bool rolling = _session->transport_rolling();
2106 bool affect_transport = true;
2108 if (rolling && roll_out_of_bounded_mode) {
2109 /* drop out of loop/range playback but leave transport rolling */
2110 if (_session->get_play_loop()) {
2111 if (_session->actively_recording()) {
2113 /* just stop using the loop, then actually stop
2116 _session->request_play_loop (false, affect_transport);
2119 if (Config->get_seamless_loop()) {
2120 /* the disk buffers contain copies of the loop - we can't
2121 just keep playing, so stop the transport. the user
2122 can restart as they wish.
2124 affect_transport = true;
2126 /* disk buffers are normal, so we can keep playing */
2127 affect_transport = false;
2129 _session->request_play_loop (false, affect_transport);
2131 } else if (_session->get_play_range ()) {
2132 affect_transport = false;
2133 _session->request_play_range (0, true);
2137 if (affect_transport) {
2139 _session->request_stop (with_abort, true);
2141 /* the only external sync condition we can be in here
2142 * would be Engine (JACK) sync, in which case we still
2146 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
2147 _session->request_play_range (&editor->get_selection().time, true);
2148 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2150 _session->request_transport_speed (1.0f);
2156 ARDOUR_UI::toggle_session_auto_loop ()
2162 Location * looploc = _session->locations()->auto_loop_location();
2168 if (_session->get_play_loop()) {
2170 /* looping enabled, our job is to disable it */
2172 _session->request_play_loop (false);
2176 /* looping not enabled, our job is to enable it.
2178 loop-is-NOT-mode: this action always starts the transport rolling.
2179 loop-IS-mode: this action simply sets the loop play mechanism, but
2180 does not start transport.
2182 if (Config->get_loop_is_mode()) {
2183 _session->request_play_loop (true, false);
2185 _session->request_play_loop (true, true);
2189 //show the loop markers
2190 looploc->set_hidden (false, this);
2194 ARDOUR_UI::transport_play_selection ()
2200 editor->play_selection ();
2204 ARDOUR_UI::transport_play_preroll ()
2209 editor->play_with_preroll ();
2213 ARDOUR_UI::transport_rewind (int option)
2215 float current_transport_speed;
2218 current_transport_speed = _session->transport_speed();
2220 if (current_transport_speed >= 0.0f) {
2223 _session->request_transport_speed (-1.0f);
2226 _session->request_transport_speed (-4.0f);
2229 _session->request_transport_speed (-0.5f);
2234 _session->request_transport_speed (current_transport_speed * 1.5f);
2240 ARDOUR_UI::transport_forward (int option)
2246 float current_transport_speed = _session->transport_speed();
2248 if (current_transport_speed <= 0.0f) {
2251 _session->request_transport_speed (1.0f);
2254 _session->request_transport_speed (4.0f);
2257 _session->request_transport_speed (0.5f);
2262 _session->request_transport_speed (current_transport_speed * 1.5f);
2267 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2273 boost::shared_ptr<Route> r;
2275 if ((r = _session->route_by_remote_id (rid)) != 0) {
2277 boost::shared_ptr<Track> t;
2279 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2280 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2286 ARDOUR_UI::map_transport_state ()
2289 auto_loop_button.unset_active_state ();
2290 play_selection_button.unset_active_state ();
2291 roll_button.unset_active_state ();
2292 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2296 shuttle_box->map_transport_state ();
2298 float sp = _session->transport_speed();
2304 if (_session->get_play_range()) {
2306 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2307 roll_button.unset_active_state ();
2308 auto_loop_button.unset_active_state ();
2310 } else if (_session->get_play_loop ()) {
2312 auto_loop_button.set_active (true);
2313 play_selection_button.set_active (false);
2314 if (Config->get_loop_is_mode()) {
2315 roll_button.set_active (true);
2317 roll_button.set_active (false);
2322 roll_button.set_active (true);
2323 play_selection_button.set_active (false);
2324 auto_loop_button.set_active (false);
2327 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2328 /* light up both roll and play-selection if they are joined */
2329 roll_button.set_active (true);
2330 play_selection_button.set_active (true);
2333 stop_button.set_active (false);
2337 stop_button.set_active (true);
2338 roll_button.set_active (false);
2339 play_selection_button.set_active (false);
2340 if (Config->get_loop_is_mode ()) {
2341 auto_loop_button.set_active (_session->get_play_loop());
2343 auto_loop_button.set_active (false);
2345 update_disk_space ();
2350 ARDOUR_UI::blink_handler (bool blink_on)
2352 transport_rec_enable_blink (blink_on);
2353 solo_blink (blink_on);
2354 sync_blink (blink_on);
2355 audition_blink (blink_on);
2356 feedback_blink (blink_on);
2357 error_blink (blink_on);
2361 ARDOUR_UI::update_clocks ()
2363 if (!_session) return;
2365 if (editor && !editor->dragging_playhead()) {
2366 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2371 ARDOUR_UI::start_clocking ()
2373 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2374 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2376 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2381 ARDOUR_UI::stop_clocking ()
2383 clock_signal_connection.disconnect ();
2387 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2391 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2393 label->set_text (buf);
2394 bar->set_fraction (fraction);
2396 /* process events, redraws, etc. */
2398 while (gtk_events_pending()) {
2399 gtk_main_iteration ();
2402 return true; /* continue with save-as */
2406 ARDOUR_UI::save_session_as ()
2412 if (!save_as_dialog) {
2413 save_as_dialog = new SaveAsDialog;
2416 save_as_dialog->set_name (_session->name());
2418 int response = save_as_dialog->run ();
2420 save_as_dialog->hide ();
2423 case Gtk::RESPONSE_OK:
2432 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2433 sa.new_name = save_as_dialog->new_name ();
2434 sa.switch_to = save_as_dialog->switch_to();
2435 sa.copy_media = save_as_dialog->copy_media();
2436 sa.copy_external = save_as_dialog->copy_external();
2437 sa.include_media = save_as_dialog->include_media ();
2439 /* Only bother with a progress dialog if we're going to copy
2440 media into the save-as target. Without that choice, this
2441 will be very fast because we're only talking about a few kB's to
2442 perhaps a couple of MB's of data.
2445 ArdourDialog progress_dialog (_("Save As"), true);
2447 if (sa.include_media && sa.copy_media) {
2450 Gtk::ProgressBar progress_bar;
2452 progress_dialog.get_vbox()->pack_start (label);
2453 progress_dialog.get_vbox()->pack_start (progress_bar);
2455 progress_bar.show ();
2457 /* this signal will be emitted from within this, the calling thread,
2458 * after every file is copied. It provides information on percentage
2459 * complete (in terms of total data to copy), the number of files
2460 * copied so far, and the total number to copy.
2465 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2467 progress_dialog.show_all ();
2468 progress_dialog.present ();
2471 if (_session->save_as (sa)) {
2473 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2477 if (!sa.include_media) {
2478 unload_session (false);
2479 load_session (sa.final_session_folder_name, sa.new_name);
2484 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2488 struct tm local_time;
2491 localtime_r (&n, &local_time);
2492 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2494 save_state (timebuf, switch_to_it);
2499 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2503 prompter.get_result (snapname);
2505 bool do_save = (snapname.length() != 0);
2508 char illegal = Session::session_name_is_legal(snapname);
2510 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2511 "snapshot names may not contain a '%1' character"), illegal));
2517 vector<std::string> p;
2518 get_state_files_in_directory (_session->session_directory().root_path(), p);
2519 vector<string> n = get_file_names_no_extension (p);
2521 if (find (n.begin(), n.end(), snapname) != n.end()) {
2523 do_save = overwrite_file_dialog (prompter,
2524 _("Confirm Snapshot Overwrite"),
2525 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2529 save_state (snapname, switch_to_it);
2539 /** Ask the user for the name of a new snapshot and then take it.
2543 ARDOUR_UI::snapshot_session (bool switch_to_it)
2545 ArdourPrompter prompter (true);
2547 prompter.set_name ("Prompter");
2548 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2550 prompter.set_title (_("Save as..."));
2551 prompter.set_prompt (_("New session name"));
2553 prompter.set_title (_("Take Snapshot"));
2554 prompter.set_prompt (_("Name of new snapshot"));
2558 prompter.set_initial_text (_session->snap_name());
2562 struct tm local_time;
2565 localtime_r (&n, &local_time);
2566 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2567 prompter.set_initial_text (timebuf);
2570 bool finished = false;
2572 switch (prompter.run()) {
2573 case RESPONSE_ACCEPT:
2575 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2586 /** Ask the user for a new session name and then rename the session to it.
2590 ARDOUR_UI::rename_session ()
2596 ArdourPrompter prompter (true);
2599 prompter.set_name ("Prompter");
2600 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2601 prompter.set_title (_("Rename Session"));
2602 prompter.set_prompt (_("New session name"));
2605 switch (prompter.run()) {
2606 case RESPONSE_ACCEPT:
2608 prompter.get_result (name);
2610 bool do_rename = (name.length() != 0);
2613 char illegal = Session::session_name_is_legal (name);
2616 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2617 "session names may not contain a '%1' character"), illegal));
2622 switch (_session->rename (name)) {
2624 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2625 msg.set_position (WIN_POS_MOUSE);
2633 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2634 msg.set_position (WIN_POS_MOUSE);
2650 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2652 if (!_session || _session->deletion_in_progress()) {
2656 XMLNode* node = new XMLNode (X_("UI"));
2658 WM::Manager::instance().add_state (*node);
2660 node->add_child_nocopy (gui_object_state->get_state());
2662 _session->add_extra_xml (*node);
2664 if (export_video_dialog) {
2665 _session->add_extra_xml (export_video_dialog->get_state());
2668 save_state_canfail (name, switch_to_it);
2672 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2677 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2682 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2687 ARDOUR_UI::primary_clock_value_changed ()
2690 _session->request_locate (primary_clock->current_time ());
2695 ARDOUR_UI::big_clock_value_changed ()
2698 _session->request_locate (big_clock->current_time ());
2703 ARDOUR_UI::secondary_clock_value_changed ()
2706 _session->request_locate (secondary_clock->current_time ());
2711 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2713 if (_session == 0) {
2717 if (_session->step_editing()) {
2721 Session::RecordState const r = _session->record_status ();
2722 bool const h = _session->have_rec_enabled_track ();
2724 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2726 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2728 rec_button.set_active_state (Gtkmm2ext::Off);
2730 } else if (r == Session::Recording && h) {
2731 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2733 rec_button.unset_active_state ();
2738 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2742 prompter.get_result (name);
2744 if (name.length()) {
2745 int failed = _session->save_template (name);
2747 if (failed == -2) { /* file already exists. */
2748 bool overwrite = overwrite_file_dialog (prompter,
2749 _("Confirm Template Overwrite"),
2750 _("A template already exists with that name. Do you want to overwrite it?"));
2753 _session->save_template (name, true);
2765 ARDOUR_UI::save_template ()
2767 ArdourPrompter prompter (true);
2769 if (!check_audioengine (_main_window)) {
2773 prompter.set_name (X_("Prompter"));
2774 prompter.set_title (_("Save Template"));
2775 prompter.set_prompt (_("Name for template:"));
2776 prompter.set_initial_text(_session->name() + _("-template"));
2777 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2779 bool finished = false;
2781 switch (prompter.run()) {
2782 case RESPONSE_ACCEPT:
2783 finished = process_save_template_prompter (prompter);
2794 ARDOUR_UI::edit_metadata ()
2796 SessionMetadataEditor dialog;
2797 dialog.set_session (_session);
2798 dialog.grab_focus ();
2803 ARDOUR_UI::import_metadata ()
2805 SessionMetadataImporter dialog;
2806 dialog.set_session (_session);
2811 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2813 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2815 MessageDialog msg (str,
2817 Gtk::MESSAGE_WARNING,
2818 Gtk::BUTTONS_YES_NO,
2822 msg.set_name (X_("OpenExistingDialog"));
2823 msg.set_title (_("Open Existing Session"));
2824 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2825 msg.set_position (Gtk::WIN_POS_CENTER);
2826 pop_back_splash (msg);
2828 switch (msg.run()) {
2837 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2839 BusProfile bus_profile;
2843 bus_profile.master_out_channels = 2;
2844 bus_profile.input_ac = AutoConnectPhysical;
2845 bus_profile.output_ac = AutoConnectMaster;
2846 bus_profile.requested_physical_in = 0; // use all available
2847 bus_profile.requested_physical_out = 0; // use all available
2851 /* get settings from advanced section of NSD */
2853 if (sd.create_master_bus()) {
2854 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2856 bus_profile.master_out_channels = 0;
2859 if (sd.connect_inputs()) {
2860 bus_profile.input_ac = AutoConnectPhysical;
2862 bus_profile.input_ac = AutoConnectOption (0);
2865 bus_profile.output_ac = AutoConnectOption (0);
2867 if (sd.connect_outputs ()) {
2868 if (sd.connect_outs_to_master()) {
2869 bus_profile.output_ac = AutoConnectMaster;
2870 } else if (sd.connect_outs_to_physical()) {
2871 bus_profile.output_ac = AutoConnectPhysical;
2875 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2876 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2879 if (build_session (session_path, session_name, bus_profile)) {
2887 ARDOUR_UI::load_from_application_api (const std::string& path)
2889 ARDOUR_COMMAND_LINE::session_name = path;
2890 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2892 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2894 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2895 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2896 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2897 * -> SessionDialog is not displayed
2900 if (_session_dialog) {
2901 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2902 std::string session_path = path;
2903 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2904 session_path = Glib::path_get_dirname (session_path);
2906 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2907 _session_dialog->set_provided_session (session_name, session_path);
2908 _session_dialog->response (RESPONSE_NONE);
2909 _session_dialog->hide();
2914 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2915 /* /path/to/foo => /path/to/foo, foo */
2916 rv = load_session (path, basename_nosuffix (path));
2918 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2919 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2922 // if load_session fails -> pop up SessionDialog.
2924 ARDOUR_COMMAND_LINE::session_name = "";
2926 if (get_session_parameters (true, false)) {
2932 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2934 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2936 string session_name;
2937 string session_path;
2938 string template_name;
2940 bool likely_new = false;
2941 bool cancel_not_quit;
2943 /* deal with any existing DIRTY session now, rather than later. don't
2944 * treat a non-dirty session this way, so that it stays visible
2945 * as we bring up the new session dialog.
2948 if (_session && ARDOUR_UI::instance()->video_timeline) {
2949 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2952 /* if there is already a session, relabel the button
2953 on the SessionDialog so that we don't Quit directly
2955 cancel_not_quit = (_session != 0);
2957 if (_session && _session->dirty()) {
2958 if (unload_session (false)) {
2959 /* unload cancelled by user */
2962 ARDOUR_COMMAND_LINE::session_name = "";
2965 if (!load_template.empty()) {
2966 should_be_new = true;
2967 template_name = load_template;
2970 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2971 session_path = ARDOUR_COMMAND_LINE::session_name;
2973 if (!session_path.empty()) {
2974 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2975 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2976 /* session/snapshot file, change path to be dir */
2977 session_path = Glib::path_get_dirname (session_path);
2982 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2984 _session_dialog = &session_dialog;
2987 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2989 /* if they named a specific statefile, use it, otherwise they are
2990 just giving a session folder, and we want to use it as is
2991 to find the session.
2994 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2996 if (suffix != string::npos) {
2997 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2998 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2999 session_name = Glib::path_get_basename (session_name);
3001 session_path = ARDOUR_COMMAND_LINE::session_name;
3002 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3007 session_dialog.clear_given ();
3010 if (should_be_new || session_name.empty()) {
3011 /* need the dialog to get info from user */
3013 cerr << "run dialog\n";
3015 switch (session_dialog.run()) {
3016 case RESPONSE_ACCEPT:
3019 /* this is used for async * app->ShouldLoad(). */
3020 continue; // while loop
3023 if (quit_on_cancel) {
3024 // JE - Currently (July 2014) this section can only get reached if the
3025 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3026 // point does NOT indicate an abnormal termination). Therefore, let's
3027 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3029 pthread_cancel_all ();
3037 session_dialog.hide ();
3040 /* if we run the startup dialog again, offer more than just "new session" */
3042 should_be_new = false;
3044 session_name = session_dialog.session_name (likely_new);
3045 session_path = session_dialog.session_folder ();
3051 string::size_type suffix = session_name.find (statefile_suffix);
3053 if (suffix != string::npos) {
3054 session_name = session_name.substr (0, suffix);
3057 /* this shouldn't happen, but we catch it just in case it does */
3059 if (session_name.empty()) {
3063 if (session_dialog.use_session_template()) {
3064 template_name = session_dialog.session_template_name();
3065 _session_is_new = true;
3068 if (session_name[0] == G_DIR_SEPARATOR ||
3069 #ifdef PLATFORM_WINDOWS
3070 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3072 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3073 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3078 /* absolute path or cwd-relative path specified for session name: infer session folder
3079 from what was given.
3082 session_path = Glib::path_get_dirname (session_name);
3083 session_name = Glib::path_get_basename (session_name);
3087 session_path = session_dialog.session_folder();
3089 char illegal = Session::session_name_is_legal (session_name);
3092 MessageDialog msg (session_dialog,
3093 string_compose (_("To ensure compatibility with various systems\n"
3094 "session names may not contain a '%1' character"),
3097 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3102 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3105 if (likely_new && !nsm) {
3107 std::string existing = Glib::build_filename (session_path, session_name);
3109 if (!ask_about_loading_existing_session (existing)) {
3110 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3115 _session_is_new = false;
3120 pop_back_splash (session_dialog);
3121 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3123 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3127 char illegal = Session::session_name_is_legal(session_name);
3130 pop_back_splash (session_dialog);
3131 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3132 "session names may not contain a '%1' character"), illegal));
3134 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3138 _session_is_new = true;
3141 if (likely_new && template_name.empty()) {
3143 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3147 ret = load_session (session_path, session_name, template_name);
3150 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3154 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3155 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3159 /* clear this to avoid endless attempts to load the
3163 ARDOUR_COMMAND_LINE::session_name = "";
3167 _session_dialog = NULL;
3173 ARDOUR_UI::close_session()
3175 if (!check_audioengine (_main_window)) {
3179 if (unload_session (true)) {
3183 ARDOUR_COMMAND_LINE::session_name = "";
3185 if (get_session_parameters (true, false)) {
3190 /** @param snap_name Snapshot name (without .ardour suffix).
3191 * @return -2 if the load failed because we are not connected to the AudioEngine.
3194 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3196 Session *new_session;
3201 unload_status = unload_session ();
3203 if (unload_status < 0) {
3205 } else if (unload_status > 0) {
3211 session_loaded = false;
3213 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3216 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3219 /* this one is special */
3221 catch (AudioEngine::PortRegistrationFailure& err) {
3223 MessageDialog msg (err.what(),
3226 Gtk::BUTTONS_CLOSE);
3228 msg.set_title (_("Port Registration Error"));
3229 msg.set_secondary_text (_("Click the Close button to try again."));
3230 msg.set_position (Gtk::WIN_POS_CENTER);
3231 pop_back_splash (msg);
3234 int response = msg.run ();
3239 case RESPONSE_CANCEL:
3246 catch (SessionException e) {
3247 MessageDialog msg (string_compose(
3248 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3249 path, snap_name, e.what()),
3254 msg.set_title (_("Loading Error"));
3255 msg.set_position (Gtk::WIN_POS_CENTER);
3256 pop_back_splash (msg);
3268 MessageDialog msg (string_compose(
3269 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3275 msg.set_title (_("Loading Error"));
3276 msg.set_position (Gtk::WIN_POS_CENTER);
3277 pop_back_splash (msg);
3289 list<string> const u = new_session->unknown_processors ();
3291 MissingPluginDialog d (_session, u);
3296 if (!new_session->writable()) {
3297 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3302 msg.set_title (_("Read-only Session"));
3303 msg.set_position (Gtk::WIN_POS_CENTER);
3304 pop_back_splash (msg);
3311 /* Now the session been created, add the transport controls */
3312 new_session->add_controllable(roll_controllable);
3313 new_session->add_controllable(stop_controllable);
3314 new_session->add_controllable(goto_start_controllable);
3315 new_session->add_controllable(goto_end_controllable);
3316 new_session->add_controllable(auto_loop_controllable);
3317 new_session->add_controllable(play_selection_controllable);
3318 new_session->add_controllable(rec_controllable);
3320 set_session (new_session);
3322 session_loaded = true;
3325 _session->set_clean ();
3328 #ifdef WINDOWS_VST_SUPPORT
3329 fst_stop_threading();
3333 Timers::TimerSuspender t;
3337 #ifdef WINDOWS_VST_SUPPORT
3338 fst_start_threading();
3347 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3349 Session *new_session;
3352 session_loaded = false;
3353 x = unload_session ();
3361 _session_is_new = true;
3364 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3367 catch (SessionException e) {
3369 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3370 msg.set_title (_("Loading Error"));
3371 msg.set_position (Gtk::WIN_POS_CENTER);
3372 pop_back_splash (msg);
3378 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3379 msg.set_title (_("Loading Error"));
3380 msg.set_position (Gtk::WIN_POS_CENTER);
3381 pop_back_splash (msg);
3386 /* Give the new session the default GUI state, if such things exist */
3389 n = Config->instant_xml (X_("Editor"));
3391 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3392 new_session->add_instant_xml (*n, false);
3394 n = Config->instant_xml (X_("Mixer"));
3396 new_session->add_instant_xml (*n, false);
3399 /* Put the playhead at 0 and scroll fully left */
3400 n = new_session->instant_xml (X_("Editor"));
3402 n->add_property (X_("playhead"), X_("0"));
3403 n->add_property (X_("left-frame"), X_("0"));
3406 set_session (new_session);
3408 session_loaded = true;
3410 new_session->save_state(new_session->name());
3416 ARDOUR_UI::launch_chat ()
3418 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3420 dialog.set_title (_("About the Chat"));
3421 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."));
3423 switch (dialog.run()) {
3426 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3427 #elif defined PLATFORM_WINDOWS
3428 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3430 open_uri("http://webchat.freenode.net/?channels=ardour");
3439 ARDOUR_UI::launch_manual ()
3441 PBD::open_uri (Config->get_tutorial_manual_url());
3445 ARDOUR_UI::launch_reference ()
3447 PBD::open_uri (Config->get_reference_manual_url());
3451 ARDOUR_UI::launch_tracker ()
3453 PBD::open_uri ("http://tracker.ardour.org");
3457 ARDOUR_UI::launch_subscribe ()
3459 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3463 ARDOUR_UI::launch_cheat_sheet ()
3466 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3468 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3473 ARDOUR_UI::launch_website ()
3475 PBD::open_uri ("http://ardour.org");
3479 ARDOUR_UI::launch_website_dev ()
3481 PBD::open_uri ("http://ardour.org/development.html");
3485 ARDOUR_UI::launch_forums ()
3487 PBD::open_uri ("https://community.ardour.org/forums");
3491 ARDOUR_UI::launch_howto_report ()
3493 PBD::open_uri ("http://ardour.org/reporting_bugs");
3497 ARDOUR_UI::loading_message (const std::string& msg)
3499 if (ARDOUR_COMMAND_LINE::no_splash) {
3507 splash->message (msg);
3511 ARDOUR_UI::show_splash ()
3515 splash = new Splash;
3525 ARDOUR_UI::hide_splash ()
3532 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3536 removed = rep.paths.size();
3539 MessageDialog msgd (_main_window,
3540 _("No files were ready for clean-up"),
3544 msgd.set_title (_("Clean-up"));
3545 msgd.set_secondary_text (_("If this seems suprising, \n\
3546 check for any existing snapshots.\n\
3547 These may still include regions that\n\
3548 require some unused files to continue to exist."));
3554 ArdourDialog results (_("Clean-up"), true, false);
3556 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3557 CleanupResultsModelColumns() {
3561 Gtk::TreeModelColumn<std::string> visible_name;
3562 Gtk::TreeModelColumn<std::string> fullpath;
3566 CleanupResultsModelColumns results_columns;
3567 Glib::RefPtr<Gtk::ListStore> results_model;
3568 Gtk::TreeView results_display;
3570 results_model = ListStore::create (results_columns);
3571 results_display.set_model (results_model);
3572 results_display.append_column (list_title, results_columns.visible_name);
3574 results_display.set_name ("CleanupResultsList");
3575 results_display.set_headers_visible (true);
3576 results_display.set_headers_clickable (false);
3577 results_display.set_reorderable (false);
3579 Gtk::ScrolledWindow list_scroller;
3582 Gtk::HBox dhbox; // the hbox for the image and text
3583 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3584 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3586 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3588 const string dead_directory = _session->session_directory().dead_path();
3591 %1 - number of files removed
3592 %2 - location of "dead"
3593 %3 - size of files affected
3594 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3597 const char* bprefix;
3598 double space_adjusted = 0;
3600 if (rep.space < 1000) {
3602 space_adjusted = rep.space;
3603 } else if (rep.space < 1000000) {
3604 bprefix = _("kilo");
3605 space_adjusted = floorf((float)rep.space / 1000.0);
3606 } else if (rep.space < 1000000 * 1000) {
3607 bprefix = _("mega");
3608 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3610 bprefix = _("giga");
3611 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3615 txt.set_markup (string_compose (P_("\
3616 The following file was deleted from %2,\n\
3617 releasing %3 %4bytes of disk space", "\
3618 The following %1 files were deleted from %2,\n\
3619 releasing %3 %4bytes of disk space", removed),
3620 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3622 txt.set_markup (string_compose (P_("\
3623 The following file was not in use and \n\
3624 has been moved to: %2\n\n\
3625 After a restart of %5\n\n\
3626 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3627 will release an additional %3 %4bytes of disk space.\n", "\
3628 The following %1 files were not in use and \n\
3629 have been moved to: %2\n\n\
3630 After a restart of %5\n\n\
3631 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3632 will release an additional %3 %4bytes of disk space.\n", removed),
3633 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3636 dhbox.pack_start (*dimage, true, false, 5);
3637 dhbox.pack_start (txt, true, false, 5);
3639 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3640 TreeModel::Row row = *(results_model->append());
3641 row[results_columns.visible_name] = *i;
3642 row[results_columns.fullpath] = *i;
3645 list_scroller.add (results_display);
3646 list_scroller.set_size_request (-1, 150);
3647 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3649 dvbox.pack_start (dhbox, true, false, 5);
3650 dvbox.pack_start (list_scroller, true, false, 5);
3651 ddhbox.pack_start (dvbox, true, false, 5);
3653 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3654 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3655 results.set_default_response (RESPONSE_CLOSE);
3656 results.set_position (Gtk::WIN_POS_MOUSE);
3658 results_display.show();
3659 list_scroller.show();
3666 //results.get_vbox()->show();
3667 results.set_resizable (false);
3674 ARDOUR_UI::cleanup ()
3676 if (_session == 0) {
3677 /* shouldn't happen: menu item is insensitive */
3682 MessageDialog checker (_("Are you sure you want to clean-up?"),
3684 Gtk::MESSAGE_QUESTION,
3687 checker.set_title (_("Clean-up"));
3689 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3690 ALL undo/redo information will be lost if you clean-up.\n\
3691 Clean-up will move all unused files to a \"dead\" location."));
3693 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3694 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3695 checker.set_default_response (RESPONSE_CANCEL);
3697 checker.set_name (_("CleanupDialog"));
3698 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3699 checker.set_position (Gtk::WIN_POS_MOUSE);
3701 switch (checker.run()) {
3702 case RESPONSE_ACCEPT:
3708 ARDOUR::CleanupReport rep;
3710 editor->prepare_for_cleanup ();
3712 /* do not allow flush until a session is reloaded */
3714 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3716 act->set_sensitive (false);
3719 if (_session->cleanup_sources (rep)) {
3720 editor->finish_cleanup ();
3724 editor->finish_cleanup ();
3727 display_cleanup_results (rep, _("Cleaned Files"), false);
3731 ARDOUR_UI::flush_trash ()
3733 if (_session == 0) {
3734 /* shouldn't happen: menu item is insensitive */
3738 ARDOUR::CleanupReport rep;
3740 if (_session->cleanup_trash_sources (rep)) {
3744 display_cleanup_results (rep, _("deleted file"), true);
3748 ARDOUR_UI::cleanup_peakfiles ()
3750 if (_session == 0) {
3751 /* shouldn't happen: menu item is insensitive */
3755 if (! _session->can_cleanup_peakfiles ()) {
3759 // get all region-views in this session
3761 TrackViewList empty;
3763 editor->get_regions_after(rs, (framepos_t) 0, empty);
3764 std::list<RegionView*> views = rs.by_layer();
3766 // remove displayed audio-region-views waveforms
3767 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3768 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3769 if (!arv) { continue ; }
3770 arv->delete_waves();
3773 // cleanup peak files:
3774 // - stop pending peakfile threads
3775 // - close peakfiles if any
3776 // - remove peak dir in session
3777 // - setup peakfiles (background thread)
3778 _session->cleanup_peakfiles ();
3780 // re-add waves to ARV
3781 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3782 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3783 if (!arv) { continue ; }
3784 arv->create_waves();
3789 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3791 uint32_t order_hint = UINT32_MAX;
3793 if (editor->get_selection().tracks.empty()) {
3798 we want the new routes to have their order keys set starting from
3799 the highest order key in the selection + 1 (if available).
3802 if (place == AddRouteDialog::AfterSelection) {
3803 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3805 order_hint = rtav->route()->order_key();
3808 } else if (place == AddRouteDialog::BeforeSelection) {
3809 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3811 order_hint = rtav->route()->order_key();
3813 } else if (place == AddRouteDialog::First) {
3816 /* leave order_hint at UINT32_MAX */
3819 if (order_hint == UINT32_MAX) {
3820 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3821 * not setting an order hint will place new routes last.
3826 _session->set_order_hint (order_hint);
3828 /* create a gap in the existing route order keys to accomodate new routes.*/
3829 boost::shared_ptr <RouteList> rd = _session->get_routes();
3830 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3831 boost::shared_ptr<Route> rt (*ri);
3833 if (rt->is_monitor()) {
3837 if (rt->order_key () >= order_hint) {
3838 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3844 ARDOUR_UI::start_duplicate_routes ()
3846 if (!duplicate_routes_dialog) {
3847 duplicate_routes_dialog = new DuplicateRouteDialog;
3850 if (duplicate_routes_dialog->restart (_session)) {
3854 duplicate_routes_dialog->present ();
3858 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3866 if (add_route_dialog->is_visible()) {
3867 /* we're already doing this */
3871 ResponseType r = (ResponseType) add_route_dialog->run ();
3873 add_route_dialog->hide();
3876 case RESPONSE_ACCEPT:
3883 if ((count = add_route_dialog->count()) <= 0) {
3887 setup_order_hint(add_route_dialog->insert_at());
3889 string template_path = add_route_dialog->track_template();
3890 DisplaySuspender ds;
3892 if (!template_path.empty()) {
3893 if (add_route_dialog->name_template_is_default()) {
3894 _session->new_route_from_template (count, template_path, string());
3896 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3901 ChanCount input_chan= add_route_dialog->channels ();
3902 ChanCount output_chan;
3903 string name_template = add_route_dialog->name_template ();
3904 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3905 RouteGroup* route_group = add_route_dialog->route_group ();
3906 AutoConnectOption oac = Config->get_output_auto_connect();
3908 if (oac & AutoConnectMaster) {
3909 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3910 output_chan.set (DataType::MIDI, 0);
3912 output_chan = input_chan;
3915 /* XXX do something with name template */
3917 switch (add_route_dialog->type_wanted()) {
3918 case AddRouteDialog::AudioTrack:
3919 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3921 case AddRouteDialog::MidiTrack:
3922 session_add_midi_track (route_group, count, name_template, instrument);
3924 case AddRouteDialog::MixedTrack:
3925 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3927 case AddRouteDialog::AudioBus:
3928 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3934 ARDOUR_UI::stop_video_server (bool ask_confirm)
3936 if (!video_server_process && ask_confirm) {
3937 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3939 if (video_server_process) {
3941 ArdourDialog confirm (_("Stop Video-Server"), true);
3942 Label m (_("Do you really want to stop the Video Server?"));
3943 confirm.get_vbox()->pack_start (m, true, true);
3944 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3945 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3946 confirm.show_all ();
3947 if (confirm.run() == RESPONSE_CANCEL) {
3951 delete video_server_process;
3952 video_server_process =0;
3957 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3959 ARDOUR_UI::start_video_server( float_window, true);
3963 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3969 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3970 if (video_server_process) {
3971 popup_error(_("The Video Server is already started."));
3973 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3979 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3981 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3983 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3985 video_server_dialog->set_transient_for (*float_window);
3988 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3989 video_server_dialog->hide();
3991 ResponseType r = (ResponseType) video_server_dialog->run ();
3992 video_server_dialog->hide();
3993 if (r != RESPONSE_ACCEPT) { return false; }
3994 if (video_server_dialog->show_again()) {
3995 Config->set_show_video_server_dialog(false);
3999 std::string icsd_exec = video_server_dialog->get_exec_path();
4000 std::string icsd_docroot = video_server_dialog->get_docroot();
4001 if (icsd_docroot.empty()) {
4002 #ifndef PLATFORM_WINDOWS
4003 icsd_docroot = X_("/");
4005 icsd_docroot = X_("C:\\");
4010 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4011 warning << _("Specified docroot is not an existing directory.") << endmsg;
4014 #ifndef PLATFORM_WINDOWS
4015 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4016 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4017 warning << _("Given Video Server is not an executable file.") << endmsg;
4021 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4022 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4023 warning << _("Given Video Server is not an executable file.") << endmsg;
4029 argp=(char**) calloc(9,sizeof(char*));
4030 argp[0] = strdup(icsd_exec.c_str());
4031 argp[1] = strdup("-P");
4032 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4033 argp[3] = strdup("-p");
4034 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4035 argp[5] = strdup("-C");
4036 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4037 argp[7] = strdup(icsd_docroot.c_str());
4039 stop_video_server();
4041 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4042 Config->set_video_advanced_setup(false);
4044 std::ostringstream osstream;
4045 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4046 Config->set_video_server_url(osstream.str());
4047 Config->set_video_server_docroot(icsd_docroot);
4048 Config->set_video_advanced_setup(true);
4051 if (video_server_process) {
4052 delete video_server_process;
4055 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4056 if (video_server_process->start()) {
4057 warning << _("Cannot launch the video-server") << endmsg;
4060 int timeout = 120; // 6 sec
4061 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4062 Glib::usleep (50000);
4064 if (--timeout <= 0 || !video_server_process->is_running()) break;
4067 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4069 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4070 delete video_server_process;
4071 video_server_process = 0;
4079 ARDOUR_UI::add_video (Gtk::Window* float_window)
4085 if (!start_video_server(float_window, false)) {
4086 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4091 add_video_dialog->set_transient_for (*float_window);
4094 if (add_video_dialog->is_visible()) {
4095 /* we're already doing this */
4099 ResponseType r = (ResponseType) add_video_dialog->run ();
4100 add_video_dialog->hide();
4101 if (r != RESPONSE_ACCEPT) { return; }
4103 bool local_file, orig_local_file;
4104 std::string path = add_video_dialog->file_name(local_file);
4106 std::string orig_path = path;
4107 orig_local_file = local_file;
4109 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4111 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4112 warning << string_compose(_("could not open %1"), path) << endmsg;
4115 if (!local_file && path.length() == 0) {
4116 warning << _("no video-file selected") << endmsg;
4120 std::string audio_from_video;
4121 bool detect_ltc = false;
4123 switch (add_video_dialog->import_option()) {
4124 case VTL_IMPORT_TRANSCODE:
4126 TranscodeVideoDialog *transcode_video_dialog;
4127 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4128 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4129 transcode_video_dialog->hide();
4130 if (r != RESPONSE_ACCEPT) {
4131 delete transcode_video_dialog;
4135 audio_from_video = transcode_video_dialog->get_audiofile();
4137 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4140 else if (!audio_from_video.empty()) {
4141 editor->embed_audio_from_video(
4143 video_timeline->get_offset(),
4144 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4147 switch (transcode_video_dialog->import_option()) {
4148 case VTL_IMPORT_TRANSCODED:
4149 path = transcode_video_dialog->get_filename();
4152 case VTL_IMPORT_REFERENCE:
4155 delete transcode_video_dialog;
4158 delete transcode_video_dialog;
4162 case VTL_IMPORT_NONE:
4166 /* strip _session->session_directory().video_path() from video file if possible */
4167 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4168 path=path.substr(_session->session_directory().video_path().size());
4169 if (path.at(0) == G_DIR_SEPARATOR) {
4170 path=path.substr(1);
4174 video_timeline->set_update_session_fps(auto_set_session_fps);
4176 if (video_timeline->video_file_info(path, local_file)) {
4177 XMLNode* node = new XMLNode(X_("Videotimeline"));
4178 node->add_property (X_("Filename"), path);
4179 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4180 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4181 if (orig_local_file) {
4182 node->add_property (X_("OriginalVideoFile"), orig_path);
4184 node->remove_property (X_("OriginalVideoFile"));
4186 _session->add_extra_xml (*node);
4187 _session->set_dirty ();
4189 if (!audio_from_video.empty() && detect_ltc) {
4190 std::vector<LTCFileReader::LTCMap> ltc_seq;
4193 /* TODO ask user about TV standard (LTC alignment if any) */
4194 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4195 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4197 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4199 /* TODO seek near end of file, and read LTC until end.
4200 * if it fails to find any LTC frames, scan complete file
4202 * calculate drift of LTC compared to video-duration,
4203 * ask user for reference (timecode from start/mid/end)
4206 // LTCFileReader will have written error messages
4209 ::g_unlink(audio_from_video.c_str());
4211 if (ltc_seq.size() == 0) {
4212 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4214 /* the very first TC in the file is somteimes not aligned properly */
4215 int i = ltc_seq.size() -1;
4216 ARDOUR::frameoffset_t video_start_offset =
4217 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4218 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4219 video_timeline->set_offset(video_start_offset);
4223 _session->maybe_update_session_range(
4224 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4225 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4228 if (add_video_dialog->launch_xjadeo() && local_file) {
4229 editor->set_xjadeo_sensitive(true);
4230 editor->toggle_xjadeo_proc(1);
4232 editor->toggle_xjadeo_proc(0);
4234 editor->toggle_ruler_video(true);
4239 ARDOUR_UI::remove_video ()
4241 video_timeline->close_session();
4242 editor->toggle_ruler_video(false);
4245 video_timeline->set_offset_locked(false);
4246 video_timeline->set_offset(0);
4248 /* delete session state */
4249 XMLNode* node = new XMLNode(X_("Videotimeline"));
4250 _session->add_extra_xml(*node);
4251 node = new XMLNode(X_("Videomonitor"));
4252 _session->add_extra_xml(*node);
4253 node = new XMLNode(X_("Videoexport"));
4254 _session->add_extra_xml(*node);
4255 stop_video_server();
4259 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4261 if (localcacheonly) {
4262 video_timeline->vmon_update();
4264 video_timeline->flush_cache();
4266 editor->queue_visual_videotimeline_update();
4270 ARDOUR_UI::export_video (bool range)
4272 if (ARDOUR::Config->get_show_video_export_info()) {
4273 ExportVideoInfobox infobox (_session);
4274 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4275 if (infobox.show_again()) {
4276 ARDOUR::Config->set_show_video_export_info(false);
4279 case GTK_RESPONSE_YES:
4280 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4286 export_video_dialog->set_session (_session);
4287 export_video_dialog->apply_state(editor->get_selection().time, range);
4288 export_video_dialog->run ();
4289 export_video_dialog->hide ();
4293 ARDOUR_UI::mixer_settings () const
4298 node = _session->instant_xml(X_("Mixer"));
4300 node = Config->instant_xml(X_("Mixer"));
4304 node = new XMLNode (X_("Mixer"));
4311 ARDOUR_UI::main_window_settings () const
4316 node = _session->instant_xml(X_("Main"));
4318 node = Config->instant_xml(X_("Main"));
4322 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4323 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4328 node = new XMLNode (X_("Main"));
4335 ARDOUR_UI::editor_settings () const
4340 node = _session->instant_xml(X_("Editor"));
4342 node = Config->instant_xml(X_("Editor"));
4346 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4347 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4352 node = new XMLNode (X_("Editor"));
4359 ARDOUR_UI::keyboard_settings () const
4363 node = Config->extra_xml(X_("Keyboard"));
4366 node = new XMLNode (X_("Keyboard"));
4373 ARDOUR_UI::create_xrun_marker (framepos_t where)
4376 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4377 _session->locations()->add (location);
4382 ARDOUR_UI::halt_on_xrun_message ()
4384 cerr << "HALT on xrun\n";
4385 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4390 ARDOUR_UI::xrun_handler (framepos_t where)
4396 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4398 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4399 create_xrun_marker(where);
4402 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4403 halt_on_xrun_message ();
4408 ARDOUR_UI::disk_overrun_handler ()
4410 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4412 if (!have_disk_speed_dialog_displayed) {
4413 have_disk_speed_dialog_displayed = true;
4414 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4415 The disk system on your computer\n\
4416 was not able to keep up with %1.\n\
4418 Specifically, it failed to write data to disk\n\
4419 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4420 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4426 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4427 static MessageDialog *scan_dlg = NULL;
4428 static ProgressBar *scan_pbar = NULL;
4429 static HBox *scan_tbox = NULL;
4430 static Gtk::Button *scan_timeout_button;
4433 ARDOUR_UI::cancel_plugin_scan ()
4435 PluginManager::instance().cancel_plugin_scan();
4439 ARDOUR_UI::cancel_plugin_timeout ()
4441 PluginManager::instance().cancel_plugin_timeout();
4442 scan_timeout_button->set_sensitive (false);
4446 ARDOUR_UI::plugin_scan_timeout (int timeout)
4448 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4452 scan_pbar->set_sensitive (false);
4453 scan_timeout_button->set_sensitive (true);
4454 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4457 scan_pbar->set_sensitive (false);
4458 scan_timeout_button->set_sensitive (false);
4464 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4466 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4470 const bool cancelled = PluginManager::instance().cancelled();
4471 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4472 if (cancelled && scan_dlg->is_mapped()) {
4477 if (cancelled || !can_cancel) {
4482 static Gtk::Button *cancel_button;
4484 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4485 VBox* vbox = scan_dlg->get_vbox();
4486 vbox->set_size_request(400,-1);
4487 scan_dlg->set_title (_("Scanning for plugins"));
4489 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4490 cancel_button->set_name ("EditorGTKButton");
4491 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4492 cancel_button->show();
4494 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4496 scan_tbox = manage( new HBox() );
4498 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4499 scan_timeout_button->set_name ("EditorGTKButton");
4500 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4501 scan_timeout_button->show();
4503 scan_pbar = manage(new ProgressBar());
4504 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4505 scan_pbar->set_text(_("Scan Timeout"));
4508 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4509 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4511 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4514 assert(scan_dlg && scan_tbox && cancel_button);
4516 if (type == X_("closeme")) {
4520 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4523 if (!can_cancel || !cancelled) {
4524 scan_timeout_button->set_sensitive(false);
4526 cancel_button->set_sensitive(can_cancel && !cancelled);
4532 ARDOUR_UI::gui_idle_handler ()
4535 /* due to idle calls, gtk_events_pending() may always return true */
4536 while (gtk_events_pending() && --timeout) {
4537 gtk_main_iteration ();
4542 ARDOUR_UI::disk_underrun_handler ()
4544 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4546 if (!have_disk_speed_dialog_displayed) {
4547 have_disk_speed_dialog_displayed = true;
4548 MessageDialog* msg = new MessageDialog (
4549 _main_window, string_compose (_("The disk system on your computer\n\
4550 was not able to keep up with %1.\n\
4552 Specifically, it failed to read data from disk\n\
4553 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4554 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4560 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4562 have_disk_speed_dialog_displayed = false;
4567 ARDOUR_UI::session_dialog (std::string msg)
4569 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4573 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4580 ARDOUR_UI::pending_state_dialog ()
4582 HBox* hbox = manage (new HBox());
4583 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4584 ArdourDialog dialog (_("Crash Recovery"), true);
4585 Label message (string_compose (_("\
4586 This session appears to have been in the\n\
4587 middle of recording when %1 or\n\
4588 the computer was shutdown.\n\
4590 %1 can recover any captured audio for\n\
4591 you, or it can ignore it. Please decide\n\
4592 what you would like to do.\n"), PROGRAM_NAME));
4593 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4594 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4595 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4596 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4597 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4598 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4599 dialog.set_default_response (RESPONSE_ACCEPT);
4600 dialog.set_position (WIN_POS_CENTER);
4605 switch (dialog.run ()) {
4606 case RESPONSE_ACCEPT:
4614 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4616 HBox* hbox = new HBox();
4617 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4618 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4619 Label message (string_compose (_("\
4620 This session was created with a sample rate of %1 Hz, but\n\
4621 %2 is currently running at %3 Hz. If you load this session,\n\
4622 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4624 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4625 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4626 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4627 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4628 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4629 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4630 dialog.set_default_response (RESPONSE_ACCEPT);
4631 dialog.set_position (WIN_POS_CENTER);
4636 switch (dialog.run()) {
4637 case RESPONSE_ACCEPT:
4647 ARDOUR_UI::use_config ()
4649 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4651 set_transport_controllable_state (*node);
4656 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4658 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4659 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4661 primary_clock->set (pos);
4664 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4665 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4667 secondary_clock->set (pos);
4670 if (big_clock_window) {
4671 big_clock->set (pos);
4673 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4677 ARDOUR_UI::step_edit_status_change (bool yn)
4679 // XXX should really store pre-step edit status of things
4680 // we make insensitive
4683 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4684 rec_button.set_sensitive (false);
4686 rec_button.unset_active_state ();;
4687 rec_button.set_sensitive (true);
4692 ARDOUR_UI::record_state_changed ()
4694 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4696 if (!_session || !big_clock_window) {
4697 /* why bother - the clock isn't visible */
4701 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4702 big_clock->set_active (true);
4704 big_clock->set_active (false);
4709 ARDOUR_UI::first_idle ()
4712 _session->allow_auto_play (true);
4716 editor->first_idle();
4719 Keyboard::set_can_save_keybindings (true);
4724 ARDOUR_UI::store_clock_modes ()
4726 XMLNode* node = new XMLNode(X_("ClockModes"));
4728 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4729 XMLNode* child = new XMLNode (X_("Clock"));
4731 child->add_property (X_("name"), (*x)->name());
4732 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4733 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4735 node->add_child_nocopy (*child);
4738 _session->add_extra_xml (*node);
4739 _session->set_dirty ();
4742 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4743 : Controllable (name), ui (u), type(tp)
4749 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4752 /* do nothing: these are radio-style actions */
4756 const char *action = 0;
4760 action = X_("Roll");
4763 action = X_("Stop");
4766 action = X_("GotoStart");
4769 action = X_("GotoEnd");
4772 action = X_("Loop");
4775 action = X_("PlaySelection");
4778 action = X_("Record");
4788 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4796 ARDOUR_UI::TransportControllable::get_value (void) const
4823 ARDOUR_UI::setup_profile ()
4825 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4826 Profile->set_small_screen ();
4829 if (g_getenv ("TRX")) {
4830 Profile->set_trx ();
4833 if (g_getenv ("MIXBUS")) {
4834 Profile->set_mixbus ();
4839 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4841 MissingFileDialog dialog (s, str, type);
4846 int result = dialog.run ();
4853 return 1; // quit entire session load
4856 result = dialog.get_action ();
4862 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4864 AmbiguousFileDialog dialog (file, hits);
4871 return dialog.get_which ();
4874 /** Allocate our thread-local buffers */
4876 ARDOUR_UI::get_process_buffers ()
4878 _process_thread->get_buffers ();
4881 /** Drop our thread-local buffers */
4883 ARDOUR_UI::drop_process_buffers ()
4885 _process_thread->drop_buffers ();
4889 ARDOUR_UI::feedback_detected ()
4891 _feedback_exists = true;
4895 ARDOUR_UI::successful_graph_sort ()
4897 _feedback_exists = false;
4901 ARDOUR_UI::midi_panic ()
4904 _session->midi_panic();
4909 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4911 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4912 const char* end_big = "</span>";
4913 const char* start_mono = "<tt>";
4914 const char* end_mono = "</tt>";
4916 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4917 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4918 "From now on, use the -2000 version with older versions of %3"),
4919 xml_path, backup_path, PROGRAM_NAME,
4921 start_mono, end_mono), true);
4928 ARDOUR_UI::reset_peak_display ()
4930 if (!_session || !_session->master_out() || !editor_meter) return;
4931 editor_meter->clear_meters();
4932 editor_meter_max_peak = -INFINITY;
4933 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4937 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4939 if (!_session || !_session->master_out()) return;
4940 if (group == _session->master_out()->route_group()) {
4941 reset_peak_display ();
4946 ARDOUR_UI::reset_route_peak_display (Route* route)
4948 if (!_session || !_session->master_out()) return;
4949 if (_session->master_out().get() == route) {
4950 reset_peak_display ();
4955 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4957 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4958 audio_midi_setup->set_position (WIN_POS_CENTER);
4963 response = audio_midi_setup->run();
4965 case Gtk::RESPONSE_OK:
4966 if (!AudioEngine::instance()->running()) {
4980 ARDOUR_UI::transport_numpad_timeout ()
4982 _numpad_locate_happening = false;
4983 if (_numpad_timeout_connection.connected() )
4984 _numpad_timeout_connection.disconnect();
4989 ARDOUR_UI::transport_numpad_decimal ()
4991 _numpad_timeout_connection.disconnect();
4993 if (_numpad_locate_happening) {
4994 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4995 _numpad_locate_happening = false;
4997 _pending_locate_num = 0;
4998 _numpad_locate_happening = true;
4999 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5004 ARDOUR_UI::transport_numpad_event (int num)
5006 if ( _numpad_locate_happening ) {
5007 _pending_locate_num = _pending_locate_num*10 + num;
5010 case 0: toggle_roll(false, false); break;
5011 case 1: transport_rewind(1); break;
5012 case 2: transport_forward(1); break;
5013 case 3: transport_record(true); break;
5014 case 4: toggle_session_auto_loop(); break;
5015 case 5: transport_record(false); toggle_session_auto_loop(); break;
5016 case 6: toggle_punch(); break;
5017 case 7: toggle_click(); break;
5018 case 8: toggle_auto_return(); break;
5019 case 9: toggle_follow_edits(); break;
5025 ARDOUR_UI::set_flat_buttons ()
5027 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5031 ARDOUR_UI::audioengine_became_silent ()
5033 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5035 Gtk::MESSAGE_WARNING,
5039 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5041 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5042 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5043 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5044 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5045 Gtk::HBox pay_button_box;
5046 Gtk::HBox subscribe_button_box;
5048 pay_button_box.pack_start (pay_button, true, false);
5049 subscribe_button_box.pack_start (subscribe_button, true, false);
5051 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 */
5053 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5054 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5056 msg.get_vbox()->pack_start (pay_label);
5057 msg.get_vbox()->pack_start (pay_button_box);
5058 msg.get_vbox()->pack_start (subscribe_label);
5059 msg.get_vbox()->pack_start (subscribe_button_box);
5061 msg.get_vbox()->show_all ();
5063 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5064 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5065 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5070 case Gtk::RESPONSE_YES:
5071 AudioEngine::instance()->reset_silence_countdown ();
5074 case Gtk::RESPONSE_NO:
5076 save_state_canfail ("");
5080 case Gtk::RESPONSE_CANCEL:
5082 /* don't reset, save session and exit */
5088 ARDOUR_UI::hide_application ()
5090 Application::instance ()-> hide ();
5094 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5096 /* icons, titles, WM stuff */
5098 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5100 if (window_icons.empty()) {
5101 Glib::RefPtr<Gdk::Pixbuf> icon;
5102 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5103 window_icons.push_back (icon);
5105 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5106 window_icons.push_back (icon);
5108 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5109 window_icons.push_back (icon);
5111 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5112 window_icons.push_back (icon);
5116 if (!window_icons.empty()) {
5117 window.set_default_icon_list (window_icons);
5120 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5122 if (!name.empty()) {
5126 window.set_title (title.get_string());
5127 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5129 window.set_flags (CAN_FOCUS);
5130 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5132 /* This is a hack to ensure that GTK-accelerators continue to
5133 * work. Once we switch over to entirely native bindings, this will be
5134 * unnecessary and should be removed
5136 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5138 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5139 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5140 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5141 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5145 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5147 Gtkmm2ext::Bindings* bindings = 0;
5148 Gtk::Window* window = 0;
5150 /* until we get ardour bindings working, we are not handling key
5154 if (ev->type != GDK_KEY_PRESS) {
5158 if (event_window == &_main_window) {
5160 window = event_window;
5162 /* find current tab contents */
5164 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5166 /* see if it uses the ardour binding system */
5169 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5172 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5176 window = event_window;
5178 /* see if window uses ardour binding system */
5180 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5183 /* An empty binding set is treated as if it doesn't exist */
5185 if (bindings && bindings->empty()) {
5189 return key_press_focus_accelerator_handler (*window, ev, bindings);
5193 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5195 GtkWindow* win = window.gobj();
5196 GtkWidget* focus = gtk_window_get_focus (win);
5197 bool special_handling_of_unmodified_accelerators = false;
5198 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5202 /* some widget has keyboard focus */
5204 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5206 /* A particular kind of focusable widget currently has keyboard
5207 * focus. All unmodified key events should go to that widget
5208 * first and not be used as an accelerator by default
5211 special_handling_of_unmodified_accelerators = true;
5215 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",
5218 show_gdk_event_state (ev->state),
5219 special_handling_of_unmodified_accelerators,
5220 Keyboard::some_magic_widget_has_focus(),
5222 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5223 ((ev->state & mask) ? "yes" : "no")));
5225 /* This exists to allow us to override the way GTK handles
5226 key events. The normal sequence is:
5228 a) event is delivered to a GtkWindow
5229 b) accelerators/mnemonics are activated
5230 c) if (b) didn't handle the event, propagate to
5231 the focus widget and/or focus chain
5233 The problem with this is that if the accelerators include
5234 keys without modifiers, such as the space bar or the
5235 letter "e", then pressing the key while typing into
5236 a text entry widget results in the accelerator being
5237 activated, instead of the desired letter appearing
5240 There is no good way of fixing this, but this
5241 represents a compromise. The idea is that
5242 key events involving modifiers (not Shift)
5243 get routed into the activation pathway first, then
5244 get propagated to the focus widget if necessary.
5246 If the key event doesn't involve modifiers,
5247 we deliver to the focus widget first, thus allowing
5248 it to get "normal text" without interference
5251 Of course, this can also be problematic: if there
5252 is a widget with focus, then it will swallow
5253 all "normal text" accelerators.
5257 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5259 /* no special handling or there are modifiers in effect: accelerate first */
5261 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5262 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5263 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5265 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5266 KeyboardKey k (ev->state, ev->keyval);
5270 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5272 if (bindings->activate (k, Bindings::Press)) {
5273 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5278 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5280 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5281 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5285 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5287 if (gtk_window_propagate_key_event (win, ev)) {
5288 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5294 /* no modifiers, propagate first */
5296 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5298 if (gtk_window_propagate_key_event (win, ev)) {
5299 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5303 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5304 KeyboardKey k (ev->state, ev->keyval);
5308 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5311 if (bindings->activate (k, Bindings::Press)) {
5312 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5318 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5320 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5321 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5326 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5331 ARDOUR_UI::load_bindings ()
5333 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5334 error << _("Global keybindings are missing") << endmsg;
5339 ARDOUR_UI::cancel_solo ()
5342 if (_session->soloing()) {
5343 _session->set_solo (_session->get_routes(), false);
5344 } else if (_session->listening()) {
5345 _session->set_listen (_session->get_routes(), false);
5348 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window