2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #ifdef WINDOWS_VST_SUPPORT
97 #ifdef AUDIOUNIT_SUPPORT
98 #include "ardour/audio_unit.h"
101 #include "timecode/time.h"
103 typedef uint64_t microseconds_t;
108 #include "add_route_dialog.h"
109 #include "ambiguous_file_dialog.h"
110 #include "ardour_ui.h"
111 #include "audio_clock.h"
112 #include "audio_region_view.h"
113 #include "big_clock_window.h"
114 #include "bundle_manager.h"
115 #include "duplicate_routes_dialog.h"
117 #include "engine_dialog.h"
118 #include "export_video_dialog.h"
119 #include "export_video_infobox.h"
120 #include "gain_meter.h"
121 #include "global_port_matrix.h"
122 #include "gui_object.h"
123 #include "gui_thread.h"
124 #include "keyboard.h"
125 #include "keyeditor.h"
126 #include "location_ui.h"
127 #include "main_clock.h"
128 #include "missing_file_dialog.h"
129 #include "missing_plugin_dialog.h"
130 #include "mixer_ui.h"
131 #include "meterbridge.h"
132 #include "mouse_cursors.h"
135 #include "pingback.h"
136 #include "processor_box.h"
137 #include "prompter.h"
138 #include "public_editor.h"
139 #include "rc_option_editor.h"
140 #include "route_time_axis.h"
141 #include "route_params_ui.h"
142 #include "save_as_dialog.h"
143 #include "session_dialog.h"
144 #include "session_metadata_dialog.h"
145 #include "session_option_editor.h"
146 #include "shuttle_control.h"
147 #include "speaker_dialog.h"
150 #include "theme_manager.h"
151 #include "time_axis_view_item.h"
154 #include "video_server_dialog.h"
155 #include "add_video_dialog.h"
156 #include "transcode_video_dialog.h"
160 using namespace ARDOUR;
161 using namespace ARDOUR_UI_UTILS;
163 using namespace Gtkmm2ext;
166 using namespace Editing;
168 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
170 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
171 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
174 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
176 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
177 "Would you like these files to be copied and used for %1 %2.x?\n\n"
178 "(This will require you to restart %1.)"),
179 PROGRAM_NAME, PROGRAM_VERSION, version),
180 false, /* no markup */
183 true /* modal, though it hardly matters since it is the only window */
186 msg.set_default_response (Gtk::RESPONSE_YES);
189 return (msg.run() == Gtk::RESPONSE_YES);
193 libxml_generic_error_func (void* /* parsing_context*/,
201 vsnprintf (buf, sizeof (buf), msg, ap);
202 error << buf << endmsg;
207 libxml_structured_error_func (void* /* parsing_context*/,
215 replace_all (msg, "\n", "");
217 if (err->file && err->line) {
218 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
221 error << ':' << err->int2;
228 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
231 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
233 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
234 >>>>>>> first compilable version of tabbable design.
235 , session_loaded (false)
236 , gui_object_state (new GUIObjectState)
237 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
238 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
239 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
241 , ignore_dual_punch (false)
246 , _mixer_on_top (false)
247 , _initial_verbose_plugin_scan (false)
248 , first_time_engine_run (true)
249 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
250 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
251 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
252 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
253 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
254 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
255 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
256 , auto_return_button (ArdourButton::led_default_elements)
257 , follow_edits_button (ArdourButton::led_default_elements)
258 , auto_input_button (ArdourButton::led_default_elements)
259 , auditioning_alert_button (_("Audition"))
260 , solo_alert_button (_("Solo"))
261 , feedback_alert_button (_("Feedback"))
262 , error_alert_button ( ArdourButton::just_led_default_elements )
264 , editor_meter_peak_display()
265 , _numpad_locate_happening (false)
266 , _session_is_new (false)
267 , last_key_press_time (0)
270 , rc_option_editor (0)
271 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
272 , key_editor (X_("key-editor"), _("Key Bindings"))
273 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
274 , about (X_("about"), _("About"))
275 , location_ui (X_("locations"), _("Locations"))
276 , route_params (X_("inspector"), _("Tracks and Busses"))
277 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
278 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
279 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
280 , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
281 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
282 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
283 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
284 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
285 , video_server_process (0)
287 , have_configure_timeout (false)
288 , last_configure_time (0)
290 , have_disk_speed_dialog_displayed (false)
291 , _status_bar_visibility (X_("status-bar"))
292 , _feedback_exists (false)
293 , _log_not_acknowledged (LogLevelNone)
294 , duplicate_routes_dialog (0)
296 Gtkmm2ext::init (localedir);
298 UIConfiguration::instance().post_gui_init ();
300 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
301 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
303 /* configuration was modified, exit immediately */
307 if (theArdourUI == 0) {
311 /* stop libxml from spewing to stdout/stderr */
313 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
314 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
316 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
317 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
318 UIConfiguration::instance().map_parameters (pc);
320 roll_button.set_controllable (roll_controllable);
321 stop_button.set_controllable (stop_controllable);
322 goto_start_button.set_controllable (goto_start_controllable);
323 goto_end_button.set_controllable (goto_end_controllable);
324 auto_loop_button.set_controllable (auto_loop_controllable);
325 play_selection_button.set_controllable (play_selection_controllable);
326 rec_button.set_controllable (rec_controllable);
328 roll_button.set_name ("transport button");
329 stop_button.set_name ("transport button");
330 goto_start_button.set_name ("transport button");
331 goto_end_button.set_name ("transport button");
332 auto_loop_button.set_name ("transport button");
333 play_selection_button.set_name ("transport button");
334 rec_button.set_name ("transport recenable button");
335 midi_panic_button.set_name ("transport button");
337 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
338 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
340 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
342 /* handle dialog requests */
344 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
346 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
348 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
350 /* handle Audio/MIDI setup when session requires it */
352 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
354 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
356 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
358 /* handle requests to quit (coming from JACK session) */
360 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
362 /* tell the user about feedback */
364 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
365 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
367 /* handle requests to deal with missing files */
369 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
371 /* and ambiguous files */
373 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
375 /* also plugin scan messages */
376 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
377 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
379 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
381 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
384 /* lets get this party started */
386 setup_gtk_ardour_enums ();
389 SessionEvent::create_per_thread_pool ("GUI", 4096);
391 /* we like keyboards */
393 keyboard = new ArdourKeyboard(*this);
395 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
397 keyboard->set_state (*node, Stateful::loading_state_version);
400 /* we don't like certain modifiers */
401 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
403 UIConfiguration::instance().reset_dpi ();
405 TimeAxisViewItem::set_constant_heights ();
407 /* Set this up so that our window proxies can register actions */
409 ActionManager::init ();
411 /* The following must happen after ARDOUR::init() so that Config is set up */
413 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
416 key_editor.set_state (*ui_xml, 0);
417 session_option_editor.set_state (*ui_xml, 0);
418 speaker_config_window.set_state (*ui_xml, 0);
419 about.set_state (*ui_xml, 0);
420 add_route_dialog.set_state (*ui_xml, 0);
421 add_video_dialog.set_state (*ui_xml, 0);
422 route_params.set_state (*ui_xml, 0);
423 bundle_manager.set_state (*ui_xml, 0);
424 location_ui.set_state (*ui_xml, 0);
425 big_clock_window.set_state (*ui_xml, 0);
426 audio_port_matrix.set_state (*ui_xml, 0);
427 midi_port_matrix.set_state (*ui_xml, 0);
428 export_video_dialog.set_state (*ui_xml, 0);
431 /* Separate windows */
433 WM::Manager::instance().register_window (&key_editor);
434 WM::Manager::instance().register_window (&session_option_editor);
435 WM::Manager::instance().register_window (&speaker_config_window);
436 WM::Manager::instance().register_window (&about);
437 WM::Manager::instance().register_window (&add_route_dialog);
438 WM::Manager::instance().register_window (&add_video_dialog);
439 WM::Manager::instance().register_window (&route_params);
440 WM::Manager::instance().register_window (&audio_midi_setup);
441 WM::Manager::instance().register_window (&export_video_dialog);
442 WM::Manager::instance().register_window (&bundle_manager);
443 WM::Manager::instance().register_window (&location_ui);
444 WM::Manager::instance().register_window (&big_clock_window);
445 WM::Manager::instance().register_window (&audio_port_matrix);
446 WM::Manager::instance().register_window (&midi_port_matrix);
448 /* Trigger setting up the color scheme and loading the GTK RC file */
450 UIConfiguration::instance().load_rc_file (false);
452 _process_thread = new ProcessThread ();
453 _process_thread->init ();
455 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
460 GlobalPortMatrixWindow*
461 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
466 return new GlobalPortMatrixWindow (_session, type);
470 ARDOUR_UI::attach_to_engine ()
472 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
473 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
477 ARDOUR_UI::engine_stopped ()
479 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
480 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
481 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
482 update_sample_rate (0);
487 ARDOUR_UI::engine_running ()
489 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
490 if (first_time_engine_run) {
492 first_time_engine_run = false;
496 _session->reset_xrun_count ();
498 update_disk_space ();
500 update_xrun_count ();
501 update_sample_rate (AudioEngine::instance()->sample_rate());
502 update_timecode_format ();
503 update_peak_thread_work ();
504 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
505 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
509 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
511 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
512 /* we can't rely on the original string continuing to exist when we are called
513 again in the GUI thread, so make a copy and note that we need to
516 char *copy = strdup (reason);
517 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
521 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
522 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
524 update_sample_rate (0);
528 /* if the reason is a non-empty string, it means that the backend was shutdown
529 rather than just Ardour.
532 if (strlen (reason)) {
533 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
535 msgstr = string_compose (_("\
536 The audio backend has either been shutdown or it\n\
537 disconnected %1 because %1\n\
538 was not fast enough. Try to restart\n\
539 the audio backend and save the session."), PROGRAM_NAME);
542 MessageDialog msg (_main_window, msgstr);
543 pop_back_splash (msg);
547 free (const_cast<char*> (reason));
552 ARDOUR_UI::post_engine ()
554 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
556 #ifdef AUDIOUNIT_SUPPORT
558 if (AUPluginInfo::au_get_crashlog(au_msg)) {
559 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
560 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
561 info << au_msg << endmsg;
565 ARDOUR::init_post_engine ();
567 /* connect to important signals */
569 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
570 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
571 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
572 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
573 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
575 if (setup_windows ()) {
576 throw failed_constructor ();
579 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
580 XMLNode* n = Config->extra_xml (X_("UI"));
582 _status_bar_visibility.set_state (*n);
585 check_memory_locking();
587 /* this is the first point at which all the keybindings are available */
589 if (ARDOUR_COMMAND_LINE::show_key_actions) {
590 vector<string> names;
591 vector<string> paths;
592 vector<string> tooltips;
594 vector<AccelKey> bindings;
596 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
598 vector<string>::iterator n;
599 vector<string>::iterator k;
600 vector<string>::iterator p;
601 for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
602 cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
605 halt_connection.disconnect ();
606 AudioEngine::instance()->stop ();
610 /* this being a GUI and all, we want peakfiles */
612 AudioFileSource::set_build_peakfiles (true);
613 AudioFileSource::set_build_missing_peakfiles (true);
615 /* set default clock modes */
617 if (Profile->get_sae()) {
618 primary_clock->set_mode (AudioClock::BBT);
619 secondary_clock->set_mode (AudioClock::MinSec);
621 primary_clock->set_mode (AudioClock::Timecode);
622 secondary_clock->set_mode (AudioClock::BBT);
625 /* start the time-of-day-clock */
628 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
629 update_wall_clock ();
630 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
635 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
636 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
637 Config->map_parameters (pc);
639 UIConfiguration::instance().map_parameters (pc);
643 ARDOUR_UI::~ARDOUR_UI ()
645 UIConfiguration::instance().save_state();
649 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
650 // don't bother at 'real' exit. the OS cleans up for us.
652 delete primary_clock;
653 delete secondary_clock;
654 delete _process_thread;
659 delete gui_object_state;
660 FastMeter::flush_pattern_cache ();
661 PixFader::flush_pattern_cache ();
665 /* Small trick to flush main-thread event pool.
666 * Other thread-pools are destroyed at pthread_exit(),
667 * but tmain thread termination is too late to trigger Pool::~Pool()
669 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.
670 delete ev->event_pool();
675 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
677 if (Splash::instance()) {
678 Splash::instance()->pop_back_for (win);
683 ARDOUR_UI::configure_timeout ()
685 if (last_configure_time == 0) {
686 /* no configure events yet */
690 /* force a gap of 0.5 seconds since the last configure event
693 if (get_microseconds() - last_configure_time < 500000) {
696 have_configure_timeout = false;
697 save_ardour_state ();
703 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
705 if (have_configure_timeout) {
706 last_configure_time = get_microseconds();
708 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
709 have_configure_timeout = true;
716 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
718 const XMLProperty* prop;
720 if ((prop = node.property ("roll")) != 0) {
721 roll_controllable->set_id (prop->value());
723 if ((prop = node.property ("stop")) != 0) {
724 stop_controllable->set_id (prop->value());
726 if ((prop = node.property ("goto-start")) != 0) {
727 goto_start_controllable->set_id (prop->value());
729 if ((prop = node.property ("goto-end")) != 0) {
730 goto_end_controllable->set_id (prop->value());
732 if ((prop = node.property ("auto-loop")) != 0) {
733 auto_loop_controllable->set_id (prop->value());
735 if ((prop = node.property ("play-selection")) != 0) {
736 play_selection_controllable->set_id (prop->value());
738 if ((prop = node.property ("rec")) != 0) {
739 rec_controllable->set_id (prop->value());
741 if ((prop = node.property ("shuttle")) != 0) {
742 shuttle_box->controllable()->set_id (prop->value());
747 ARDOUR_UI::get_transport_controllable_state ()
749 XMLNode* node = new XMLNode(X_("TransportControllables"));
752 roll_controllable->id().print (buf, sizeof (buf));
753 node->add_property (X_("roll"), buf);
754 stop_controllable->id().print (buf, sizeof (buf));
755 node->add_property (X_("stop"), buf);
756 goto_start_controllable->id().print (buf, sizeof (buf));
757 node->add_property (X_("goto_start"), buf);
758 goto_end_controllable->id().print (buf, sizeof (buf));
759 node->add_property (X_("goto_end"), buf);
760 auto_loop_controllable->id().print (buf, sizeof (buf));
761 node->add_property (X_("auto_loop"), buf);
762 play_selection_controllable->id().print (buf, sizeof (buf));
763 node->add_property (X_("play_selection"), buf);
764 rec_controllable->id().print (buf, sizeof (buf));
765 node->add_property (X_("rec"), buf);
766 shuttle_box->controllable()->id().print (buf, sizeof (buf));
767 node->add_property (X_("shuttle"), buf);
773 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
776 _session->save_state (snapshot_name);
781 ARDOUR_UI::autosave_session ()
783 if (g_main_depth() > 1) {
784 /* inside a recursive main loop,
785 give up because we may not be able to
791 if (!Config->get_periodic_safety_backups()) {
796 _session->maybe_write_autosave();
803 ARDOUR_UI::session_dirty_changed ()
810 ARDOUR_UI::update_autosave ()
812 if (_session && _session->dirty()) {
813 if (_autosave_connection.connected()) {
814 _autosave_connection.disconnect();
817 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
818 Config->get_periodic_safety_backup_interval() * 1000);
821 if (_autosave_connection.connected()) {
822 _autosave_connection.disconnect();
828 ARDOUR_UI::check_announcements ()
831 string _annc_filename;
834 _annc_filename = PROGRAM_NAME "_announcements_osx_";
835 #elif defined PLATFORM_WINDOWS
836 _annc_filename = PROGRAM_NAME "_announcements_windows_";
838 _annc_filename = PROGRAM_NAME "_announcements_linux_";
840 _annc_filename.append (VERSIONSTRING);
842 _announce_string = "";
844 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
845 FILE* fin = g_fopen (path.c_str(), "rb");
847 while (!feof (fin)) {
850 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
853 _announce_string.append (tmp, len);
858 pingback (VERSIONSTRING, path);
863 ARDOUR_UI::starting ()
865 Application* app = Application::instance ();
867 bool brand_new_user = ArdourStartup::required ();
869 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
870 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
872 if (ARDOUR_COMMAND_LINE::check_announcements) {
873 check_announcements ();
878 /* we need to create this early because it may need to set the
879 * audio backend end up.
883 audio_midi_setup.get (true);
885 std::cerr << "audio-midi engine setup failed."<< std::endl;
889 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
890 nsm = new NSM_Client;
891 if (!nsm->init (nsm_url)) {
892 /* the ardour executable may have different names:
894 * waf's obj.target for distro versions: eg ardour4, ardourvst4
895 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
896 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
898 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
900 const char *process_name = g_getenv ("ARDOUR_SELF");
901 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
904 // wait for announce reply from nsm server
905 for ( i = 0; i < 5000; ++i) {
909 if (nsm->is_active()) {
914 error << _("NSM server did not announce itself") << endmsg;
917 // wait for open command from nsm server
918 for ( i = 0; i < 5000; ++i) {
921 if (nsm->client_id ()) {
927 error << _("NSM: no client ID provided") << endmsg;
931 if (_session && nsm) {
932 _session->set_nsm_state( nsm->is_active() );
934 error << _("NSM: no session created") << endmsg;
938 // nsm requires these actions disabled
939 vector<string> action_names;
940 action_names.push_back("SaveAs");
941 action_names.push_back("Rename");
942 action_names.push_back("New");
943 action_names.push_back("Open");
944 action_names.push_back("Recent");
945 action_names.push_back("Close");
947 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
948 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
950 act->set_sensitive (false);
957 error << _("NSM: initialization failed") << endmsg;
963 if (brand_new_user) {
964 _initial_verbose_plugin_scan = true;
969 _initial_verbose_plugin_scan = false;
970 switch (s.response ()) {
971 case Gtk::RESPONSE_OK:
978 #ifdef NO_PLUGIN_STATE
980 ARDOUR::RecentSessions rs;
981 ARDOUR::read_recent_sessions (rs);
983 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
985 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
987 /* already used Ardour, have sessions ... warn about plugin state */
989 ArdourDialog d (_("Free/Demo Version Warning"), true);
991 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
992 CheckButton c (_("Don't warn me about this again"));
994 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"),
995 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
996 _("It will not restore OR save any plugin settings"),
997 _("If you load an existing session with plugin settings\n"
998 "they will not be used and will be lost."),
999 _("To get full access to updates without this limitation\n"
1000 "consider becoming a subscriber for a low cost every month.")));
1001 l.set_justify (JUSTIFY_CENTER);
1003 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1005 d.get_vbox()->pack_start (l, true, true);
1006 d.get_vbox()->pack_start (b, false, false, 12);
1007 d.get_vbox()->pack_start (c, false, false, 12);
1009 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1010 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1014 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1016 if (d.run () != RESPONSE_OK) {
1022 /* go get a session */
1024 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1026 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1027 std::cerr << "Cannot get session parameters."<< std::endl;
1034 goto_editor_window ();
1036 WM::Manager::instance().show_visible ();
1038 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1039 * editor window, and we may want stuff to be hidden.
1041 _status_bar_visibility.update ();
1043 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1048 ARDOUR_UI::check_memory_locking ()
1050 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1051 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1055 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1057 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1059 struct rlimit limits;
1061 long pages, page_size;
1063 size_t pages_len=sizeof(pages);
1064 if ((page_size = getpagesize()) < 0 ||
1065 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1067 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1072 ram = (int64_t) pages * (int64_t) page_size;
1075 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1079 if (limits.rlim_cur != RLIM_INFINITY) {
1081 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1085 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1086 "This might cause %1 to run out of memory before your system "
1087 "runs out of memory. \n\n"
1088 "You can view the memory limit with 'ulimit -l', "
1089 "and it is normally controlled by %2"),
1092 X_("/etc/login.conf")
1094 X_(" /etc/security/limits.conf")
1098 msg.set_default_response (RESPONSE_OK);
1100 VBox* vbox = msg.get_vbox();
1102 CheckButton cb (_("Do not show this window again"));
1103 hbox.pack_start (cb, true, false);
1104 vbox->pack_start (hbox);
1109 pop_back_splash (msg);
1113 if (cb.get_active()) {
1114 XMLNode node (X_("no-memory-warning"));
1115 Config->add_instant_xml (node);
1120 #endif // !__APPLE__
1125 ARDOUR_UI::queue_finish ()
1127 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1131 ARDOUR_UI::idle_finish ()
1134 return false; /* do not call again */
1141 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1143 if (_session->dirty()) {
1144 vector<string> actions;
1145 actions.push_back (_("Don't quit"));
1146 actions.push_back (_("Just quit"));
1147 actions.push_back (_("Save and quit"));
1148 switch (ask_about_saving_session(actions)) {
1153 /* use the default name */
1154 if (save_state_canfail ("")) {
1155 /* failed - don't quit */
1156 MessageDialog msg (_main_window,
1157 string_compose (_("\
1158 %1 was unable to save your session.\n\n\
1159 If you still wish to quit, please use the\n\n\
1160 \"Just quit\" option."), PROGRAM_NAME));
1161 pop_back_splash(msg);
1171 second_connection.disconnect ();
1172 point_one_second_connection.disconnect ();
1173 point_zero_something_second_connection.disconnect();
1174 fps_connection.disconnect();
1177 delete ARDOUR_UI::instance()->video_timeline;
1178 ARDOUR_UI::instance()->video_timeline = NULL;
1179 stop_video_server();
1181 /* Save state before deleting the session, as that causes some
1182 windows to be destroyed before their visible state can be
1185 save_ardour_state ();
1187 close_all_dialogs ();
1190 _session->set_clean ();
1191 _session->remove_pending_capture_state ();
1196 halt_connection.disconnect ();
1197 AudioEngine::instance()->stop ();
1198 #ifdef WINDOWS_VST_SUPPORT
1199 fst_stop_threading();
1205 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1207 ArdourDialog window (_("Unsaved Session"));
1208 Gtk::HBox dhbox; // the hbox for the image and text
1209 Gtk::Label prompt_label;
1210 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1214 assert (actions.size() >= 3);
1216 window.add_button (actions[0], RESPONSE_REJECT);
1217 window.add_button (actions[1], RESPONSE_APPLY);
1218 window.add_button (actions[2], RESPONSE_ACCEPT);
1220 window.set_default_response (RESPONSE_ACCEPT);
1222 Gtk::Button noquit_button (msg);
1223 noquit_button.set_name ("EditorGTKButton");
1227 if (_session->snap_name() == _session->name()) {
1228 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?"),
1229 _session->snap_name());
1231 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?"),
1232 _session->snap_name());
1235 prompt_label.set_text (prompt);
1236 prompt_label.set_name (X_("PrompterLabel"));
1237 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1239 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1240 dhbox.set_homogeneous (false);
1241 dhbox.pack_start (*dimage, false, false, 5);
1242 dhbox.pack_start (prompt_label, true, false, 5);
1243 window.get_vbox()->pack_start (dhbox);
1245 window.set_name (_("Prompter"));
1246 window.set_modal (true);
1247 window.set_resizable (false);
1250 prompt_label.show();
1255 ResponseType r = (ResponseType) window.run();
1260 case RESPONSE_ACCEPT: // save and get out of here
1262 case RESPONSE_APPLY: // get out of here
1273 ARDOUR_UI::every_second ()
1276 update_xrun_count ();
1277 update_buffer_load ();
1278 update_disk_space ();
1279 update_timecode_format ();
1280 update_peak_thread_work ();
1282 if (nsm && nsm->is_active ()) {
1285 if (!_was_dirty && _session->dirty ()) {
1289 else if (_was_dirty && !_session->dirty ()){
1297 ARDOUR_UI::every_point_one_seconds ()
1299 // TODO get rid of this..
1300 // ShuttleControl is updated directly via TransportStateChange signal
1304 ARDOUR_UI::every_point_zero_something_seconds ()
1306 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1308 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1309 float mpeak = editor_meter->update_meters();
1310 if (mpeak > editor_meter_max_peak) {
1311 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1312 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1319 ARDOUR_UI::set_fps_timeout_connection ()
1321 unsigned int interval = 40;
1322 if (!_session) return;
1323 if (_session->timecode_frames_per_second() != 0) {
1324 /* ideally we'll use a select() to sleep and not accumulate
1325 * idle time to provide a regular periodic signal.
1326 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1327 * However, that'll require a dedicated thread and cross-thread
1328 * signals to the GUI Thread..
1330 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1331 * _session->frame_rate() / _session->nominal_frame_rate()
1332 / _session->timecode_frames_per_second()
1334 #ifdef PLATFORM_WINDOWS
1335 // the smallest windows scheduler time-slice is ~15ms.
1336 // periodic GUI timeouts shorter than that will cause
1337 // WaitForSingleObject to spinlock (100% of one CPU Core)
1338 // and gtk never enters idle mode.
1339 // also changing timeBeginPeriod(1) does not affect that in
1340 // any beneficial way, so we just limit the max rate for now.
1341 interval = std::max(30u, interval); // at most ~33Hz.
1343 interval = std::max(8u, interval); // at most 120Hz.
1346 fps_connection.disconnect();
1347 Timers::set_fps_interval (interval);
1351 ARDOUR_UI::update_sample_rate (framecnt_t)
1355 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1357 if (!AudioEngine::instance()->connected()) {
1359 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1363 framecnt_t rate = AudioEngine::instance()->sample_rate();
1366 /* no sample rate available */
1367 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1370 if (fmod (rate, 1000.0) != 0.0) {
1371 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1372 (float) rate / 1000.0f,
1373 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1375 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1377 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1381 sample_rate_label.set_markup (buf);
1385 ARDOUR_UI::update_format ()
1388 format_label.set_text ("");
1393 s << _("File:") << X_(" <span foreground=\"green\">");
1395 switch (_session->config.get_native_file_header_format ()) {
1427 switch (_session->config.get_native_file_data_format ()) {
1441 format_label.set_markup (s.str ());
1445 ARDOUR_UI::update_xrun_count ()
1449 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1450 should also be changed.
1454 const unsigned int x = _session->get_xrun_count ();
1456 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1458 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1461 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1463 xrun_label.set_markup (buf);
1464 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1468 ARDOUR_UI::update_cpu_load ()
1472 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1473 should also be changed.
1476 double const c = AudioEngine::instance()->get_dsp_load ();
1477 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1478 cpu_load_label.set_markup (buf);
1482 ARDOUR_UI::update_peak_thread_work ()
1485 const int c = SourceFactory::peak_work_queue_length ();
1487 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1488 peak_thread_work_label.set_markup (buf);
1490 peak_thread_work_label.set_markup (X_(""));
1495 ARDOUR_UI::update_buffer_load ()
1499 uint32_t const playback = _session ? _session->playback_load () : 100;
1500 uint32_t const capture = _session ? _session->capture_load () : 100;
1502 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1503 should also be changed.
1509 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1510 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1511 playback <= 5 ? X_("red") : X_("green"),
1513 capture <= 5 ? X_("red") : X_("green"),
1517 buffer_load_label.set_markup (buf);
1519 buffer_load_label.set_text ("");
1524 ARDOUR_UI::count_recenabled_streams (Route& route)
1526 Track* track = dynamic_cast<Track*>(&route);
1527 if (track && track->record_enabled()) {
1528 rec_enabled_streams += track->n_inputs().n_total();
1533 ARDOUR_UI::update_disk_space()
1535 if (_session == 0) {
1539 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1541 framecnt_t fr = _session->frame_rate();
1544 /* skip update - no SR available */
1549 /* Available space is unknown */
1550 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1551 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1552 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1554 rec_enabled_streams = 0;
1555 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1557 framecnt_t frames = opt_frames.get_value_or (0);
1559 if (rec_enabled_streams) {
1560 frames /= rec_enabled_streams;
1567 hrs = frames / (fr * 3600);
1570 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1572 frames -= hrs * fr * 3600;
1573 mins = frames / (fr * 60);
1574 frames -= mins * fr * 60;
1577 bool const low = (hrs == 0 && mins <= 30);
1581 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1582 low ? X_("red") : X_("green"),
1588 disk_space_label.set_markup (buf);
1592 ARDOUR_UI::update_timecode_format ()
1598 TimecodeSlave* tcslave;
1599 SyncSource sync_src = Config->get_sync_source();
1601 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1602 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1607 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1608 matching ? X_("green") : X_("red"),
1609 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1611 snprintf (buf, sizeof (buf), "TC: n/a");
1614 timecode_format_label.set_markup (buf);
1618 ARDOUR_UI::update_wall_clock ()
1622 static int last_min = -1;
1625 tm_now = localtime (&now);
1626 if (last_min != tm_now->tm_min) {
1628 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1629 wall_clock_label.set_text (buf);
1630 last_min = tm_now->tm_min;
1637 ARDOUR_UI::open_recent_session ()
1639 bool can_return = (_session != 0);
1641 SessionDialog recent_session_dialog;
1645 ResponseType r = (ResponseType) recent_session_dialog.run ();
1648 case RESPONSE_ACCEPT:
1652 recent_session_dialog.hide();
1659 recent_session_dialog.hide();
1663 std::string path = recent_session_dialog.session_folder();
1664 std::string state = recent_session_dialog.session_name (should_be_new);
1666 if (should_be_new == true) {
1670 _session_is_new = false;
1672 if (load_session (path, state) == 0) {
1681 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1683 if (!AudioEngine::instance()->connected()) {
1684 MessageDialog msg (parent, string_compose (
1685 _("%1 is not connected to any audio backend.\n"
1686 "You cannot open or close sessions in this condition"),
1688 pop_back_splash (msg);
1696 ARDOUR_UI::open_session ()
1698 if (!check_audioengine(*editor)) {
1702 /* ardour sessions are folders */
1703 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1704 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1705 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1706 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1709 string session_parent_dir = Glib::path_get_dirname(_session->path());
1710 open_session_selector.set_current_folder(session_parent_dir);
1712 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1715 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1717 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1718 string default_session_folder = Config->get_default_session_parent_dir();
1719 open_session_selector.add_shortcut_folder (default_session_folder);
1721 catch (Glib::Error & e) {
1722 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1725 FileFilter session_filter;
1726 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1727 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1728 open_session_selector.add_filter (session_filter);
1729 open_session_selector.set_filter (session_filter);
1731 int response = open_session_selector.run();
1732 open_session_selector.hide ();
1734 if (response == Gtk::RESPONSE_CANCEL) {
1738 string session_path = open_session_selector.get_filename();
1742 if (session_path.length() > 0) {
1743 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1744 _session_is_new = isnew;
1745 load_session (path, name);
1752 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1753 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1755 list<boost::shared_ptr<MidiTrack> > tracks;
1757 if (_session == 0) {
1758 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1763 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1765 if (tracks.size() != how_many) {
1766 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1771 MessageDialog msg (_main_window,
1772 string_compose (_("There are insufficient ports available\n\
1773 to create a new track or bus.\n\
1774 You should save %1, exit and\n\
1775 restart with more ports."), PROGRAM_NAME));
1782 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1784 ChanCount one_midi_channel;
1785 one_midi_channel.set (DataType::MIDI, 1);
1788 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1793 ARDOUR_UI::session_add_audio_route (
1795 int32_t input_channels,
1796 int32_t output_channels,
1797 ARDOUR::TrackMode mode,
1798 RouteGroup* route_group,
1800 string const & name_template
1803 list<boost::shared_ptr<AudioTrack> > tracks;
1806 if (_session == 0) {
1807 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1813 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1815 if (tracks.size() != how_many) {
1816 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1822 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1824 if (routes.size() != how_many) {
1825 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1832 MessageDialog msg (_main_window,
1833 string_compose (_("There are insufficient ports available\n\
1834 to create a new track or bus.\n\
1835 You should save %1, exit and\n\
1836 restart with more ports."), PROGRAM_NAME));
1837 pop_back_splash (msg);
1843 ARDOUR_UI::transport_goto_start ()
1846 _session->goto_start();
1848 /* force displayed area in editor to start no matter
1849 what "follow playhead" setting is.
1853 editor->center_screen (_session->current_start_frame ());
1859 ARDOUR_UI::transport_goto_zero ()
1862 _session->request_locate (0);
1864 /* force displayed area in editor to start no matter
1865 what "follow playhead" setting is.
1869 editor->reset_x_origin (0);
1875 ARDOUR_UI::transport_goto_wallclock ()
1877 if (_session && editor) {
1884 localtime_r (&now, &tmnow);
1886 framecnt_t frame_rate = _session->frame_rate();
1888 if (frame_rate == 0) {
1889 /* no frame rate available */
1893 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1894 frames += tmnow.tm_min * (60 * frame_rate);
1895 frames += tmnow.tm_sec * frame_rate;
1897 _session->request_locate (frames, _session->transport_rolling ());
1899 /* force displayed area in editor to start no matter
1900 what "follow playhead" setting is.
1904 editor->center_screen (frames);
1910 ARDOUR_UI::transport_goto_end ()
1913 framepos_t const frame = _session->current_end_frame();
1914 _session->request_locate (frame);
1916 /* force displayed area in editor to start no matter
1917 what "follow playhead" setting is.
1921 editor->center_screen (frame);
1927 ARDOUR_UI::transport_stop ()
1933 if (_session->is_auditioning()) {
1934 _session->cancel_audition ();
1938 _session->request_stop (false, true);
1941 /** Check if any tracks are record enabled. If none are, record enable all of them.
1942 * @return true if track record-enabled status was changed, false otherwise.
1945 ARDOUR_UI::trx_record_enable_all_tracks ()
1951 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1952 bool none_record_enabled = true;
1954 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1955 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1958 if (t->record_enabled()) {
1959 none_record_enabled = false;
1964 if (none_record_enabled) {
1965 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1968 return none_record_enabled;
1972 ARDOUR_UI::transport_record (bool roll)
1975 switch (_session->record_status()) {
1976 case Session::Disabled:
1977 if (_session->ntracks() == 0) {
1978 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."));
1982 if (Profile->get_trx()) {
1983 roll = trx_record_enable_all_tracks ();
1985 _session->maybe_enable_record ();
1990 case Session::Recording:
1992 _session->request_stop();
1994 _session->disable_record (false, true);
1998 case Session::Enabled:
1999 _session->disable_record (false, true);
2005 ARDOUR_UI::transport_roll ()
2011 if (_session->is_auditioning()) {
2016 if (_session->config.get_external_sync()) {
2017 switch (Config->get_sync_source()) {
2021 /* transport controlled by the master */
2027 bool rolling = _session->transport_rolling();
2029 if (_session->get_play_loop()) {
2031 /* If loop playback is not a mode, then we should cancel
2032 it when this action is requested. If it is a mode
2033 we just leave it in place.
2036 if (!Config->get_loop_is_mode()) {
2037 /* XXX it is not possible to just leave seamless loop and keep
2038 playing at present (nov 4th 2009)
2040 if (!Config->get_seamless_loop()) {
2041 /* stop loop playback and stop rolling */
2042 _session->request_play_loop (false, true);
2043 } else if (rolling) {
2044 /* stop loop playback but keep rolling */
2045 _session->request_play_loop (false, false);
2049 } else if (_session->get_play_range () ) {
2050 /* stop playing a range if we currently are */
2051 _session->request_play_range (0, true);
2055 _session->request_transport_speed (1.0f);
2060 ARDOUR_UI::get_smart_mode() const
2062 return ( editor->get_smart_mode() );
2067 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2073 if (_session->is_auditioning()) {
2074 _session->cancel_audition ();
2078 if (_session->config.get_external_sync()) {
2079 switch (Config->get_sync_source()) {
2083 /* transport controlled by the master */
2088 bool rolling = _session->transport_rolling();
2089 bool affect_transport = true;
2091 if (rolling && roll_out_of_bounded_mode) {
2092 /* drop out of loop/range playback but leave transport rolling */
2093 if (_session->get_play_loop()) {
2094 if (_session->actively_recording()) {
2096 /* just stop using the loop, then actually stop
2099 _session->request_play_loop (false, affect_transport);
2102 if (Config->get_seamless_loop()) {
2103 /* the disk buffers contain copies of the loop - we can't
2104 just keep playing, so stop the transport. the user
2105 can restart as they wish.
2107 affect_transport = true;
2109 /* disk buffers are normal, so we can keep playing */
2110 affect_transport = false;
2112 _session->request_play_loop (false, affect_transport);
2114 } else if (_session->get_play_range ()) {
2115 affect_transport = false;
2116 _session->request_play_range (0, true);
2120 if (affect_transport) {
2122 _session->request_stop (with_abort, true);
2124 /* the only external sync condition we can be in here
2125 * would be Engine (JACK) sync, in which case we still
2129 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
2130 _session->request_play_range (&editor->get_selection().time, true);
2131 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2133 _session->request_transport_speed (1.0f);
2139 ARDOUR_UI::toggle_session_auto_loop ()
2145 Location * looploc = _session->locations()->auto_loop_location();
2151 if (_session->get_play_loop()) {
2153 /* looping enabled, our job is to disable it */
2155 _session->request_play_loop (false);
2159 /* looping not enabled, our job is to enable it.
2161 loop-is-NOT-mode: this action always starts the transport rolling.
2162 loop-IS-mode: this action simply sets the loop play mechanism, but
2163 does not start transport.
2165 if (Config->get_loop_is_mode()) {
2166 _session->request_play_loop (true, false);
2168 _session->request_play_loop (true, true);
2172 //show the loop markers
2173 looploc->set_hidden (false, this);
2177 ARDOUR_UI::transport_play_selection ()
2183 editor->play_selection ();
2187 ARDOUR_UI::transport_play_preroll ()
2192 editor->play_with_preroll ();
2196 ARDOUR_UI::transport_rewind (int option)
2198 float current_transport_speed;
2201 current_transport_speed = _session->transport_speed();
2203 if (current_transport_speed >= 0.0f) {
2206 _session->request_transport_speed (-1.0f);
2209 _session->request_transport_speed (-4.0f);
2212 _session->request_transport_speed (-0.5f);
2217 _session->request_transport_speed (current_transport_speed * 1.5f);
2223 ARDOUR_UI::transport_forward (int option)
2229 float current_transport_speed = _session->transport_speed();
2231 if (current_transport_speed <= 0.0f) {
2234 _session->request_transport_speed (1.0f);
2237 _session->request_transport_speed (4.0f);
2240 _session->request_transport_speed (0.5f);
2245 _session->request_transport_speed (current_transport_speed * 1.5f);
2250 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2256 boost::shared_ptr<Route> r;
2258 if ((r = _session->route_by_remote_id (rid)) != 0) {
2260 boost::shared_ptr<Track> t;
2262 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2263 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2269 ARDOUR_UI::map_transport_state ()
2272 auto_loop_button.unset_active_state ();
2273 play_selection_button.unset_active_state ();
2274 roll_button.unset_active_state ();
2275 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2279 shuttle_box->map_transport_state ();
2281 float sp = _session->transport_speed();
2287 if (_session->get_play_range()) {
2289 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2290 roll_button.unset_active_state ();
2291 auto_loop_button.unset_active_state ();
2293 } else if (_session->get_play_loop ()) {
2295 auto_loop_button.set_active (true);
2296 play_selection_button.set_active (false);
2297 if (Config->get_loop_is_mode()) {
2298 roll_button.set_active (true);
2300 roll_button.set_active (false);
2305 roll_button.set_active (true);
2306 play_selection_button.set_active (false);
2307 auto_loop_button.set_active (false);
2310 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2311 /* light up both roll and play-selection if they are joined */
2312 roll_button.set_active (true);
2313 play_selection_button.set_active (true);
2316 stop_button.set_active (false);
2320 stop_button.set_active (true);
2321 roll_button.set_active (false);
2322 play_selection_button.set_active (false);
2323 if (Config->get_loop_is_mode ()) {
2324 auto_loop_button.set_active (_session->get_play_loop());
2326 auto_loop_button.set_active (false);
2328 update_disk_space ();
2333 ARDOUR_UI::blink_handler (bool blink_on)
2335 transport_rec_enable_blink (blink_on);
2336 solo_blink (blink_on);
2337 sync_blink (blink_on);
2338 audition_blink (blink_on);
2339 feedback_blink (blink_on);
2340 error_blink (blink_on);
2344 ARDOUR_UI::update_clocks ()
2346 if (!_session) return;
2348 if (editor && !editor->dragging_playhead()) {
2349 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2354 ARDOUR_UI::start_clocking ()
2356 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2357 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2359 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2364 ARDOUR_UI::stop_clocking ()
2366 clock_signal_connection.disconnect ();
2370 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2374 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2376 label->set_text (buf);
2377 bar->set_fraction (fraction);
2379 /* process events, redraws, etc. */
2381 while (gtk_events_pending()) {
2382 gtk_main_iteration ();
2385 return true; /* continue with save-as */
2389 ARDOUR_UI::save_session_as ()
2395 if (!save_as_dialog) {
2396 save_as_dialog = new SaveAsDialog;
2399 save_as_dialog->set_name (_session->name());
2401 int response = save_as_dialog->run ();
2403 save_as_dialog->hide ();
2406 case Gtk::RESPONSE_OK:
2415 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2416 sa.new_name = save_as_dialog->new_name ();
2417 sa.switch_to = save_as_dialog->switch_to();
2418 sa.copy_media = save_as_dialog->copy_media();
2419 sa.copy_external = save_as_dialog->copy_external();
2420 sa.include_media = save_as_dialog->include_media ();
2422 /* Only bother with a progress dialog if we're going to copy
2423 media into the save-as target. Without that choice, this
2424 will be very fast because we're only talking about a few kB's to
2425 perhaps a couple of MB's of data.
2428 ArdourDialog progress_dialog (_("Save As"), true);
2430 if (sa.include_media && sa.copy_media) {
2433 Gtk::ProgressBar progress_bar;
2435 progress_dialog.get_vbox()->pack_start (label);
2436 progress_dialog.get_vbox()->pack_start (progress_bar);
2438 progress_bar.show ();
2440 /* this signal will be emitted from within this, the calling thread,
2441 * after every file is copied. It provides information on percentage
2442 * complete (in terms of total data to copy), the number of files
2443 * copied so far, and the total number to copy.
2448 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2450 progress_dialog.show_all ();
2451 progress_dialog.present ();
2454 if (_session->save_as (sa)) {
2456 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2460 if (!sa.include_media) {
2461 unload_session (false);
2462 load_session (sa.final_session_folder_name, sa.new_name);
2467 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2471 struct tm local_time;
2474 localtime_r (&n, &local_time);
2475 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2477 save_state (timebuf, switch_to_it);
2482 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2486 prompter.get_result (snapname);
2488 bool do_save = (snapname.length() != 0);
2491 char illegal = Session::session_name_is_legal(snapname);
2493 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2494 "snapshot names may not contain a '%1' character"), illegal));
2500 vector<std::string> p;
2501 get_state_files_in_directory (_session->session_directory().root_path(), p);
2502 vector<string> n = get_file_names_no_extension (p);
2504 if (find (n.begin(), n.end(), snapname) != n.end()) {
2506 do_save = overwrite_file_dialog (prompter,
2507 _("Confirm Snapshot Overwrite"),
2508 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2512 save_state (snapname, switch_to_it);
2522 /** Ask the user for the name of a new snapshot and then take it.
2526 ARDOUR_UI::snapshot_session (bool switch_to_it)
2528 ArdourPrompter prompter (true);
2530 prompter.set_name ("Prompter");
2531 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2533 prompter.set_title (_("Save as..."));
2534 prompter.set_prompt (_("New session name"));
2536 prompter.set_title (_("Take Snapshot"));
2537 prompter.set_prompt (_("Name of new snapshot"));
2541 prompter.set_initial_text (_session->snap_name());
2545 struct tm local_time;
2548 localtime_r (&n, &local_time);
2549 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2550 prompter.set_initial_text (timebuf);
2553 bool finished = false;
2555 switch (prompter.run()) {
2556 case RESPONSE_ACCEPT:
2558 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2569 /** Ask the user for a new session name and then rename the session to it.
2573 ARDOUR_UI::rename_session ()
2579 ArdourPrompter prompter (true);
2582 prompter.set_name ("Prompter");
2583 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2584 prompter.set_title (_("Rename Session"));
2585 prompter.set_prompt (_("New session name"));
2588 switch (prompter.run()) {
2589 case RESPONSE_ACCEPT:
2591 prompter.get_result (name);
2593 bool do_rename = (name.length() != 0);
2596 char illegal = Session::session_name_is_legal (name);
2599 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2600 "session names may not contain a '%1' character"), illegal));
2605 switch (_session->rename (name)) {
2607 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2608 msg.set_position (WIN_POS_MOUSE);
2616 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2617 msg.set_position (WIN_POS_MOUSE);
2633 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2635 if (!_session || _session->deletion_in_progress()) {
2639 XMLNode* node = new XMLNode (X_("UI"));
2641 WM::Manager::instance().add_state (*node);
2643 node->add_child_nocopy (gui_object_state->get_state());
2645 _session->add_extra_xml (*node);
2647 if (export_video_dialog) {
2648 _session->add_extra_xml (export_video_dialog->get_state());
2651 save_state_canfail (name, switch_to_it);
2655 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2660 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2665 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2670 ARDOUR_UI::primary_clock_value_changed ()
2673 _session->request_locate (primary_clock->current_time ());
2678 ARDOUR_UI::big_clock_value_changed ()
2681 _session->request_locate (big_clock->current_time ());
2686 ARDOUR_UI::secondary_clock_value_changed ()
2689 _session->request_locate (secondary_clock->current_time ());
2694 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2696 if (_session == 0) {
2700 if (_session->step_editing()) {
2704 Session::RecordState const r = _session->record_status ();
2705 bool const h = _session->have_rec_enabled_track ();
2707 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2709 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2711 rec_button.set_active_state (Gtkmm2ext::Off);
2713 } else if (r == Session::Recording && h) {
2714 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2716 rec_button.unset_active_state ();
2721 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2725 prompter.get_result (name);
2727 if (name.length()) {
2728 int failed = _session->save_template (name);
2730 if (failed == -2) { /* file already exists. */
2731 bool overwrite = overwrite_file_dialog (prompter,
2732 _("Confirm Template Overwrite"),
2733 _("A template already exists with that name. Do you want to overwrite it?"));
2736 _session->save_template (name, true);
2748 ARDOUR_UI::save_template ()
2750 ArdourPrompter prompter (true);
2752 if (!check_audioengine(*editor)) {
2756 prompter.set_name (X_("Prompter"));
2757 prompter.set_title (_("Save Template"));
2758 prompter.set_prompt (_("Name for template:"));
2759 prompter.set_initial_text(_session->name() + _("-template"));
2760 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2762 bool finished = false;
2764 switch (prompter.run()) {
2765 case RESPONSE_ACCEPT:
2766 finished = process_save_template_prompter (prompter);
2777 ARDOUR_UI::edit_metadata ()
2779 SessionMetadataEditor dialog;
2780 dialog.set_session (_session);
2781 dialog.grab_focus ();
2786 ARDOUR_UI::import_metadata ()
2788 SessionMetadataImporter dialog;
2789 dialog.set_session (_session);
2794 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2796 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2798 MessageDialog msg (str,
2800 Gtk::MESSAGE_WARNING,
2801 Gtk::BUTTONS_YES_NO,
2805 msg.set_name (X_("OpenExistingDialog"));
2806 msg.set_title (_("Open Existing Session"));
2807 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2808 msg.set_position (Gtk::WIN_POS_CENTER);
2809 pop_back_splash (msg);
2811 switch (msg.run()) {
2820 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2822 BusProfile bus_profile;
2824 if (nsm || Profile->get_sae()) {
2826 bus_profile.master_out_channels = 2;
2827 bus_profile.input_ac = AutoConnectPhysical;
2828 bus_profile.output_ac = AutoConnectMaster;
2829 bus_profile.requested_physical_in = 0; // use all available
2830 bus_profile.requested_physical_out = 0; // use all available
2834 /* get settings from advanced section of NSD */
2836 if (sd.create_master_bus()) {
2837 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2839 bus_profile.master_out_channels = 0;
2842 if (sd.connect_inputs()) {
2843 bus_profile.input_ac = AutoConnectPhysical;
2845 bus_profile.input_ac = AutoConnectOption (0);
2848 bus_profile.output_ac = AutoConnectOption (0);
2850 if (sd.connect_outputs ()) {
2851 if (sd.connect_outs_to_master()) {
2852 bus_profile.output_ac = AutoConnectMaster;
2853 } else if (sd.connect_outs_to_physical()) {
2854 bus_profile.output_ac = AutoConnectPhysical;
2858 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2859 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2862 if (build_session (session_path, session_name, bus_profile)) {
2870 ARDOUR_UI::load_from_application_api (const std::string& path)
2872 ARDOUR_COMMAND_LINE::session_name = path;
2873 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2875 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2877 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2878 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2879 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2880 * -> SessionDialog is not displayed
2883 if (_session_dialog) {
2884 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2885 std::string session_path = path;
2886 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2887 session_path = Glib::path_get_dirname (session_path);
2889 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2890 _session_dialog->set_provided_session (session_name, session_path);
2891 _session_dialog->response (RESPONSE_NONE);
2892 _session_dialog->hide();
2897 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2898 /* /path/to/foo => /path/to/foo, foo */
2899 rv = load_session (path, basename_nosuffix (path));
2901 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2902 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2905 // if load_session fails -> pop up SessionDialog.
2907 ARDOUR_COMMAND_LINE::session_name = "";
2909 if (get_session_parameters (true, false)) {
2913 goto_editor_window ();
2917 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2919 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2921 string session_name;
2922 string session_path;
2923 string template_name;
2925 bool likely_new = false;
2926 bool cancel_not_quit;
2928 /* deal with any existing DIRTY session now, rather than later. don't
2929 * treat a non-dirty session this way, so that it stays visible
2930 * as we bring up the new session dialog.
2933 if (_session && ARDOUR_UI::instance()->video_timeline) {
2934 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2937 /* if there is already a session, relabel the button
2938 on the SessionDialog so that we don't Quit directly
2940 cancel_not_quit = (_session != 0);
2942 if (_session && _session->dirty()) {
2943 if (unload_session (false)) {
2944 /* unload cancelled by user */
2947 ARDOUR_COMMAND_LINE::session_name = "";
2950 if (!load_template.empty()) {
2951 should_be_new = true;
2952 template_name = load_template;
2955 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2956 session_path = ARDOUR_COMMAND_LINE::session_name;
2958 if (!session_path.empty()) {
2959 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2960 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2961 /* session/snapshot file, change path to be dir */
2962 session_path = Glib::path_get_dirname (session_path);
2967 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2969 _session_dialog = &session_dialog;
2972 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2974 /* if they named a specific statefile, use it, otherwise they are
2975 just giving a session folder, and we want to use it as is
2976 to find the session.
2979 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2981 if (suffix != string::npos) {
2982 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2983 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2984 session_name = Glib::path_get_basename (session_name);
2986 session_path = ARDOUR_COMMAND_LINE::session_name;
2987 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2992 session_dialog.clear_given ();
2995 if (should_be_new || session_name.empty()) {
2996 /* need the dialog to get info from user */
2998 cerr << "run dialog\n";
3000 switch (session_dialog.run()) {
3001 case RESPONSE_ACCEPT:
3004 /* this is used for async * app->ShouldLoad(). */
3005 continue; // while loop
3008 if (quit_on_cancel) {
3009 // JE - Currently (July 2014) this section can only get reached if the
3010 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3011 // point does NOT indicate an abnormal termination). Therefore, let's
3012 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3014 pthread_cancel_all ();
3022 session_dialog.hide ();
3025 /* if we run the startup dialog again, offer more than just "new session" */
3027 should_be_new = false;
3029 session_name = session_dialog.session_name (likely_new);
3030 session_path = session_dialog.session_folder ();
3036 string::size_type suffix = session_name.find (statefile_suffix);
3038 if (suffix != string::npos) {
3039 session_name = session_name.substr (0, suffix);
3042 /* this shouldn't happen, but we catch it just in case it does */
3044 if (session_name.empty()) {
3048 if (session_dialog.use_session_template()) {
3049 template_name = session_dialog.session_template_name();
3050 _session_is_new = true;
3053 if (session_name[0] == G_DIR_SEPARATOR ||
3054 #ifdef PLATFORM_WINDOWS
3055 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3057 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3058 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3063 /* absolute path or cwd-relative path specified for session name: infer session folder
3064 from what was given.
3067 session_path = Glib::path_get_dirname (session_name);
3068 session_name = Glib::path_get_basename (session_name);
3072 session_path = session_dialog.session_folder();
3074 char illegal = Session::session_name_is_legal (session_name);
3077 MessageDialog msg (session_dialog,
3078 string_compose (_("To ensure compatibility with various systems\n"
3079 "session names may not contain a '%1' character"),
3082 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3087 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3090 if (likely_new && !nsm) {
3092 std::string existing = Glib::build_filename (session_path, session_name);
3094 if (!ask_about_loading_existing_session (existing)) {
3095 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3100 _session_is_new = false;
3105 pop_back_splash (session_dialog);
3106 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3108 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3112 char illegal = Session::session_name_is_legal(session_name);
3115 pop_back_splash (session_dialog);
3116 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3117 "session names may not contain a '%1' character"), illegal));
3119 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3123 _session_is_new = true;
3126 if (likely_new && template_name.empty()) {
3128 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3132 ret = load_session (session_path, session_name, template_name);
3135 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3139 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3140 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3144 /* clear this to avoid endless attempts to load the
3148 ARDOUR_COMMAND_LINE::session_name = "";
3152 _session_dialog = NULL;
3158 ARDOUR_UI::close_session()
3160 if (!check_audioengine(*editor)) {
3164 if (unload_session (true)) {
3168 ARDOUR_COMMAND_LINE::session_name = "";
3170 if (get_session_parameters (true, false)) {
3174 goto_editor_window ();
3177 /** @param snap_name Snapshot name (without .ardour suffix).
3178 * @return -2 if the load failed because we are not connected to the AudioEngine.
3181 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3183 Session *new_session;
3188 unload_status = unload_session ();
3190 if (unload_status < 0) {
3192 } else if (unload_status > 0) {
3198 session_loaded = false;
3200 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3203 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3206 /* this one is special */
3208 catch (AudioEngine::PortRegistrationFailure& err) {
3210 MessageDialog msg (err.what(),
3213 Gtk::BUTTONS_CLOSE);
3215 msg.set_title (_("Port Registration Error"));
3216 msg.set_secondary_text (_("Click the Close button to try again."));
3217 msg.set_position (Gtk::WIN_POS_CENTER);
3218 pop_back_splash (msg);
3221 int response = msg.run ();
3226 case RESPONSE_CANCEL:
3233 catch (SessionException e) {
3234 MessageDialog msg (string_compose(
3235 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3236 path, snap_name, e.what()),
3241 msg.set_title (_("Loading Error"));
3242 msg.set_position (Gtk::WIN_POS_CENTER);
3243 pop_back_splash (msg);
3255 MessageDialog msg (string_compose(
3256 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3262 msg.set_title (_("Loading Error"));
3263 msg.set_position (Gtk::WIN_POS_CENTER);
3264 pop_back_splash (msg);
3276 list<string> const u = new_session->unknown_processors ();
3278 MissingPluginDialog d (_session, u);
3283 if (!new_session->writable()) {
3284 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3289 msg.set_title (_("Read-only Session"));
3290 msg.set_position (Gtk::WIN_POS_CENTER);
3291 pop_back_splash (msg);
3298 /* Now the session been created, add the transport controls */
3299 new_session->add_controllable(roll_controllable);
3300 new_session->add_controllable(stop_controllable);
3301 new_session->add_controllable(goto_start_controllable);
3302 new_session->add_controllable(goto_end_controllable);
3303 new_session->add_controllable(auto_loop_controllable);
3304 new_session->add_controllable(play_selection_controllable);
3305 new_session->add_controllable(rec_controllable);
3307 set_session (new_session);
3309 session_loaded = true;
3311 goto_editor_window ();
3314 _session->set_clean ();
3317 #ifdef WINDOWS_VST_SUPPORT
3318 fst_stop_threading();
3322 Timers::TimerSuspender t;
3326 #ifdef WINDOWS_VST_SUPPORT
3327 fst_start_threading();
3336 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3338 Session *new_session;
3341 session_loaded = false;
3342 x = unload_session ();
3350 _session_is_new = true;
3353 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3356 catch (SessionException e) {
3358 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3359 msg.set_title (_("Loading Error"));
3360 msg.set_position (Gtk::WIN_POS_CENTER);
3361 pop_back_splash (msg);
3367 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3368 msg.set_title (_("Loading Error"));
3369 msg.set_position (Gtk::WIN_POS_CENTER);
3370 pop_back_splash (msg);
3375 /* Give the new session the default GUI state, if such things exist */
3378 n = Config->instant_xml (X_("Editor"));
3380 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3381 new_session->add_instant_xml (*n, false);
3383 n = Config->instant_xml (X_("Mixer"));
3385 new_session->add_instant_xml (*n, false);
3388 /* Put the playhead at 0 and scroll fully left */
3389 n = new_session->instant_xml (X_("Editor"));
3391 n->add_property (X_("playhead"), X_("0"));
3392 n->add_property (X_("left-frame"), X_("0"));
3395 set_session (new_session);
3397 session_loaded = true;
3399 new_session->save_state(new_session->name());
3405 ARDOUR_UI::launch_chat ()
3407 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3409 dialog.set_title (_("About the Chat"));
3410 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."));
3412 switch (dialog.run()) {
3415 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3416 #elif defined PLATFORM_WINDOWS
3417 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3419 open_uri("http://webchat.freenode.net/?channels=ardour");
3428 ARDOUR_UI::launch_manual ()
3430 PBD::open_uri (Config->get_tutorial_manual_url());
3434 ARDOUR_UI::launch_reference ()
3436 PBD::open_uri (Config->get_reference_manual_url());
3440 ARDOUR_UI::launch_tracker ()
3442 PBD::open_uri ("http://tracker.ardour.org");
3446 ARDOUR_UI::launch_subscribe ()
3448 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3452 ARDOUR_UI::launch_cheat_sheet ()
3455 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3457 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3462 ARDOUR_UI::launch_website ()
3464 PBD::open_uri ("http://ardour.org");
3468 ARDOUR_UI::launch_website_dev ()
3470 PBD::open_uri ("http://ardour.org/development.html");
3474 ARDOUR_UI::launch_forums ()
3476 PBD::open_uri ("https://community.ardour.org/forums");
3480 ARDOUR_UI::launch_howto_report ()
3482 PBD::open_uri ("http://ardour.org/reporting_bugs");
3486 ARDOUR_UI::loading_message (const std::string& msg)
3488 if (ARDOUR_COMMAND_LINE::no_splash) {
3496 splash->message (msg);
3500 ARDOUR_UI::show_splash ()
3504 splash = new Splash;
3514 ARDOUR_UI::hide_splash ()
3521 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3525 removed = rep.paths.size();
3528 MessageDialog msgd (_main_window,
3529 _("No files were ready for clean-up"),
3533 msgd.set_title (_("Clean-up"));
3534 msgd.set_secondary_text (_("If this seems suprising, \n\
3535 check for any existing snapshots.\n\
3536 These may still include regions that\n\
3537 require some unused files to continue to exist."));
3543 ArdourDialog results (_("Clean-up"), true, false);
3545 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3546 CleanupResultsModelColumns() {
3550 Gtk::TreeModelColumn<std::string> visible_name;
3551 Gtk::TreeModelColumn<std::string> fullpath;
3555 CleanupResultsModelColumns results_columns;
3556 Glib::RefPtr<Gtk::ListStore> results_model;
3557 Gtk::TreeView results_display;
3559 results_model = ListStore::create (results_columns);
3560 results_display.set_model (results_model);
3561 results_display.append_column (list_title, results_columns.visible_name);
3563 results_display.set_name ("CleanupResultsList");
3564 results_display.set_headers_visible (true);
3565 results_display.set_headers_clickable (false);
3566 results_display.set_reorderable (false);
3568 Gtk::ScrolledWindow list_scroller;
3571 Gtk::HBox dhbox; // the hbox for the image and text
3572 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3573 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3575 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3577 const string dead_directory = _session->session_directory().dead_path();
3580 %1 - number of files removed
3581 %2 - location of "dead"
3582 %3 - size of files affected
3583 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3586 const char* bprefix;
3587 double space_adjusted = 0;
3589 if (rep.space < 1000) {
3591 space_adjusted = rep.space;
3592 } else if (rep.space < 1000000) {
3593 bprefix = _("kilo");
3594 space_adjusted = floorf((float)rep.space / 1000.0);
3595 } else if (rep.space < 1000000 * 1000) {
3596 bprefix = _("mega");
3597 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3599 bprefix = _("giga");
3600 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3604 txt.set_markup (string_compose (P_("\
3605 The following file was deleted from %2,\n\
3606 releasing %3 %4bytes of disk space", "\
3607 The following %1 files were deleted from %2,\n\
3608 releasing %3 %4bytes of disk space", removed),
3609 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3611 txt.set_markup (string_compose (P_("\
3612 The following file was not in use and \n\
3613 has been moved to: %2\n\n\
3614 After a restart of %5\n\n\
3615 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3616 will release an additional %3 %4bytes of disk space.\n", "\
3617 The following %1 files were not in use and \n\
3618 have been moved to: %2\n\n\
3619 After a restart of %5\n\n\
3620 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3621 will release an additional %3 %4bytes of disk space.\n", removed),
3622 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3625 dhbox.pack_start (*dimage, true, false, 5);
3626 dhbox.pack_start (txt, true, false, 5);
3628 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3629 TreeModel::Row row = *(results_model->append());
3630 row[results_columns.visible_name] = *i;
3631 row[results_columns.fullpath] = *i;
3634 list_scroller.add (results_display);
3635 list_scroller.set_size_request (-1, 150);
3636 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3638 dvbox.pack_start (dhbox, true, false, 5);
3639 dvbox.pack_start (list_scroller, true, false, 5);
3640 ddhbox.pack_start (dvbox, true, false, 5);
3642 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3643 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3644 results.set_default_response (RESPONSE_CLOSE);
3645 results.set_position (Gtk::WIN_POS_MOUSE);
3647 results_display.show();
3648 list_scroller.show();
3655 //results.get_vbox()->show();
3656 results.set_resizable (false);
3663 ARDOUR_UI::cleanup ()
3665 if (_session == 0) {
3666 /* shouldn't happen: menu item is insensitive */
3671 MessageDialog checker (_("Are you sure you want to clean-up?"),
3673 Gtk::MESSAGE_QUESTION,
3676 checker.set_title (_("Clean-up"));
3678 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3679 ALL undo/redo information will be lost if you clean-up.\n\
3680 Clean-up will move all unused files to a \"dead\" location."));
3682 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3683 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3684 checker.set_default_response (RESPONSE_CANCEL);
3686 checker.set_name (_("CleanupDialog"));
3687 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3688 checker.set_position (Gtk::WIN_POS_MOUSE);
3690 switch (checker.run()) {
3691 case RESPONSE_ACCEPT:
3697 ARDOUR::CleanupReport rep;
3699 editor->prepare_for_cleanup ();
3701 /* do not allow flush until a session is reloaded */
3703 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3705 act->set_sensitive (false);
3708 if (_session->cleanup_sources (rep)) {
3709 editor->finish_cleanup ();
3713 editor->finish_cleanup ();
3716 display_cleanup_results (rep, _("Cleaned Files"), false);
3720 ARDOUR_UI::flush_trash ()
3722 if (_session == 0) {
3723 /* shouldn't happen: menu item is insensitive */
3727 ARDOUR::CleanupReport rep;
3729 if (_session->cleanup_trash_sources (rep)) {
3733 display_cleanup_results (rep, _("deleted file"), true);
3737 ARDOUR_UI::cleanup_peakfiles ()
3739 if (_session == 0) {
3740 /* shouldn't happen: menu item is insensitive */
3744 if (! _session->can_cleanup_peakfiles ()) {
3748 // get all region-views in this session
3750 TrackViewList empty;
3752 editor->get_regions_after(rs, (framepos_t) 0, empty);
3753 std::list<RegionView*> views = rs.by_layer();
3755 // remove displayed audio-region-views waveforms
3756 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3757 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3758 if (!arv) { continue ; }
3759 arv->delete_waves();
3762 // cleanup peak files:
3763 // - stop pending peakfile threads
3764 // - close peakfiles if any
3765 // - remove peak dir in session
3766 // - setup peakfiles (background thread)
3767 _session->cleanup_peakfiles ();
3769 // re-add waves to ARV
3770 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3771 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3772 if (!arv) { continue ; }
3773 arv->create_waves();
3778 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3780 uint32_t order_hint = UINT32_MAX;
3782 if (editor->get_selection().tracks.empty()) {
3787 we want the new routes to have their order keys set starting from
3788 the highest order key in the selection + 1 (if available).
3791 if (place == AddRouteDialog::AfterSelection) {
3792 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3794 order_hint = rtav->route()->order_key();
3797 } else if (place == AddRouteDialog::BeforeSelection) {
3798 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3800 order_hint = rtav->route()->order_key();
3802 } else if (place == AddRouteDialog::First) {
3805 /* leave order_hint at UINT32_MAX */
3808 if (order_hint == UINT32_MAX) {
3809 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3810 * not setting an order hint will place new routes last.
3815 _session->set_order_hint (order_hint);
3817 /* create a gap in the existing route order keys to accomodate new routes.*/
3818 boost::shared_ptr <RouteList> rd = _session->get_routes();
3819 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3820 boost::shared_ptr<Route> rt (*ri);
3822 if (rt->is_monitor()) {
3826 if (rt->order_key () >= order_hint) {
3827 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3833 ARDOUR_UI::start_duplicate_routes ()
3835 if (!duplicate_routes_dialog) {
3836 duplicate_routes_dialog = new DuplicateRouteDialog;
3839 if (duplicate_routes_dialog->restart (_session)) {
3843 duplicate_routes_dialog->present ();
3847 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3855 if (add_route_dialog->is_visible()) {
3856 /* we're already doing this */
3860 ResponseType r = (ResponseType) add_route_dialog->run ();
3862 add_route_dialog->hide();
3865 case RESPONSE_ACCEPT:
3872 if ((count = add_route_dialog->count()) <= 0) {
3876 setup_order_hint(add_route_dialog->insert_at());
3878 string template_path = add_route_dialog->track_template();
3879 DisplaySuspender ds;
3881 if (!template_path.empty()) {
3882 if (add_route_dialog->name_template_is_default()) {
3883 _session->new_route_from_template (count, template_path, string());
3885 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3890 ChanCount input_chan= add_route_dialog->channels ();
3891 ChanCount output_chan;
3892 string name_template = add_route_dialog->name_template ();
3893 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3894 RouteGroup* route_group = add_route_dialog->route_group ();
3895 AutoConnectOption oac = Config->get_output_auto_connect();
3897 if (oac & AutoConnectMaster) {
3898 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3899 output_chan.set (DataType::MIDI, 0);
3901 output_chan = input_chan;
3904 /* XXX do something with name template */
3906 switch (add_route_dialog->type_wanted()) {
3907 case AddRouteDialog::AudioTrack:
3908 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3910 case AddRouteDialog::MidiTrack:
3911 session_add_midi_track (route_group, count, name_template, instrument);
3913 case AddRouteDialog::MixedTrack:
3914 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3916 case AddRouteDialog::AudioBus:
3917 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3923 ARDOUR_UI::stop_video_server (bool ask_confirm)
3925 if (!video_server_process && ask_confirm) {
3926 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3928 if (video_server_process) {
3930 ArdourDialog confirm (_("Stop Video-Server"), true);
3931 Label m (_("Do you really want to stop the Video Server?"));
3932 confirm.get_vbox()->pack_start (m, true, true);
3933 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3934 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3935 confirm.show_all ();
3936 if (confirm.run() == RESPONSE_CANCEL) {
3940 delete video_server_process;
3941 video_server_process =0;
3946 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3948 ARDOUR_UI::start_video_server( float_window, true);
3952 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3958 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3959 if (video_server_process) {
3960 popup_error(_("The Video Server is already started."));
3962 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3968 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3970 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3972 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3974 video_server_dialog->set_transient_for (*float_window);
3977 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3978 video_server_dialog->hide();
3980 ResponseType r = (ResponseType) video_server_dialog->run ();
3981 video_server_dialog->hide();
3982 if (r != RESPONSE_ACCEPT) { return false; }
3983 if (video_server_dialog->show_again()) {
3984 Config->set_show_video_server_dialog(false);
3988 std::string icsd_exec = video_server_dialog->get_exec_path();
3989 std::string icsd_docroot = video_server_dialog->get_docroot();
3990 if (icsd_docroot.empty()) {
3991 #ifndef PLATFORM_WINDOWS
3992 icsd_docroot = X_("/");
3994 icsd_docroot = X_("C:\\");
3999 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4000 warning << _("Specified docroot is not an existing directory.") << endmsg;
4003 #ifndef PLATFORM_WINDOWS
4004 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4005 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4006 warning << _("Given Video Server is not an executable file.") << endmsg;
4010 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4011 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4012 warning << _("Given Video Server is not an executable file.") << endmsg;
4018 argp=(char**) calloc(9,sizeof(char*));
4019 argp[0] = strdup(icsd_exec.c_str());
4020 argp[1] = strdup("-P");
4021 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4022 argp[3] = strdup("-p");
4023 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4024 argp[5] = strdup("-C");
4025 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4026 argp[7] = strdup(icsd_docroot.c_str());
4028 stop_video_server();
4030 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4031 Config->set_video_advanced_setup(false);
4033 std::ostringstream osstream;
4034 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4035 Config->set_video_server_url(osstream.str());
4036 Config->set_video_server_docroot(icsd_docroot);
4037 Config->set_video_advanced_setup(true);
4040 if (video_server_process) {
4041 delete video_server_process;
4044 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4045 if (video_server_process->start()) {
4046 warning << _("Cannot launch the video-server") << endmsg;
4049 int timeout = 120; // 6 sec
4050 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4051 Glib::usleep (50000);
4053 if (--timeout <= 0 || !video_server_process->is_running()) break;
4056 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4058 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4059 delete video_server_process;
4060 video_server_process = 0;
4068 ARDOUR_UI::add_video (Gtk::Window* float_window)
4074 if (!start_video_server(float_window, false)) {
4075 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4080 add_video_dialog->set_transient_for (*float_window);
4083 if (add_video_dialog->is_visible()) {
4084 /* we're already doing this */
4088 ResponseType r = (ResponseType) add_video_dialog->run ();
4089 add_video_dialog->hide();
4090 if (r != RESPONSE_ACCEPT) { return; }
4092 bool local_file, orig_local_file;
4093 std::string path = add_video_dialog->file_name(local_file);
4095 std::string orig_path = path;
4096 orig_local_file = local_file;
4098 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4100 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4101 warning << string_compose(_("could not open %1"), path) << endmsg;
4104 if (!local_file && path.length() == 0) {
4105 warning << _("no video-file selected") << endmsg;
4109 std::string audio_from_video;
4110 bool detect_ltc = false;
4112 switch (add_video_dialog->import_option()) {
4113 case VTL_IMPORT_TRANSCODE:
4115 TranscodeVideoDialog *transcode_video_dialog;
4116 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4117 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4118 transcode_video_dialog->hide();
4119 if (r != RESPONSE_ACCEPT) {
4120 delete transcode_video_dialog;
4124 audio_from_video = transcode_video_dialog->get_audiofile();
4126 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4129 else if (!audio_from_video.empty()) {
4130 editor->embed_audio_from_video(
4132 video_timeline->get_offset(),
4133 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4136 switch (transcode_video_dialog->import_option()) {
4137 case VTL_IMPORT_TRANSCODED:
4138 path = transcode_video_dialog->get_filename();
4141 case VTL_IMPORT_REFERENCE:
4144 delete transcode_video_dialog;
4147 delete transcode_video_dialog;
4151 case VTL_IMPORT_NONE:
4155 /* strip _session->session_directory().video_path() from video file if possible */
4156 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4157 path=path.substr(_session->session_directory().video_path().size());
4158 if (path.at(0) == G_DIR_SEPARATOR) {
4159 path=path.substr(1);
4163 video_timeline->set_update_session_fps(auto_set_session_fps);
4165 if (video_timeline->video_file_info(path, local_file)) {
4166 XMLNode* node = new XMLNode(X_("Videotimeline"));
4167 node->add_property (X_("Filename"), path);
4168 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4169 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4170 if (orig_local_file) {
4171 node->add_property (X_("OriginalVideoFile"), orig_path);
4173 node->remove_property (X_("OriginalVideoFile"));
4175 _session->add_extra_xml (*node);
4176 _session->set_dirty ();
4178 if (!audio_from_video.empty() && detect_ltc) {
4179 std::vector<LTCFileReader::LTCMap> ltc_seq;
4182 /* TODO ask user about TV standard (LTC alignment if any) */
4183 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4184 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4186 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4188 /* TODO seek near end of file, and read LTC until end.
4189 * if it fails to find any LTC frames, scan complete file
4191 * calculate drift of LTC compared to video-duration,
4192 * ask user for reference (timecode from start/mid/end)
4195 // LTCFileReader will have written error messages
4198 ::g_unlink(audio_from_video.c_str());
4200 if (ltc_seq.size() == 0) {
4201 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4203 /* the very first TC in the file is somteimes not aligned properly */
4204 int i = ltc_seq.size() -1;
4205 ARDOUR::frameoffset_t video_start_offset =
4206 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4207 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4208 video_timeline->set_offset(video_start_offset);
4212 _session->maybe_update_session_range(
4213 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4214 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4217 if (add_video_dialog->launch_xjadeo() && local_file) {
4218 editor->set_xjadeo_sensitive(true);
4219 editor->toggle_xjadeo_proc(1);
4221 editor->toggle_xjadeo_proc(0);
4223 editor->toggle_ruler_video(true);
4228 ARDOUR_UI::remove_video ()
4230 video_timeline->close_session();
4231 editor->toggle_ruler_video(false);
4234 video_timeline->set_offset_locked(false);
4235 video_timeline->set_offset(0);
4237 /* delete session state */
4238 XMLNode* node = new XMLNode(X_("Videotimeline"));
4239 _session->add_extra_xml(*node);
4240 node = new XMLNode(X_("Videomonitor"));
4241 _session->add_extra_xml(*node);
4242 node = new XMLNode(X_("Videoexport"));
4243 _session->add_extra_xml(*node);
4244 stop_video_server();
4248 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4250 if (localcacheonly) {
4251 video_timeline->vmon_update();
4253 video_timeline->flush_cache();
4255 editor->queue_visual_videotimeline_update();
4259 ARDOUR_UI::export_video (bool range)
4261 if (ARDOUR::Config->get_show_video_export_info()) {
4262 ExportVideoInfobox infobox (_session);
4263 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4264 if (infobox.show_again()) {
4265 ARDOUR::Config->set_show_video_export_info(false);
4268 case GTK_RESPONSE_YES:
4269 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4275 export_video_dialog->set_session (_session);
4276 export_video_dialog->apply_state(editor->get_selection().time, range);
4277 export_video_dialog->run ();
4278 export_video_dialog->hide ();
4282 ARDOUR_UI::mixer_settings () const
4287 node = _session->instant_xml(X_("Mixer"));
4289 node = Config->instant_xml(X_("Mixer"));
4293 node = new XMLNode (X_("Mixer"));
4300 ARDOUR_UI::main_window_settings () const
4305 node = _session->instant_xml(X_("Main"));
4307 node = Config->instant_xml(X_("Main"));
4311 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4312 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4317 node = new XMLNode (X_("Main"));
4324 ARDOUR_UI::editor_settings () const
4329 node = _session->instant_xml(X_("Editor"));
4331 node = Config->instant_xml(X_("Editor"));
4335 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4336 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4341 node = new XMLNode (X_("Editor"));
4348 ARDOUR_UI::keyboard_settings () const
4352 node = Config->extra_xml(X_("Keyboard"));
4355 node = new XMLNode (X_("Keyboard"));
4362 ARDOUR_UI::create_xrun_marker (framepos_t where)
4365 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4366 _session->locations()->add (location);
4371 ARDOUR_UI::halt_on_xrun_message ()
4373 cerr << "HALT on xrun\n";
4374 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4379 ARDOUR_UI::xrun_handler (framepos_t where)
4385 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4387 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4388 create_xrun_marker(where);
4391 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4392 halt_on_xrun_message ();
4397 ARDOUR_UI::disk_overrun_handler ()
4399 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4401 if (!have_disk_speed_dialog_displayed) {
4402 have_disk_speed_dialog_displayed = true;
4403 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4404 The disk system on your computer\n\
4405 was not able to keep up with %1.\n\
4407 Specifically, it failed to write data to disk\n\
4408 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4409 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4415 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4416 static MessageDialog *scan_dlg = NULL;
4417 static ProgressBar *scan_pbar = NULL;
4418 static HBox *scan_tbox = NULL;
4419 static Gtk::Button *scan_timeout_button;
4422 ARDOUR_UI::cancel_plugin_scan ()
4424 PluginManager::instance().cancel_plugin_scan();
4428 ARDOUR_UI::cancel_plugin_timeout ()
4430 PluginManager::instance().cancel_plugin_timeout();
4431 scan_timeout_button->set_sensitive (false);
4435 ARDOUR_UI::plugin_scan_timeout (int timeout)
4437 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4441 scan_pbar->set_sensitive (false);
4442 scan_timeout_button->set_sensitive (true);
4443 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4446 scan_pbar->set_sensitive (false);
4447 scan_timeout_button->set_sensitive (false);
4453 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4455 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4459 const bool cancelled = PluginManager::instance().cancelled();
4460 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4461 if (cancelled && scan_dlg->is_mapped()) {
4466 if (cancelled || !can_cancel) {
4471 static Gtk::Button *cancel_button;
4473 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4474 VBox* vbox = scan_dlg->get_vbox();
4475 vbox->set_size_request(400,-1);
4476 scan_dlg->set_title (_("Scanning for plugins"));
4478 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4479 cancel_button->set_name ("EditorGTKButton");
4480 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4481 cancel_button->show();
4483 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4485 scan_tbox = manage( new HBox() );
4487 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4488 scan_timeout_button->set_name ("EditorGTKButton");
4489 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4490 scan_timeout_button->show();
4492 scan_pbar = manage(new ProgressBar());
4493 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4494 scan_pbar->set_text(_("Scan Timeout"));
4497 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4498 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4500 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4503 assert(scan_dlg && scan_tbox && cancel_button);
4505 if (type == X_("closeme")) {
4509 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4512 if (!can_cancel || !cancelled) {
4513 scan_timeout_button->set_sensitive(false);
4515 cancel_button->set_sensitive(can_cancel && !cancelled);
4521 ARDOUR_UI::gui_idle_handler ()
4524 /* due to idle calls, gtk_events_pending() may always return true */
4525 while (gtk_events_pending() && --timeout) {
4526 gtk_main_iteration ();
4531 ARDOUR_UI::disk_underrun_handler ()
4533 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4535 if (!have_disk_speed_dialog_displayed) {
4536 have_disk_speed_dialog_displayed = true;
4537 MessageDialog* msg = new MessageDialog (
4538 _main_window, string_compose (_("The disk system on your computer\n\
4539 was not able to keep up with %1.\n\
4541 Specifically, it failed to read data from disk\n\
4542 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4543 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4549 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4551 have_disk_speed_dialog_displayed = false;
4556 ARDOUR_UI::session_dialog (std::string msg)
4558 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4562 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4569 ARDOUR_UI::pending_state_dialog ()
4571 HBox* hbox = manage (new HBox());
4572 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4573 ArdourDialog dialog (_("Crash Recovery"), true);
4574 Label message (string_compose (_("\
4575 This session appears to have been in the\n\
4576 middle of recording when %1 or\n\
4577 the computer was shutdown.\n\
4579 %1 can recover any captured audio for\n\
4580 you, or it can ignore it. Please decide\n\
4581 what you would like to do.\n"), PROGRAM_NAME));
4582 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4583 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4584 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4585 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4586 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4587 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4588 dialog.set_default_response (RESPONSE_ACCEPT);
4589 dialog.set_position (WIN_POS_CENTER);
4594 switch (dialog.run ()) {
4595 case RESPONSE_ACCEPT:
4603 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4605 HBox* hbox = new HBox();
4606 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4607 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4608 Label message (string_compose (_("\
4609 This session was created with a sample rate of %1 Hz, but\n\
4610 %2 is currently running at %3 Hz. If you load this session,\n\
4611 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4613 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4614 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4615 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4616 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4617 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4618 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4619 dialog.set_default_response (RESPONSE_ACCEPT);
4620 dialog.set_position (WIN_POS_CENTER);
4625 switch (dialog.run()) {
4626 case RESPONSE_ACCEPT:
4636 ARDOUR_UI::use_config ()
4638 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4640 set_transport_controllable_state (*node);
4645 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4647 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4648 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4650 primary_clock->set (pos);
4653 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4654 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4656 secondary_clock->set (pos);
4659 if (big_clock_window) {
4660 big_clock->set (pos);
4662 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4666 ARDOUR_UI::step_edit_status_change (bool yn)
4668 // XXX should really store pre-step edit status of things
4669 // we make insensitive
4672 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4673 rec_button.set_sensitive (false);
4675 rec_button.unset_active_state ();;
4676 rec_button.set_sensitive (true);
4681 ARDOUR_UI::record_state_changed ()
4683 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4685 if (!_session || !big_clock_window) {
4686 /* why bother - the clock isn't visible */
4690 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4691 big_clock->set_active (true);
4693 big_clock->set_active (false);
4698 ARDOUR_UI::first_idle ()
4701 _session->allow_auto_play (true);
4705 editor->first_idle();
4708 Keyboard::set_can_save_keybindings (true);
4713 ARDOUR_UI::store_clock_modes ()
4715 XMLNode* node = new XMLNode(X_("ClockModes"));
4717 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4718 XMLNode* child = new XMLNode (X_("Clock"));
4720 child->add_property (X_("name"), (*x)->name());
4721 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4722 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4724 node->add_child_nocopy (*child);
4727 _session->add_extra_xml (*node);
4728 _session->set_dirty ();
4731 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4732 : Controllable (name), ui (u), type(tp)
4738 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4741 /* do nothing: these are radio-style actions */
4745 const char *action = 0;
4749 action = X_("Roll");
4752 action = X_("Stop");
4755 action = X_("GotoStart");
4758 action = X_("GotoEnd");
4761 action = X_("Loop");
4764 action = X_("PlaySelection");
4767 action = X_("Record");
4777 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4785 ARDOUR_UI::TransportControllable::get_value (void) const
4812 ARDOUR_UI::setup_profile ()
4814 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4815 Profile->set_small_screen ();
4818 if (g_getenv ("ARDOUR_SAE")) {
4819 Profile->set_sae ();
4820 Profile->set_single_package ();
4823 if (g_getenv ("TRX")) {
4824 Profile->set_trx ();
4827 if (g_getenv ("MIXBUS")) {
4828 Profile->set_mixbus ();
4833 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4835 MissingFileDialog dialog (s, str, type);
4840 int result = dialog.run ();
4847 return 1; // quit entire session load
4850 result = dialog.get_action ();
4856 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4858 AmbiguousFileDialog dialog (file, hits);
4865 return dialog.get_which ();
4868 /** Allocate our thread-local buffers */
4870 ARDOUR_UI::get_process_buffers ()
4872 _process_thread->get_buffers ();
4875 /** Drop our thread-local buffers */
4877 ARDOUR_UI::drop_process_buffers ()
4879 _process_thread->drop_buffers ();
4883 ARDOUR_UI::feedback_detected ()
4885 _feedback_exists = true;
4889 ARDOUR_UI::successful_graph_sort ()
4891 _feedback_exists = false;
4895 ARDOUR_UI::midi_panic ()
4898 _session->midi_panic();
4903 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4905 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4906 const char* end_big = "</span>";
4907 const char* start_mono = "<tt>";
4908 const char* end_mono = "</tt>";
4910 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4911 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4912 "From now on, use the -2000 version with older versions of %3"),
4913 xml_path, backup_path, PROGRAM_NAME,
4915 start_mono, end_mono), true);
4922 ARDOUR_UI::reset_peak_display ()
4924 if (!_session || !_session->master_out() || !editor_meter) return;
4925 editor_meter->clear_meters();
4926 editor_meter_max_peak = -INFINITY;
4927 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4931 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4933 if (!_session || !_session->master_out()) return;
4934 if (group == _session->master_out()->route_group()) {
4935 reset_peak_display ();
4940 ARDOUR_UI::reset_route_peak_display (Route* route)
4942 if (!_session || !_session->master_out()) return;
4943 if (_session->master_out().get() == route) {
4944 reset_peak_display ();
4949 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4951 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4952 audio_midi_setup->set_position (WIN_POS_CENTER);
4957 response = audio_midi_setup->run();
4959 case Gtk::RESPONSE_OK:
4960 if (!AudioEngine::instance()->running()) {
4974 ARDOUR_UI::transport_numpad_timeout ()
4976 _numpad_locate_happening = false;
4977 if (_numpad_timeout_connection.connected() )
4978 _numpad_timeout_connection.disconnect();
4983 ARDOUR_UI::transport_numpad_decimal ()
4985 _numpad_timeout_connection.disconnect();
4987 if (_numpad_locate_happening) {
4988 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4989 _numpad_locate_happening = false;
4991 _pending_locate_num = 0;
4992 _numpad_locate_happening = true;
4993 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
4998 ARDOUR_UI::transport_numpad_event (int num)
5000 if ( _numpad_locate_happening ) {
5001 _pending_locate_num = _pending_locate_num*10 + num;
5004 case 0: toggle_roll(false, false); break;
5005 case 1: transport_rewind(1); break;
5006 case 2: transport_forward(1); break;
5007 case 3: transport_record(true); break;
5008 case 4: toggle_session_auto_loop(); break;
5009 case 5: transport_record(false); toggle_session_auto_loop(); break;
5010 case 6: toggle_punch(); break;
5011 case 7: toggle_click(); break;
5012 case 8: toggle_auto_return(); break;
5013 case 9: toggle_follow_edits(); break;
5019 ARDOUR_UI::set_flat_buttons ()
5021 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5025 ARDOUR_UI::audioengine_became_silent ()
5027 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5029 Gtk::MESSAGE_WARNING,
5033 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5035 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5036 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5037 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5038 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5039 Gtk::HBox pay_button_box;
5040 Gtk::HBox subscribe_button_box;
5042 pay_button_box.pack_start (pay_button, true, false);
5043 subscribe_button_box.pack_start (subscribe_button, true, false);
5045 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 */
5047 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5048 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5050 msg.get_vbox()->pack_start (pay_label);
5051 msg.get_vbox()->pack_start (pay_button_box);
5052 msg.get_vbox()->pack_start (subscribe_label);
5053 msg.get_vbox()->pack_start (subscribe_button_box);
5055 msg.get_vbox()->show_all ();
5057 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5058 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5059 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5064 case Gtk::RESPONSE_YES:
5065 AudioEngine::instance()->reset_silence_countdown ();
5068 case Gtk::RESPONSE_NO:
5070 save_state_canfail ("");
5074 case Gtk::RESPONSE_CANCEL:
5076 /* don't reset, save session and exit */
5082 ARDOUR_UI::hide_application ()
5084 Application::instance ()-> hide ();
5088 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5090 /* icons, titles, WM stuff */
5092 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5094 if (window_icons.empty()) {
5095 Glib::RefPtr<Gdk::Pixbuf> icon;
5096 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5097 window_icons.push_back (icon);
5099 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5100 window_icons.push_back (icon);
5102 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5103 window_icons.push_back (icon);
5105 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5106 window_icons.push_back (icon);
5110 if (!window_icons.empty()) {
5111 window.set_default_icon_list (window_icons);
5114 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5116 if (!name.empty()) {
5120 window.set_title (title.get_string());
5121 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5123 window.set_flags (CAN_FOCUS);
5124 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5126 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5128 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5129 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5130 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5131 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5135 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5137 Gtkmm2ext::Bindings* bindings = 0;
5138 Gtk::Window* window = 0;
5140 /* until we get ardour bindings working, we are not handling key
5144 if (ev->type != GDK_KEY_PRESS) {
5148 if (event_window == &_main_window) {
5150 window = event_window;
5152 /* find current tab contents */
5154 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5156 /* see if it uses the ardour binding system */
5159 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5161 bindings = &_global_bindings;
5164 } else if (event_window != 0) {
5166 window = event_window;
5168 /* see if window uses ardour binding system */
5170 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5174 /* An empty binding set is treated as if it doesn't exist */
5176 if (bindings && bindings->empty()) {
5180 return key_press_focus_accelerator_handler (*window, ev, bindings);
5184 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5186 GtkWindow* win = window.gobj();
5187 GtkWidget* focus = gtk_window_get_focus (win);
5188 bool special_handling_of_unmodified_accelerators = false;
5189 /* consider all relevant modifiers but not LOCK or SHIFT */
5190 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5192 GdkModifierType modifier = GdkModifierType (ev->state);
5193 modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
5194 Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
5198 /* some widget has keyboard focus */
5200 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5202 /* A particular kind of focusable widget currently has keyboard
5203 * focus. All unmodified key events should go to that widget
5204 * first and not be used as an accelerator by default
5207 special_handling_of_unmodified_accelerators = true;
5211 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\n",
5214 show_gdk_event_state (ev->state),
5215 special_handling_of_unmodified_accelerators,
5216 Keyboard::some_magic_widget_has_focus(),
5218 (focus ? gtk_widget_get_name (focus) : "no focus widget")));
5220 /* This exists to allow us to override the way GTK handles
5221 key events. The normal sequence is:
5223 a) event is delivered to a GtkWindow
5224 b) accelerators/mnemonics are activated
5225 c) if (b) didn't handle the event, propagate to
5226 the focus widget and/or focus chain
5228 The problem with this is that if the accelerators include
5229 keys without modifiers, such as the space bar or the
5230 letter "e", then pressing the key while typing into
5231 a text entry widget results in the accelerator being
5232 activated, instead of the desired letter appearing
5235 There is no good way of fixing this, but this
5236 represents a compromise. The idea is that
5237 key events involving modifiers (not Shift)
5238 get routed into the activation pathway first, then
5239 get propagated to the focus widget if necessary.
5241 If the key event doesn't involve modifiers,
5242 we deliver to the focus widget first, thus allowing
5243 it to get "normal text" without interference
5246 Of course, this can also be problematic: if there
5247 is a widget with focus, then it will swallow
5248 all "normal text" accelerators.
5252 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5254 /* no special handling or there are modifiers in effect: accelerate first */
5256 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5257 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5258 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5260 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5264 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5265 KeyboardKey k (ev->state, ev->keyval);
5267 if (bindings->activate (k, Bindings::Press)) {
5268 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5273 if (try_gtk_accel_binding (win, ev, !special_handling_of_unmodified_accelerators, modifier)) {
5274 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5279 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5281 if (gtk_window_propagate_key_event (win, ev)) {
5282 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5288 /* no modifiers, propagate first */
5290 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5292 if (gtk_window_propagate_key_event (win, ev)) {
5293 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5297 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5301 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5302 KeyboardKey k (ev->state, ev->keyval);
5304 if (bindings->activate (k, Bindings::Press)) {
5305 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5311 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try GTK bindings\n");
5313 if (try_gtk_accel_binding (win, ev, !special_handling_of_unmodified_accelerators, modifier)) {
5314 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5319 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5321 KeyboardKey k (ev->state, ev->keyval);
5323 if (_global_bindings.activate (k, Bindings::Press)) {
5324 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5328 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5333 ARDOUR_UI::try_gtk_accel_binding (GtkWindow* win, GdkEventKey* ev, bool translate, GdkModifierType modifier)
5335 uint32_t fakekey = ev->keyval;
5339 /* pretend that certain key events that GTK does not allow
5340 to be used as accelerators are actually something that
5341 it does allow. but only where there are no modifiers.
5344 if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) {
5345 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tactivate (was %1 now %2) without special hanlding of unmodified accels, modifier was %3\n",
5346 ev->keyval, fakekey, show_gdk_event_state (modifier)));
5350 if (gtk_accel_groups_activate (G_OBJECT(win), fakekey, modifier)) {
5351 DEBUG_TRACE (DEBUG::Accelerators, "\tGTK accel group activated\n");