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 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
273 , about (X_("about"), _("About"))
274 , location_ui (X_("locations"), _("Locations"))
275 , route_params (X_("inspector"), _("Tracks and Busses"))
276 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
277 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
278 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
279 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
280 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
281 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
282 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
283 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
284 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
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 _hide_splash (gpointer arg)
865 ((ARDOUR_UI*)arg)->hide_splash();
870 ARDOUR_UI::starting ()
872 Application* app = Application::instance ();
874 bool brand_new_user = ArdourStartup::required ();
876 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
877 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
879 if (ARDOUR_COMMAND_LINE::check_announcements) {
880 check_announcements ();
885 /* we need to create this early because it may need to set the
886 * audio backend end up.
890 audio_midi_setup.get (true);
892 std::cerr << "audio-midi engine setup failed."<< std::endl;
896 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
897 nsm = new NSM_Client;
898 if (!nsm->init (nsm_url)) {
899 /* the ardour executable may have different names:
901 * waf's obj.target for distro versions: eg ardour4, ardourvst4
902 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
903 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
905 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
907 const char *process_name = g_getenv ("ARDOUR_SELF");
908 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
911 // wait for announce reply from nsm server
912 for ( i = 0; i < 5000; ++i) {
916 if (nsm->is_active()) {
921 error << _("NSM server did not announce itself") << endmsg;
924 // wait for open command from nsm server
925 for ( i = 0; i < 5000; ++i) {
928 if (nsm->client_id ()) {
934 error << _("NSM: no client ID provided") << endmsg;
938 if (_session && nsm) {
939 _session->set_nsm_state( nsm->is_active() );
941 error << _("NSM: no session created") << endmsg;
945 // nsm requires these actions disabled
946 vector<string> action_names;
947 action_names.push_back("SaveAs");
948 action_names.push_back("Rename");
949 action_names.push_back("New");
950 action_names.push_back("Open");
951 action_names.push_back("Recent");
952 action_names.push_back("Close");
954 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
955 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
957 act->set_sensitive (false);
964 error << _("NSM: initialization failed") << endmsg;
970 if (brand_new_user) {
971 _initial_verbose_plugin_scan = true;
976 _initial_verbose_plugin_scan = false;
977 switch (s.response ()) {
978 case Gtk::RESPONSE_OK:
985 #ifdef NO_PLUGIN_STATE
987 ARDOUR::RecentSessions rs;
988 ARDOUR::read_recent_sessions (rs);
990 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
992 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
994 /* already used Ardour, have sessions ... warn about plugin state */
996 ArdourDialog d (_("Free/Demo Version Warning"), true);
998 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
999 CheckButton c (_("Don't warn me about this again"));
1001 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"),
1002 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1003 _("It will not restore OR save any plugin settings"),
1004 _("If you load an existing session with plugin settings\n"
1005 "they will not be used and will be lost."),
1006 _("To get full access to updates without this limitation\n"
1007 "consider becoming a subscriber for a low cost every month.")));
1008 l.set_justify (JUSTIFY_CENTER);
1010 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1012 d.get_vbox()->pack_start (l, true, true);
1013 d.get_vbox()->pack_start (b, false, false, 12);
1014 d.get_vbox()->pack_start (c, false, false, 12);
1016 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1017 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1021 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1023 if (d.run () != RESPONSE_OK) {
1029 /* go get a session */
1031 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1033 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1034 std::cerr << "Cannot get session parameters."<< std::endl;
1041 WM::Manager::instance().show_visible ();
1043 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1044 * editor window, and we may want stuff to be hidden.
1046 _status_bar_visibility.update ();
1048 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1050 if (splash && splash->is_visible()) {
1051 // in 1 second, hide the splash screen
1052 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1055 /* all other dialogs are created conditionally */
1061 ARDOUR_UI::check_memory_locking ()
1063 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1064 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1068 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1070 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1072 struct rlimit limits;
1074 long pages, page_size;
1076 size_t pages_len=sizeof(pages);
1077 if ((page_size = getpagesize()) < 0 ||
1078 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1080 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1085 ram = (int64_t) pages * (int64_t) page_size;
1088 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1092 if (limits.rlim_cur != RLIM_INFINITY) {
1094 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1098 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1099 "This might cause %1 to run out of memory before your system "
1100 "runs out of memory. \n\n"
1101 "You can view the memory limit with 'ulimit -l', "
1102 "and it is normally controlled by %2"),
1105 X_("/etc/login.conf")
1107 X_(" /etc/security/limits.conf")
1111 msg.set_default_response (RESPONSE_OK);
1113 VBox* vbox = msg.get_vbox();
1115 CheckButton cb (_("Do not show this window again"));
1116 hbox.pack_start (cb, true, false);
1117 vbox->pack_start (hbox);
1122 pop_back_splash (msg);
1126 if (cb.get_active()) {
1127 XMLNode node (X_("no-memory-warning"));
1128 Config->add_instant_xml (node);
1133 #endif // !__APPLE__
1138 ARDOUR_UI::queue_finish ()
1140 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1144 ARDOUR_UI::idle_finish ()
1147 return false; /* do not call again */
1154 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1156 if (_session->dirty()) {
1157 vector<string> actions;
1158 actions.push_back (_("Don't quit"));
1159 actions.push_back (_("Just quit"));
1160 actions.push_back (_("Save and quit"));
1161 switch (ask_about_saving_session(actions)) {
1166 /* use the default name */
1167 if (save_state_canfail ("")) {
1168 /* failed - don't quit */
1169 MessageDialog msg (_main_window,
1170 string_compose (_("\
1171 %1 was unable to save your session.\n\n\
1172 If you still wish to quit, please use the\n\n\
1173 \"Just quit\" option."), PROGRAM_NAME));
1174 pop_back_splash(msg);
1184 second_connection.disconnect ();
1185 point_one_second_connection.disconnect ();
1186 point_zero_something_second_connection.disconnect();
1187 fps_connection.disconnect();
1190 delete ARDOUR_UI::instance()->video_timeline;
1191 ARDOUR_UI::instance()->video_timeline = NULL;
1192 stop_video_server();
1194 /* Save state before deleting the session, as that causes some
1195 windows to be destroyed before their visible state can be
1198 save_ardour_state ();
1200 close_all_dialogs ();
1203 _session->set_clean ();
1204 _session->remove_pending_capture_state ();
1209 halt_connection.disconnect ();
1210 AudioEngine::instance()->stop ();
1211 #ifdef WINDOWS_VST_SUPPORT
1212 fst_stop_threading();
1218 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1220 ArdourDialog window (_("Unsaved Session"));
1221 Gtk::HBox dhbox; // the hbox for the image and text
1222 Gtk::Label prompt_label;
1223 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1227 assert (actions.size() >= 3);
1229 window.add_button (actions[0], RESPONSE_REJECT);
1230 window.add_button (actions[1], RESPONSE_APPLY);
1231 window.add_button (actions[2], RESPONSE_ACCEPT);
1233 window.set_default_response (RESPONSE_ACCEPT);
1235 Gtk::Button noquit_button (msg);
1236 noquit_button.set_name ("EditorGTKButton");
1240 if (_session->snap_name() == _session->name()) {
1241 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?"),
1242 _session->snap_name());
1244 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?"),
1245 _session->snap_name());
1248 prompt_label.set_text (prompt);
1249 prompt_label.set_name (X_("PrompterLabel"));
1250 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1252 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1253 dhbox.set_homogeneous (false);
1254 dhbox.pack_start (*dimage, false, false, 5);
1255 dhbox.pack_start (prompt_label, true, false, 5);
1256 window.get_vbox()->pack_start (dhbox);
1258 window.set_name (_("Prompter"));
1259 window.set_modal (true);
1260 window.set_resizable (false);
1263 prompt_label.show();
1268 ResponseType r = (ResponseType) window.run();
1273 case RESPONSE_ACCEPT: // save and get out of here
1275 case RESPONSE_APPLY: // get out of here
1286 ARDOUR_UI::every_second ()
1289 update_xrun_count ();
1290 update_buffer_load ();
1291 update_disk_space ();
1292 update_timecode_format ();
1293 update_peak_thread_work ();
1295 if (nsm && nsm->is_active ()) {
1298 if (!_was_dirty && _session->dirty ()) {
1302 else if (_was_dirty && !_session->dirty ()){
1310 ARDOUR_UI::every_point_one_seconds ()
1312 // TODO get rid of this..
1313 // ShuttleControl is updated directly via TransportStateChange signal
1317 ARDOUR_UI::every_point_zero_something_seconds ()
1319 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1321 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1322 float mpeak = editor_meter->update_meters();
1323 if (mpeak > editor_meter_max_peak) {
1324 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1325 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1332 ARDOUR_UI::set_fps_timeout_connection ()
1334 unsigned int interval = 40;
1335 if (!_session) return;
1336 if (_session->timecode_frames_per_second() != 0) {
1337 /* ideally we'll use a select() to sleep and not accumulate
1338 * idle time to provide a regular periodic signal.
1339 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1340 * However, that'll require a dedicated thread and cross-thread
1341 * signals to the GUI Thread..
1343 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1344 * _session->frame_rate() / _session->nominal_frame_rate()
1345 / _session->timecode_frames_per_second()
1347 #ifdef PLATFORM_WINDOWS
1348 // the smallest windows scheduler time-slice is ~15ms.
1349 // periodic GUI timeouts shorter than that will cause
1350 // WaitForSingleObject to spinlock (100% of one CPU Core)
1351 // and gtk never enters idle mode.
1352 // also changing timeBeginPeriod(1) does not affect that in
1353 // any beneficial way, so we just limit the max rate for now.
1354 interval = std::max(30u, interval); // at most ~33Hz.
1356 interval = std::max(8u, interval); // at most 120Hz.
1359 fps_connection.disconnect();
1360 Timers::set_fps_interval (interval);
1364 ARDOUR_UI::update_sample_rate (framecnt_t)
1368 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1370 if (!AudioEngine::instance()->connected()) {
1372 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1376 framecnt_t rate = AudioEngine::instance()->sample_rate();
1379 /* no sample rate available */
1380 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1383 if (fmod (rate, 1000.0) != 0.0) {
1384 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1385 (float) rate / 1000.0f,
1386 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1388 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1390 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1394 sample_rate_label.set_markup (buf);
1398 ARDOUR_UI::update_format ()
1401 format_label.set_text ("");
1406 s << _("File:") << X_(" <span foreground=\"green\">");
1408 switch (_session->config.get_native_file_header_format ()) {
1440 switch (_session->config.get_native_file_data_format ()) {
1454 format_label.set_markup (s.str ());
1458 ARDOUR_UI::update_xrun_count ()
1462 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1463 should also be changed.
1467 const unsigned int x = _session->get_xrun_count ();
1469 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1471 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1474 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1476 xrun_label.set_markup (buf);
1477 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1481 ARDOUR_UI::update_cpu_load ()
1485 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1486 should also be changed.
1489 double const c = AudioEngine::instance()->get_dsp_load ();
1490 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1491 cpu_load_label.set_markup (buf);
1495 ARDOUR_UI::update_peak_thread_work ()
1498 const int c = SourceFactory::peak_work_queue_length ();
1500 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1501 peak_thread_work_label.set_markup (buf);
1503 peak_thread_work_label.set_markup (X_(""));
1508 ARDOUR_UI::update_buffer_load ()
1512 uint32_t const playback = _session ? _session->playback_load () : 100;
1513 uint32_t const capture = _session ? _session->capture_load () : 100;
1515 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1516 should also be changed.
1522 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1523 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1524 playback <= 5 ? X_("red") : X_("green"),
1526 capture <= 5 ? X_("red") : X_("green"),
1530 buffer_load_label.set_markup (buf);
1532 buffer_load_label.set_text ("");
1537 ARDOUR_UI::count_recenabled_streams (Route& route)
1539 Track* track = dynamic_cast<Track*>(&route);
1540 if (track && track->record_enabled()) {
1541 rec_enabled_streams += track->n_inputs().n_total();
1546 ARDOUR_UI::update_disk_space()
1548 if (_session == 0) {
1552 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1554 framecnt_t fr = _session->frame_rate();
1557 /* skip update - no SR available */
1562 /* Available space is unknown */
1563 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1564 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1565 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1567 rec_enabled_streams = 0;
1568 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1570 framecnt_t frames = opt_frames.get_value_or (0);
1572 if (rec_enabled_streams) {
1573 frames /= rec_enabled_streams;
1580 hrs = frames / (fr * 3600);
1583 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1585 frames -= hrs * fr * 3600;
1586 mins = frames / (fr * 60);
1587 frames -= mins * fr * 60;
1590 bool const low = (hrs == 0 && mins <= 30);
1594 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1595 low ? X_("red") : X_("green"),
1601 disk_space_label.set_markup (buf);
1605 ARDOUR_UI::update_timecode_format ()
1611 TimecodeSlave* tcslave;
1612 SyncSource sync_src = Config->get_sync_source();
1614 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1615 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1620 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1621 matching ? X_("green") : X_("red"),
1622 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1624 snprintf (buf, sizeof (buf), "TC: n/a");
1627 timecode_format_label.set_markup (buf);
1631 ARDOUR_UI::update_wall_clock ()
1635 static int last_min = -1;
1638 tm_now = localtime (&now);
1639 if (last_min != tm_now->tm_min) {
1641 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1642 wall_clock_label.set_text (buf);
1643 last_min = tm_now->tm_min;
1650 ARDOUR_UI::open_recent_session ()
1652 bool can_return = (_session != 0);
1654 SessionDialog recent_session_dialog;
1658 ResponseType r = (ResponseType) recent_session_dialog.run ();
1661 case RESPONSE_ACCEPT:
1665 recent_session_dialog.hide();
1672 recent_session_dialog.hide();
1676 std::string path = recent_session_dialog.session_folder();
1677 std::string state = recent_session_dialog.session_name (should_be_new);
1679 if (should_be_new == true) {
1683 _session_is_new = false;
1685 if (load_session (path, state) == 0) {
1694 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1696 if (!AudioEngine::instance()->connected()) {
1697 MessageDialog msg (parent, string_compose (
1698 _("%1 is not connected to any audio backend.\n"
1699 "You cannot open or close sessions in this condition"),
1701 pop_back_splash (msg);
1709 ARDOUR_UI::open_session ()
1711 if (!check_audioengine(*editor)) {
1715 /* ardour sessions are folders */
1716 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1717 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1718 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1719 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1722 string session_parent_dir = Glib::path_get_dirname(_session->path());
1723 open_session_selector.set_current_folder(session_parent_dir);
1725 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1728 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1730 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1731 string default_session_folder = Config->get_default_session_parent_dir();
1732 open_session_selector.add_shortcut_folder (default_session_folder);
1734 catch (Glib::Error & e) {
1735 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1738 FileFilter session_filter;
1739 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1740 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1741 open_session_selector.add_filter (session_filter);
1742 open_session_selector.set_filter (session_filter);
1744 int response = open_session_selector.run();
1745 open_session_selector.hide ();
1747 if (response == Gtk::RESPONSE_CANCEL) {
1751 string session_path = open_session_selector.get_filename();
1755 if (session_path.length() > 0) {
1756 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1757 _session_is_new = isnew;
1758 load_session (path, name);
1765 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1766 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1768 list<boost::shared_ptr<MidiTrack> > tracks;
1770 if (_session == 0) {
1771 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1776 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1778 if (tracks.size() != how_many) {
1779 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1784 MessageDialog msg (_main_window,
1785 string_compose (_("There are insufficient ports available\n\
1786 to create a new track or bus.\n\
1787 You should save %1, exit and\n\
1788 restart with more ports."), PROGRAM_NAME));
1795 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1797 ChanCount one_midi_channel;
1798 one_midi_channel.set (DataType::MIDI, 1);
1801 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1806 ARDOUR_UI::session_add_audio_route (
1808 int32_t input_channels,
1809 int32_t output_channels,
1810 ARDOUR::TrackMode mode,
1811 RouteGroup* route_group,
1813 string const & name_template
1816 list<boost::shared_ptr<AudioTrack> > tracks;
1819 if (_session == 0) {
1820 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1826 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1828 if (tracks.size() != how_many) {
1829 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1835 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1837 if (routes.size() != how_many) {
1838 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1845 MessageDialog msg (_main_window,
1846 string_compose (_("There are insufficient ports available\n\
1847 to create a new track or bus.\n\
1848 You should save %1, exit and\n\
1849 restart with more ports."), PROGRAM_NAME));
1850 pop_back_splash (msg);
1856 ARDOUR_UI::transport_goto_start ()
1859 _session->goto_start();
1861 /* force displayed area in editor to start no matter
1862 what "follow playhead" setting is.
1866 editor->center_screen (_session->current_start_frame ());
1872 ARDOUR_UI::transport_goto_zero ()
1875 _session->request_locate (0);
1877 /* force displayed area in editor to start no matter
1878 what "follow playhead" setting is.
1882 editor->reset_x_origin (0);
1888 ARDOUR_UI::transport_goto_wallclock ()
1890 if (_session && editor) {
1897 localtime_r (&now, &tmnow);
1899 framecnt_t frame_rate = _session->frame_rate();
1901 if (frame_rate == 0) {
1902 /* no frame rate available */
1906 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1907 frames += tmnow.tm_min * (60 * frame_rate);
1908 frames += tmnow.tm_sec * frame_rate;
1910 _session->request_locate (frames, _session->transport_rolling ());
1912 /* force displayed area in editor to start no matter
1913 what "follow playhead" setting is.
1917 editor->center_screen (frames);
1923 ARDOUR_UI::transport_goto_end ()
1926 framepos_t const frame = _session->current_end_frame();
1927 _session->request_locate (frame);
1929 /* force displayed area in editor to start no matter
1930 what "follow playhead" setting is.
1934 editor->center_screen (frame);
1940 ARDOUR_UI::transport_stop ()
1946 if (_session->is_auditioning()) {
1947 _session->cancel_audition ();
1951 _session->request_stop (false, true);
1954 /** Check if any tracks are record enabled. If none are, record enable all of them.
1955 * @return true if track record-enabled status was changed, false otherwise.
1958 ARDOUR_UI::trx_record_enable_all_tracks ()
1964 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1965 bool none_record_enabled = true;
1967 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1968 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1971 if (t->record_enabled()) {
1972 none_record_enabled = false;
1977 if (none_record_enabled) {
1978 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1981 return none_record_enabled;
1985 ARDOUR_UI::transport_record (bool roll)
1988 switch (_session->record_status()) {
1989 case Session::Disabled:
1990 if (_session->ntracks() == 0) {
1991 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."));
1995 if (Profile->get_trx()) {
1996 roll = trx_record_enable_all_tracks ();
1998 _session->maybe_enable_record ();
2003 case Session::Recording:
2005 _session->request_stop();
2007 _session->disable_record (false, true);
2011 case Session::Enabled:
2012 _session->disable_record (false, true);
2018 ARDOUR_UI::transport_roll ()
2024 if (_session->is_auditioning()) {
2029 if (_session->config.get_external_sync()) {
2030 switch (Config->get_sync_source()) {
2034 /* transport controlled by the master */
2040 bool rolling = _session->transport_rolling();
2042 if (_session->get_play_loop()) {
2044 /* If loop playback is not a mode, then we should cancel
2045 it when this action is requested. If it is a mode
2046 we just leave it in place.
2049 if (!Config->get_loop_is_mode()) {
2050 /* XXX it is not possible to just leave seamless loop and keep
2051 playing at present (nov 4th 2009)
2053 if (!Config->get_seamless_loop()) {
2054 /* stop loop playback and stop rolling */
2055 _session->request_play_loop (false, true);
2056 } else if (rolling) {
2057 /* stop loop playback but keep rolling */
2058 _session->request_play_loop (false, false);
2062 } else if (_session->get_play_range () ) {
2063 /* stop playing a range if we currently are */
2064 _session->request_play_range (0, true);
2068 _session->request_transport_speed (1.0f);
2073 ARDOUR_UI::get_smart_mode() const
2075 return ( editor->get_smart_mode() );
2080 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2086 if (_session->is_auditioning()) {
2087 _session->cancel_audition ();
2091 if (_session->config.get_external_sync()) {
2092 switch (Config->get_sync_source()) {
2096 /* transport controlled by the master */
2101 bool rolling = _session->transport_rolling();
2102 bool affect_transport = true;
2104 if (rolling && roll_out_of_bounded_mode) {
2105 /* drop out of loop/range playback but leave transport rolling */
2106 if (_session->get_play_loop()) {
2107 if (_session->actively_recording()) {
2109 /* just stop using the loop, then actually stop
2112 _session->request_play_loop (false, affect_transport);
2115 if (Config->get_seamless_loop()) {
2116 /* the disk buffers contain copies of the loop - we can't
2117 just keep playing, so stop the transport. the user
2118 can restart as they wish.
2120 affect_transport = true;
2122 /* disk buffers are normal, so we can keep playing */
2123 affect_transport = false;
2125 _session->request_play_loop (false, affect_transport);
2127 } else if (_session->get_play_range ()) {
2128 affect_transport = false;
2129 _session->request_play_range (0, true);
2133 if (affect_transport) {
2135 _session->request_stop (with_abort, true);
2137 /* the only external sync condition we can be in here
2138 * would be Engine (JACK) sync, in which case we still
2142 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
2143 _session->request_play_range (&editor->get_selection().time, true);
2144 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2146 _session->request_transport_speed (1.0f);
2152 ARDOUR_UI::toggle_session_auto_loop ()
2158 Location * looploc = _session->locations()->auto_loop_location();
2164 if (_session->get_play_loop()) {
2166 /* looping enabled, our job is to disable it */
2168 _session->request_play_loop (false);
2172 /* looping not enabled, our job is to enable it.
2174 loop-is-NOT-mode: this action always starts the transport rolling.
2175 loop-IS-mode: this action simply sets the loop play mechanism, but
2176 does not start transport.
2178 if (Config->get_loop_is_mode()) {
2179 _session->request_play_loop (true, false);
2181 _session->request_play_loop (true, true);
2185 //show the loop markers
2186 looploc->set_hidden (false, this);
2190 ARDOUR_UI::transport_play_selection ()
2196 editor->play_selection ();
2200 ARDOUR_UI::transport_play_preroll ()
2205 editor->play_with_preroll ();
2209 ARDOUR_UI::transport_rewind (int option)
2211 float current_transport_speed;
2214 current_transport_speed = _session->transport_speed();
2216 if (current_transport_speed >= 0.0f) {
2219 _session->request_transport_speed (-1.0f);
2222 _session->request_transport_speed (-4.0f);
2225 _session->request_transport_speed (-0.5f);
2230 _session->request_transport_speed (current_transport_speed * 1.5f);
2236 ARDOUR_UI::transport_forward (int option)
2242 float current_transport_speed = _session->transport_speed();
2244 if (current_transport_speed <= 0.0f) {
2247 _session->request_transport_speed (1.0f);
2250 _session->request_transport_speed (4.0f);
2253 _session->request_transport_speed (0.5f);
2258 _session->request_transport_speed (current_transport_speed * 1.5f);
2263 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2269 boost::shared_ptr<Route> r;
2271 if ((r = _session->route_by_remote_id (rid)) != 0) {
2273 boost::shared_ptr<Track> t;
2275 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2276 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2282 ARDOUR_UI::map_transport_state ()
2285 auto_loop_button.unset_active_state ();
2286 play_selection_button.unset_active_state ();
2287 roll_button.unset_active_state ();
2288 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2292 shuttle_box->map_transport_state ();
2294 float sp = _session->transport_speed();
2300 if (_session->get_play_range()) {
2302 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2303 roll_button.unset_active_state ();
2304 auto_loop_button.unset_active_state ();
2306 } else if (_session->get_play_loop ()) {
2308 auto_loop_button.set_active (true);
2309 play_selection_button.set_active (false);
2310 if (Config->get_loop_is_mode()) {
2311 roll_button.set_active (true);
2313 roll_button.set_active (false);
2318 roll_button.set_active (true);
2319 play_selection_button.set_active (false);
2320 auto_loop_button.set_active (false);
2323 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2324 /* light up both roll and play-selection if they are joined */
2325 roll_button.set_active (true);
2326 play_selection_button.set_active (true);
2329 stop_button.set_active (false);
2333 stop_button.set_active (true);
2334 roll_button.set_active (false);
2335 play_selection_button.set_active (false);
2336 if (Config->get_loop_is_mode ()) {
2337 auto_loop_button.set_active (_session->get_play_loop());
2339 auto_loop_button.set_active (false);
2341 update_disk_space ();
2346 ARDOUR_UI::blink_handler (bool blink_on)
2348 transport_rec_enable_blink (blink_on);
2349 solo_blink (blink_on);
2350 sync_blink (blink_on);
2351 audition_blink (blink_on);
2352 feedback_blink (blink_on);
2353 error_blink (blink_on);
2357 ARDOUR_UI::update_clocks ()
2359 if (!_session) return;
2361 if (editor && !editor->dragging_playhead()) {
2362 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2367 ARDOUR_UI::start_clocking ()
2369 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2370 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2372 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2377 ARDOUR_UI::stop_clocking ()
2379 clock_signal_connection.disconnect ();
2383 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2387 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2389 label->set_text (buf);
2390 bar->set_fraction (fraction);
2392 /* process events, redraws, etc. */
2394 while (gtk_events_pending()) {
2395 gtk_main_iteration ();
2398 return true; /* continue with save-as */
2402 ARDOUR_UI::save_session_as ()
2408 if (!save_as_dialog) {
2409 save_as_dialog = new SaveAsDialog;
2412 save_as_dialog->set_name (_session->name());
2414 int response = save_as_dialog->run ();
2416 save_as_dialog->hide ();
2419 case Gtk::RESPONSE_OK:
2428 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2429 sa.new_name = save_as_dialog->new_name ();
2430 sa.switch_to = save_as_dialog->switch_to();
2431 sa.copy_media = save_as_dialog->copy_media();
2432 sa.copy_external = save_as_dialog->copy_external();
2433 sa.include_media = save_as_dialog->include_media ();
2435 /* Only bother with a progress dialog if we're going to copy
2436 media into the save-as target. Without that choice, this
2437 will be very fast because we're only talking about a few kB's to
2438 perhaps a couple of MB's of data.
2441 ArdourDialog progress_dialog (_("Save As"), true);
2443 if (sa.include_media && sa.copy_media) {
2446 Gtk::ProgressBar progress_bar;
2448 progress_dialog.get_vbox()->pack_start (label);
2449 progress_dialog.get_vbox()->pack_start (progress_bar);
2451 progress_bar.show ();
2453 /* this signal will be emitted from within this, the calling thread,
2454 * after every file is copied. It provides information on percentage
2455 * complete (in terms of total data to copy), the number of files
2456 * copied so far, and the total number to copy.
2461 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2463 progress_dialog.show_all ();
2464 progress_dialog.present ();
2467 if (_session->save_as (sa)) {
2469 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2473 if (!sa.include_media) {
2474 unload_session (false);
2475 load_session (sa.final_session_folder_name, sa.new_name);
2480 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2484 struct tm local_time;
2487 localtime_r (&n, &local_time);
2488 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2490 save_state (timebuf, switch_to_it);
2495 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2499 prompter.get_result (snapname);
2501 bool do_save = (snapname.length() != 0);
2504 char illegal = Session::session_name_is_legal(snapname);
2506 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2507 "snapshot names may not contain a '%1' character"), illegal));
2513 vector<std::string> p;
2514 get_state_files_in_directory (_session->session_directory().root_path(), p);
2515 vector<string> n = get_file_names_no_extension (p);
2517 if (find (n.begin(), n.end(), snapname) != n.end()) {
2519 do_save = overwrite_file_dialog (prompter,
2520 _("Confirm Snapshot Overwrite"),
2521 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2525 save_state (snapname, switch_to_it);
2535 /** Ask the user for the name of a new snapshot and then take it.
2539 ARDOUR_UI::snapshot_session (bool switch_to_it)
2541 ArdourPrompter prompter (true);
2543 prompter.set_name ("Prompter");
2544 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2546 prompter.set_title (_("Save as..."));
2547 prompter.set_prompt (_("New session name"));
2549 prompter.set_title (_("Take Snapshot"));
2550 prompter.set_prompt (_("Name of new snapshot"));
2554 prompter.set_initial_text (_session->snap_name());
2558 struct tm local_time;
2561 localtime_r (&n, &local_time);
2562 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2563 prompter.set_initial_text (timebuf);
2566 bool finished = false;
2568 switch (prompter.run()) {
2569 case RESPONSE_ACCEPT:
2571 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2582 /** Ask the user for a new session name and then rename the session to it.
2586 ARDOUR_UI::rename_session ()
2592 ArdourPrompter prompter (true);
2595 prompter.set_name ("Prompter");
2596 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2597 prompter.set_title (_("Rename Session"));
2598 prompter.set_prompt (_("New session name"));
2601 switch (prompter.run()) {
2602 case RESPONSE_ACCEPT:
2604 prompter.get_result (name);
2606 bool do_rename = (name.length() != 0);
2609 char illegal = Session::session_name_is_legal (name);
2612 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2613 "session names may not contain a '%1' character"), illegal));
2618 switch (_session->rename (name)) {
2620 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2621 msg.set_position (WIN_POS_MOUSE);
2629 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2630 msg.set_position (WIN_POS_MOUSE);
2646 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2648 if (!_session || _session->deletion_in_progress()) {
2652 XMLNode* node = new XMLNode (X_("UI"));
2654 WM::Manager::instance().add_state (*node);
2656 node->add_child_nocopy (gui_object_state->get_state());
2658 _session->add_extra_xml (*node);
2660 if (export_video_dialog) {
2661 _session->add_extra_xml (export_video_dialog->get_state());
2664 save_state_canfail (name, switch_to_it);
2668 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2673 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2678 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2683 ARDOUR_UI::primary_clock_value_changed ()
2686 _session->request_locate (primary_clock->current_time ());
2691 ARDOUR_UI::big_clock_value_changed ()
2694 _session->request_locate (big_clock->current_time ());
2699 ARDOUR_UI::secondary_clock_value_changed ()
2702 _session->request_locate (secondary_clock->current_time ());
2707 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2709 if (_session == 0) {
2713 if (_session->step_editing()) {
2717 Session::RecordState const r = _session->record_status ();
2718 bool const h = _session->have_rec_enabled_track ();
2720 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2722 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2724 rec_button.set_active_state (Gtkmm2ext::Off);
2726 } else if (r == Session::Recording && h) {
2727 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2729 rec_button.unset_active_state ();
2734 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2738 prompter.get_result (name);
2740 if (name.length()) {
2741 int failed = _session->save_template (name);
2743 if (failed == -2) { /* file already exists. */
2744 bool overwrite = overwrite_file_dialog (prompter,
2745 _("Confirm Template Overwrite"),
2746 _("A template already exists with that name. Do you want to overwrite it?"));
2749 _session->save_template (name, true);
2761 ARDOUR_UI::save_template ()
2763 ArdourPrompter prompter (true);
2765 if (!check_audioengine(*editor)) {
2769 prompter.set_name (X_("Prompter"));
2770 prompter.set_title (_("Save Template"));
2771 prompter.set_prompt (_("Name for template:"));
2772 prompter.set_initial_text(_session->name() + _("-template"));
2773 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2775 bool finished = false;
2777 switch (prompter.run()) {
2778 case RESPONSE_ACCEPT:
2779 finished = process_save_template_prompter (prompter);
2790 ARDOUR_UI::edit_metadata ()
2792 SessionMetadataEditor dialog;
2793 dialog.set_session (_session);
2794 dialog.grab_focus ();
2799 ARDOUR_UI::import_metadata ()
2801 SessionMetadataImporter dialog;
2802 dialog.set_session (_session);
2807 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2809 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2811 MessageDialog msg (str,
2813 Gtk::MESSAGE_WARNING,
2814 Gtk::BUTTONS_YES_NO,
2818 msg.set_name (X_("OpenExistingDialog"));
2819 msg.set_title (_("Open Existing Session"));
2820 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2821 msg.set_position (Gtk::WIN_POS_CENTER);
2822 pop_back_splash (msg);
2824 switch (msg.run()) {
2833 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2835 BusProfile bus_profile;
2837 if (nsm || Profile->get_sae()) {
2839 bus_profile.master_out_channels = 2;
2840 bus_profile.input_ac = AutoConnectPhysical;
2841 bus_profile.output_ac = AutoConnectMaster;
2842 bus_profile.requested_physical_in = 0; // use all available
2843 bus_profile.requested_physical_out = 0; // use all available
2847 /* get settings from advanced section of NSD */
2849 if (sd.create_master_bus()) {
2850 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2852 bus_profile.master_out_channels = 0;
2855 if (sd.connect_inputs()) {
2856 bus_profile.input_ac = AutoConnectPhysical;
2858 bus_profile.input_ac = AutoConnectOption (0);
2861 bus_profile.output_ac = AutoConnectOption (0);
2863 if (sd.connect_outputs ()) {
2864 if (sd.connect_outs_to_master()) {
2865 bus_profile.output_ac = AutoConnectMaster;
2866 } else if (sd.connect_outs_to_physical()) {
2867 bus_profile.output_ac = AutoConnectPhysical;
2871 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2872 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2875 if (build_session (session_path, session_name, bus_profile)) {
2883 ARDOUR_UI::load_from_application_api (const std::string& path)
2885 ARDOUR_COMMAND_LINE::session_name = path;
2886 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2888 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2890 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2891 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2892 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2893 * -> SessionDialog is not displayed
2896 if (_session_dialog) {
2897 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2898 std::string session_path = path;
2899 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2900 session_path = Glib::path_get_dirname (session_path);
2902 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2903 _session_dialog->set_provided_session (session_name, session_path);
2904 _session_dialog->response (RESPONSE_NONE);
2905 _session_dialog->hide();
2910 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2911 /* /path/to/foo => /path/to/foo, foo */
2912 rv = load_session (path, basename_nosuffix (path));
2914 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2915 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2918 // if load_session fails -> pop up SessionDialog.
2920 ARDOUR_COMMAND_LINE::session_name = "";
2922 if (get_session_parameters (true, false)) {
2926 goto_editor_window ();
2930 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2932 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2934 string session_name;
2935 string session_path;
2936 string template_name;
2938 bool likely_new = false;
2939 bool cancel_not_quit;
2941 /* deal with any existing DIRTY session now, rather than later. don't
2942 * treat a non-dirty session this way, so that it stays visible
2943 * as we bring up the new session dialog.
2946 if (_session && ARDOUR_UI::instance()->video_timeline) {
2947 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2950 /* if there is already a session, relabel the button
2951 on the SessionDialog so that we don't Quit directly
2953 cancel_not_quit = (_session != 0);
2955 if (_session && _session->dirty()) {
2956 if (unload_session (false)) {
2957 /* unload cancelled by user */
2960 ARDOUR_COMMAND_LINE::session_name = "";
2963 if (!load_template.empty()) {
2964 should_be_new = true;
2965 template_name = load_template;
2968 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2969 session_path = ARDOUR_COMMAND_LINE::session_name;
2971 if (!session_path.empty()) {
2972 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2973 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2974 /* session/snapshot file, change path to be dir */
2975 session_path = Glib::path_get_dirname (session_path);
2980 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2982 _session_dialog = &session_dialog;
2985 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2987 /* if they named a specific statefile, use it, otherwise they are
2988 just giving a session folder, and we want to use it as is
2989 to find the session.
2992 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2994 if (suffix != string::npos) {
2995 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2996 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2997 session_name = Glib::path_get_basename (session_name);
2999 session_path = ARDOUR_COMMAND_LINE::session_name;
3000 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3005 session_dialog.clear_given ();
3008 if (should_be_new || session_name.empty()) {
3009 /* need the dialog to get info from user */
3011 cerr << "run dialog\n";
3013 switch (session_dialog.run()) {
3014 case RESPONSE_ACCEPT:
3017 /* this is used for async * app->ShouldLoad(). */
3018 continue; // while loop
3021 if (quit_on_cancel) {
3022 // JE - Currently (July 2014) this section can only get reached if the
3023 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3024 // point does NOT indicate an abnormal termination). Therefore, let's
3025 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3027 pthread_cancel_all ();
3035 session_dialog.hide ();
3038 /* if we run the startup dialog again, offer more than just "new session" */
3040 should_be_new = false;
3042 session_name = session_dialog.session_name (likely_new);
3043 session_path = session_dialog.session_folder ();
3049 string::size_type suffix = session_name.find (statefile_suffix);
3051 if (suffix != string::npos) {
3052 session_name = session_name.substr (0, suffix);
3055 /* this shouldn't happen, but we catch it just in case it does */
3057 if (session_name.empty()) {
3061 if (session_dialog.use_session_template()) {
3062 template_name = session_dialog.session_template_name();
3063 _session_is_new = true;
3066 if (session_name[0] == G_DIR_SEPARATOR ||
3067 #ifdef PLATFORM_WINDOWS
3068 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3070 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3071 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3076 /* absolute path or cwd-relative path specified for session name: infer session folder
3077 from what was given.
3080 session_path = Glib::path_get_dirname (session_name);
3081 session_name = Glib::path_get_basename (session_name);
3085 session_path = session_dialog.session_folder();
3087 char illegal = Session::session_name_is_legal (session_name);
3090 MessageDialog msg (session_dialog,
3091 string_compose (_("To ensure compatibility with various systems\n"
3092 "session names may not contain a '%1' character"),
3095 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3100 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3103 if (likely_new && !nsm) {
3105 std::string existing = Glib::build_filename (session_path, session_name);
3107 if (!ask_about_loading_existing_session (existing)) {
3108 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3113 _session_is_new = false;
3118 pop_back_splash (session_dialog);
3119 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3121 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3125 char illegal = Session::session_name_is_legal(session_name);
3128 pop_back_splash (session_dialog);
3129 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3130 "session names may not contain a '%1' character"), illegal));
3132 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3136 _session_is_new = true;
3139 if (likely_new && template_name.empty()) {
3141 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3145 ret = load_session (session_path, session_name, template_name);
3148 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3152 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3153 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3157 /* clear this to avoid endless attempts to load the
3161 ARDOUR_COMMAND_LINE::session_name = "";
3165 _session_dialog = NULL;
3171 ARDOUR_UI::close_session()
3173 if (!check_audioengine(*editor)) {
3177 if (unload_session (true)) {
3181 ARDOUR_COMMAND_LINE::session_name = "";
3183 if (get_session_parameters (true, false)) {
3188 /** @param snap_name Snapshot name (without .ardour suffix).
3189 * @return -2 if the load failed because we are not connected to the AudioEngine.
3192 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3194 Session *new_session;
3199 unload_status = unload_session ();
3201 if (unload_status < 0) {
3203 } else if (unload_status > 0) {
3209 session_loaded = false;
3211 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3214 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3217 /* this one is special */
3219 catch (AudioEngine::PortRegistrationFailure& err) {
3221 MessageDialog msg (err.what(),
3224 Gtk::BUTTONS_CLOSE);
3226 msg.set_title (_("Port Registration Error"));
3227 msg.set_secondary_text (_("Click the Close button to try again."));
3228 msg.set_position (Gtk::WIN_POS_CENTER);
3229 pop_back_splash (msg);
3232 int response = msg.run ();
3237 case RESPONSE_CANCEL:
3244 catch (SessionException e) {
3245 MessageDialog msg (string_compose(
3246 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3247 path, snap_name, e.what()),
3252 msg.set_title (_("Loading Error"));
3253 msg.set_position (Gtk::WIN_POS_CENTER);
3254 pop_back_splash (msg);
3266 MessageDialog msg (string_compose(
3267 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3273 msg.set_title (_("Loading Error"));
3274 msg.set_position (Gtk::WIN_POS_CENTER);
3275 pop_back_splash (msg);
3287 list<string> const u = new_session->unknown_processors ();
3289 MissingPluginDialog d (_session, u);
3294 if (!new_session->writable()) {
3295 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3300 msg.set_title (_("Read-only Session"));
3301 msg.set_position (Gtk::WIN_POS_CENTER);
3302 pop_back_splash (msg);
3309 /* Now the session been created, add the transport controls */
3310 new_session->add_controllable(roll_controllable);
3311 new_session->add_controllable(stop_controllable);
3312 new_session->add_controllable(goto_start_controllable);
3313 new_session->add_controllable(goto_end_controllable);
3314 new_session->add_controllable(auto_loop_controllable);
3315 new_session->add_controllable(play_selection_controllable);
3316 new_session->add_controllable(rec_controllable);
3318 set_session (new_session);
3320 session_loaded = true;
3323 _session->set_clean ();
3326 #ifdef WINDOWS_VST_SUPPORT
3327 fst_stop_threading();
3331 Timers::TimerSuspender t;
3335 #ifdef WINDOWS_VST_SUPPORT
3336 fst_start_threading();
3345 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3347 Session *new_session;
3350 session_loaded = false;
3351 x = unload_session ();
3359 _session_is_new = true;
3362 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3365 catch (SessionException e) {
3367 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3368 msg.set_title (_("Loading Error"));
3369 msg.set_position (Gtk::WIN_POS_CENTER);
3370 pop_back_splash (msg);
3376 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3377 msg.set_title (_("Loading Error"));
3378 msg.set_position (Gtk::WIN_POS_CENTER);
3379 pop_back_splash (msg);
3384 /* Give the new session the default GUI state, if such things exist */
3387 n = Config->instant_xml (X_("Editor"));
3389 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3390 new_session->add_instant_xml (*n, false);
3392 n = Config->instant_xml (X_("Mixer"));
3394 new_session->add_instant_xml (*n, false);
3397 /* Put the playhead at 0 and scroll fully left */
3398 n = new_session->instant_xml (X_("Editor"));
3400 n->add_property (X_("playhead"), X_("0"));
3401 n->add_property (X_("left-frame"), X_("0"));
3404 set_session (new_session);
3406 session_loaded = true;
3408 new_session->save_state(new_session->name());
3414 ARDOUR_UI::launch_chat ()
3416 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3418 dialog.set_title (_("About the Chat"));
3419 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."));
3421 switch (dialog.run()) {
3424 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3425 #elif defined PLATFORM_WINDOWS
3426 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3428 open_uri("http://webchat.freenode.net/?channels=ardour");
3437 ARDOUR_UI::launch_manual ()
3439 PBD::open_uri (Config->get_tutorial_manual_url());
3443 ARDOUR_UI::launch_reference ()
3445 PBD::open_uri (Config->get_reference_manual_url());
3449 ARDOUR_UI::launch_tracker ()
3451 PBD::open_uri ("http://tracker.ardour.org");
3455 ARDOUR_UI::launch_subscribe ()
3457 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3461 ARDOUR_UI::launch_cheat_sheet ()
3464 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3466 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3471 ARDOUR_UI::launch_website ()
3473 PBD::open_uri ("http://ardour.org");
3477 ARDOUR_UI::launch_website_dev ()
3479 PBD::open_uri ("http://ardour.org/development.html");
3483 ARDOUR_UI::launch_forums ()
3485 PBD::open_uri ("https://community.ardour.org/forums");
3489 ARDOUR_UI::launch_howto_report ()
3491 PBD::open_uri ("http://ardour.org/reporting_bugs");
3495 ARDOUR_UI::loading_message (const std::string& msg)
3497 if (ARDOUR_COMMAND_LINE::no_splash) {
3505 splash->message (msg);
3509 ARDOUR_UI::show_splash ()
3513 splash = new Splash;
3523 ARDOUR_UI::hide_splash ()
3530 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3534 removed = rep.paths.size();
3537 MessageDialog msgd (_main_window,
3538 _("No files were ready for clean-up"),
3542 msgd.set_title (_("Clean-up"));
3543 msgd.set_secondary_text (_("If this seems suprising, \n\
3544 check for any existing snapshots.\n\
3545 These may still include regions that\n\
3546 require some unused files to continue to exist."));
3552 ArdourDialog results (_("Clean-up"), true, false);
3554 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3555 CleanupResultsModelColumns() {
3559 Gtk::TreeModelColumn<std::string> visible_name;
3560 Gtk::TreeModelColumn<std::string> fullpath;
3564 CleanupResultsModelColumns results_columns;
3565 Glib::RefPtr<Gtk::ListStore> results_model;
3566 Gtk::TreeView results_display;
3568 results_model = ListStore::create (results_columns);
3569 results_display.set_model (results_model);
3570 results_display.append_column (list_title, results_columns.visible_name);
3572 results_display.set_name ("CleanupResultsList");
3573 results_display.set_headers_visible (true);
3574 results_display.set_headers_clickable (false);
3575 results_display.set_reorderable (false);
3577 Gtk::ScrolledWindow list_scroller;
3580 Gtk::HBox dhbox; // the hbox for the image and text
3581 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3582 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3584 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3586 const string dead_directory = _session->session_directory().dead_path();
3589 %1 - number of files removed
3590 %2 - location of "dead"
3591 %3 - size of files affected
3592 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3595 const char* bprefix;
3596 double space_adjusted = 0;
3598 if (rep.space < 1000) {
3600 space_adjusted = rep.space;
3601 } else if (rep.space < 1000000) {
3602 bprefix = _("kilo");
3603 space_adjusted = floorf((float)rep.space / 1000.0);
3604 } else if (rep.space < 1000000 * 1000) {
3605 bprefix = _("mega");
3606 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3608 bprefix = _("giga");
3609 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3613 txt.set_markup (string_compose (P_("\
3614 The following file was deleted from %2,\n\
3615 releasing %3 %4bytes of disk space", "\
3616 The following %1 files were deleted from %2,\n\
3617 releasing %3 %4bytes of disk space", removed),
3618 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3620 txt.set_markup (string_compose (P_("\
3621 The following file was not in use and \n\
3622 has been moved to: %2\n\n\
3623 After a restart of %5\n\n\
3624 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3625 will release an additional %3 %4bytes of disk space.\n", "\
3626 The following %1 files were not in use and \n\
3627 have been moved to: %2\n\n\
3628 After a restart of %5\n\n\
3629 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3630 will release an additional %3 %4bytes of disk space.\n", removed),
3631 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3634 dhbox.pack_start (*dimage, true, false, 5);
3635 dhbox.pack_start (txt, true, false, 5);
3637 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3638 TreeModel::Row row = *(results_model->append());
3639 row[results_columns.visible_name] = *i;
3640 row[results_columns.fullpath] = *i;
3643 list_scroller.add (results_display);
3644 list_scroller.set_size_request (-1, 150);
3645 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3647 dvbox.pack_start (dhbox, true, false, 5);
3648 dvbox.pack_start (list_scroller, true, false, 5);
3649 ddhbox.pack_start (dvbox, true, false, 5);
3651 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3652 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3653 results.set_default_response (RESPONSE_CLOSE);
3654 results.set_position (Gtk::WIN_POS_MOUSE);
3656 results_display.show();
3657 list_scroller.show();
3664 //results.get_vbox()->show();
3665 results.set_resizable (false);
3672 ARDOUR_UI::cleanup ()
3674 if (_session == 0) {
3675 /* shouldn't happen: menu item is insensitive */
3680 MessageDialog checker (_("Are you sure you want to clean-up?"),
3682 Gtk::MESSAGE_QUESTION,
3685 checker.set_title (_("Clean-up"));
3687 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3688 ALL undo/redo information will be lost if you clean-up.\n\
3689 Clean-up will move all unused files to a \"dead\" location."));
3691 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3692 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3693 checker.set_default_response (RESPONSE_CANCEL);
3695 checker.set_name (_("CleanupDialog"));
3696 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3697 checker.set_position (Gtk::WIN_POS_MOUSE);
3699 switch (checker.run()) {
3700 case RESPONSE_ACCEPT:
3706 ARDOUR::CleanupReport rep;
3708 editor->prepare_for_cleanup ();
3710 /* do not allow flush until a session is reloaded */
3712 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3714 act->set_sensitive (false);
3717 if (_session->cleanup_sources (rep)) {
3718 editor->finish_cleanup ();
3722 editor->finish_cleanup ();
3725 display_cleanup_results (rep, _("Cleaned Files"), false);
3729 ARDOUR_UI::flush_trash ()
3731 if (_session == 0) {
3732 /* shouldn't happen: menu item is insensitive */
3736 ARDOUR::CleanupReport rep;
3738 if (_session->cleanup_trash_sources (rep)) {
3742 display_cleanup_results (rep, _("deleted file"), true);
3746 ARDOUR_UI::cleanup_peakfiles ()
3748 if (_session == 0) {
3749 /* shouldn't happen: menu item is insensitive */
3753 if (! _session->can_cleanup_peakfiles ()) {
3757 // get all region-views in this session
3759 TrackViewList empty;
3761 editor->get_regions_after(rs, (framepos_t) 0, empty);
3762 std::list<RegionView*> views = rs.by_layer();
3764 // remove displayed audio-region-views waveforms
3765 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3766 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3767 if (!arv) { continue ; }
3768 arv->delete_waves();
3771 // cleanup peak files:
3772 // - stop pending peakfile threads
3773 // - close peakfiles if any
3774 // - remove peak dir in session
3775 // - setup peakfiles (background thread)
3776 _session->cleanup_peakfiles ();
3778 // re-add waves to ARV
3779 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3780 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3781 if (!arv) { continue ; }
3782 arv->create_waves();
3787 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3789 uint32_t order_hint = UINT32_MAX;
3791 if (editor->get_selection().tracks.empty()) {
3796 we want the new routes to have their order keys set starting from
3797 the highest order key in the selection + 1 (if available).
3800 if (place == AddRouteDialog::AfterSelection) {
3801 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3803 order_hint = rtav->route()->order_key();
3806 } else if (place == AddRouteDialog::BeforeSelection) {
3807 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3809 order_hint = rtav->route()->order_key();
3811 } else if (place == AddRouteDialog::First) {
3814 /* leave order_hint at UINT32_MAX */
3817 if (order_hint == UINT32_MAX) {
3818 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3819 * not setting an order hint will place new routes last.
3824 _session->set_order_hint (order_hint);
3826 /* create a gap in the existing route order keys to accomodate new routes.*/
3827 boost::shared_ptr <RouteList> rd = _session->get_routes();
3828 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3829 boost::shared_ptr<Route> rt (*ri);
3831 if (rt->is_monitor()) {
3835 if (rt->order_key () >= order_hint) {
3836 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3842 ARDOUR_UI::start_duplicate_routes ()
3844 if (!duplicate_routes_dialog) {
3845 duplicate_routes_dialog = new DuplicateRouteDialog;
3848 if (duplicate_routes_dialog->restart (_session)) {
3852 duplicate_routes_dialog->present ();
3856 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3864 if (add_route_dialog->is_visible()) {
3865 /* we're already doing this */
3869 ResponseType r = (ResponseType) add_route_dialog->run ();
3871 add_route_dialog->hide();
3874 case RESPONSE_ACCEPT:
3881 if ((count = add_route_dialog->count()) <= 0) {
3885 setup_order_hint(add_route_dialog->insert_at());
3887 string template_path = add_route_dialog->track_template();
3888 DisplaySuspender ds;
3890 if (!template_path.empty()) {
3891 if (add_route_dialog->name_template_is_default()) {
3892 _session->new_route_from_template (count, template_path, string());
3894 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3899 ChanCount input_chan= add_route_dialog->channels ();
3900 ChanCount output_chan;
3901 string name_template = add_route_dialog->name_template ();
3902 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3903 RouteGroup* route_group = add_route_dialog->route_group ();
3904 AutoConnectOption oac = Config->get_output_auto_connect();
3906 if (oac & AutoConnectMaster) {
3907 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3908 output_chan.set (DataType::MIDI, 0);
3910 output_chan = input_chan;
3913 /* XXX do something with name template */
3915 switch (add_route_dialog->type_wanted()) {
3916 case AddRouteDialog::AudioTrack:
3917 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3919 case AddRouteDialog::MidiTrack:
3920 session_add_midi_track (route_group, count, name_template, instrument);
3922 case AddRouteDialog::MixedTrack:
3923 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3925 case AddRouteDialog::AudioBus:
3926 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3932 ARDOUR_UI::stop_video_server (bool ask_confirm)
3934 if (!video_server_process && ask_confirm) {
3935 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3937 if (video_server_process) {
3939 ArdourDialog confirm (_("Stop Video-Server"), true);
3940 Label m (_("Do you really want to stop the Video Server?"));
3941 confirm.get_vbox()->pack_start (m, true, true);
3942 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3943 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3944 confirm.show_all ();
3945 if (confirm.run() == RESPONSE_CANCEL) {
3949 delete video_server_process;
3950 video_server_process =0;
3955 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3957 ARDOUR_UI::start_video_server( float_window, true);
3961 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3967 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3968 if (video_server_process) {
3969 popup_error(_("The Video Server is already started."));
3971 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3977 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3979 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3981 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3983 video_server_dialog->set_transient_for (*float_window);
3986 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3987 video_server_dialog->hide();
3989 ResponseType r = (ResponseType) video_server_dialog->run ();
3990 video_server_dialog->hide();
3991 if (r != RESPONSE_ACCEPT) { return false; }
3992 if (video_server_dialog->show_again()) {
3993 Config->set_show_video_server_dialog(false);
3997 std::string icsd_exec = video_server_dialog->get_exec_path();
3998 std::string icsd_docroot = video_server_dialog->get_docroot();
3999 if (icsd_docroot.empty()) {
4000 #ifndef PLATFORM_WINDOWS
4001 icsd_docroot = X_("/");
4003 icsd_docroot = X_("C:\\");
4008 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4009 warning << _("Specified docroot is not an existing directory.") << endmsg;
4012 #ifndef PLATFORM_WINDOWS
4013 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4014 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4015 warning << _("Given Video Server is not an executable file.") << endmsg;
4019 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4020 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4021 warning << _("Given Video Server is not an executable file.") << endmsg;
4027 argp=(char**) calloc(9,sizeof(char*));
4028 argp[0] = strdup(icsd_exec.c_str());
4029 argp[1] = strdup("-P");
4030 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4031 argp[3] = strdup("-p");
4032 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4033 argp[5] = strdup("-C");
4034 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4035 argp[7] = strdup(icsd_docroot.c_str());
4037 stop_video_server();
4039 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4040 Config->set_video_advanced_setup(false);
4042 std::ostringstream osstream;
4043 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4044 Config->set_video_server_url(osstream.str());
4045 Config->set_video_server_docroot(icsd_docroot);
4046 Config->set_video_advanced_setup(true);
4049 if (video_server_process) {
4050 delete video_server_process;
4053 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4054 if (video_server_process->start()) {
4055 warning << _("Cannot launch the video-server") << endmsg;
4058 int timeout = 120; // 6 sec
4059 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4060 Glib::usleep (50000);
4062 if (--timeout <= 0 || !video_server_process->is_running()) break;
4065 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4067 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4068 delete video_server_process;
4069 video_server_process = 0;
4077 ARDOUR_UI::add_video (Gtk::Window* float_window)
4083 if (!start_video_server(float_window, false)) {
4084 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4089 add_video_dialog->set_transient_for (*float_window);
4092 if (add_video_dialog->is_visible()) {
4093 /* we're already doing this */
4097 ResponseType r = (ResponseType) add_video_dialog->run ();
4098 add_video_dialog->hide();
4099 if (r != RESPONSE_ACCEPT) { return; }
4101 bool local_file, orig_local_file;
4102 std::string path = add_video_dialog->file_name(local_file);
4104 std::string orig_path = path;
4105 orig_local_file = local_file;
4107 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4109 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4110 warning << string_compose(_("could not open %1"), path) << endmsg;
4113 if (!local_file && path.length() == 0) {
4114 warning << _("no video-file selected") << endmsg;
4118 std::string audio_from_video;
4119 bool detect_ltc = false;
4121 switch (add_video_dialog->import_option()) {
4122 case VTL_IMPORT_TRANSCODE:
4124 TranscodeVideoDialog *transcode_video_dialog;
4125 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4126 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4127 transcode_video_dialog->hide();
4128 if (r != RESPONSE_ACCEPT) {
4129 delete transcode_video_dialog;
4133 audio_from_video = transcode_video_dialog->get_audiofile();
4135 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4138 else if (!audio_from_video.empty()) {
4139 editor->embed_audio_from_video(
4141 video_timeline->get_offset(),
4142 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4145 switch (transcode_video_dialog->import_option()) {
4146 case VTL_IMPORT_TRANSCODED:
4147 path = transcode_video_dialog->get_filename();
4150 case VTL_IMPORT_REFERENCE:
4153 delete transcode_video_dialog;
4156 delete transcode_video_dialog;
4160 case VTL_IMPORT_NONE:
4164 /* strip _session->session_directory().video_path() from video file if possible */
4165 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4166 path=path.substr(_session->session_directory().video_path().size());
4167 if (path.at(0) == G_DIR_SEPARATOR) {
4168 path=path.substr(1);
4172 video_timeline->set_update_session_fps(auto_set_session_fps);
4174 if (video_timeline->video_file_info(path, local_file)) {
4175 XMLNode* node = new XMLNode(X_("Videotimeline"));
4176 node->add_property (X_("Filename"), path);
4177 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4178 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4179 if (orig_local_file) {
4180 node->add_property (X_("OriginalVideoFile"), orig_path);
4182 node->remove_property (X_("OriginalVideoFile"));
4184 _session->add_extra_xml (*node);
4185 _session->set_dirty ();
4187 if (!audio_from_video.empty() && detect_ltc) {
4188 std::vector<LTCFileReader::LTCMap> ltc_seq;
4191 /* TODO ask user about TV standard (LTC alignment if any) */
4192 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4193 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4195 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4197 /* TODO seek near end of file, and read LTC until end.
4198 * if it fails to find any LTC frames, scan complete file
4200 * calculate drift of LTC compared to video-duration,
4201 * ask user for reference (timecode from start/mid/end)
4204 // LTCFileReader will have written error messages
4207 ::g_unlink(audio_from_video.c_str());
4209 if (ltc_seq.size() == 0) {
4210 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4212 /* the very first TC in the file is somteimes not aligned properly */
4213 int i = ltc_seq.size() -1;
4214 ARDOUR::frameoffset_t video_start_offset =
4215 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4216 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4217 video_timeline->set_offset(video_start_offset);
4221 _session->maybe_update_session_range(
4222 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4223 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4226 if (add_video_dialog->launch_xjadeo() && local_file) {
4227 editor->set_xjadeo_sensitive(true);
4228 editor->toggle_xjadeo_proc(1);
4230 editor->toggle_xjadeo_proc(0);
4232 editor->toggle_ruler_video(true);
4237 ARDOUR_UI::remove_video ()
4239 video_timeline->close_session();
4240 editor->toggle_ruler_video(false);
4243 video_timeline->set_offset_locked(false);
4244 video_timeline->set_offset(0);
4246 /* delete session state */
4247 XMLNode* node = new XMLNode(X_("Videotimeline"));
4248 _session->add_extra_xml(*node);
4249 node = new XMLNode(X_("Videomonitor"));
4250 _session->add_extra_xml(*node);
4251 node = new XMLNode(X_("Videoexport"));
4252 _session->add_extra_xml(*node);
4253 stop_video_server();
4257 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4259 if (localcacheonly) {
4260 video_timeline->vmon_update();
4262 video_timeline->flush_cache();
4264 editor->queue_visual_videotimeline_update();
4268 ARDOUR_UI::export_video (bool range)
4270 if (ARDOUR::Config->get_show_video_export_info()) {
4271 ExportVideoInfobox infobox (_session);
4272 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4273 if (infobox.show_again()) {
4274 ARDOUR::Config->set_show_video_export_info(false);
4277 case GTK_RESPONSE_YES:
4278 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4284 export_video_dialog->set_session (_session);
4285 export_video_dialog->apply_state(editor->get_selection().time, range);
4286 export_video_dialog->run ();
4287 export_video_dialog->hide ();
4291 ARDOUR_UI::mixer_settings () const
4296 node = _session->instant_xml(X_("Mixer"));
4298 node = Config->instant_xml(X_("Mixer"));
4302 node = new XMLNode (X_("Mixer"));
4309 ARDOUR_UI::main_window_settings () const
4314 node = _session->instant_xml(X_("Main"));
4316 node = Config->instant_xml(X_("Main"));
4320 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4321 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4326 node = new XMLNode (X_("Main"));
4333 ARDOUR_UI::editor_settings () const
4338 node = _session->instant_xml(X_("Editor"));
4340 node = Config->instant_xml(X_("Editor"));
4344 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4345 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4350 node = new XMLNode (X_("Editor"));
4357 ARDOUR_UI::keyboard_settings () const
4361 node = Config->extra_xml(X_("Keyboard"));
4364 node = new XMLNode (X_("Keyboard"));
4371 ARDOUR_UI::create_xrun_marker (framepos_t where)
4374 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4375 _session->locations()->add (location);
4380 ARDOUR_UI::halt_on_xrun_message ()
4382 cerr << "HALT on xrun\n";
4383 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4388 ARDOUR_UI::xrun_handler (framepos_t where)
4394 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4396 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4397 create_xrun_marker(where);
4400 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4401 halt_on_xrun_message ();
4406 ARDOUR_UI::disk_overrun_handler ()
4408 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4410 if (!have_disk_speed_dialog_displayed) {
4411 have_disk_speed_dialog_displayed = true;
4412 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4413 The disk system on your computer\n\
4414 was not able to keep up with %1.\n\
4416 Specifically, it failed to write data to disk\n\
4417 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4418 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4424 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4425 static MessageDialog *scan_dlg = NULL;
4426 static ProgressBar *scan_pbar = NULL;
4427 static HBox *scan_tbox = NULL;
4428 static Gtk::Button *scan_timeout_button;
4431 ARDOUR_UI::cancel_plugin_scan ()
4433 PluginManager::instance().cancel_plugin_scan();
4437 ARDOUR_UI::cancel_plugin_timeout ()
4439 PluginManager::instance().cancel_plugin_timeout();
4440 scan_timeout_button->set_sensitive (false);
4444 ARDOUR_UI::plugin_scan_timeout (int timeout)
4446 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4450 scan_pbar->set_sensitive (false);
4451 scan_timeout_button->set_sensitive (true);
4452 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4455 scan_pbar->set_sensitive (false);
4456 scan_timeout_button->set_sensitive (false);
4462 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4464 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4468 const bool cancelled = PluginManager::instance().cancelled();
4469 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4470 if (cancelled && scan_dlg->is_mapped()) {
4475 if (cancelled || !can_cancel) {
4480 static Gtk::Button *cancel_button;
4482 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4483 VBox* vbox = scan_dlg->get_vbox();
4484 vbox->set_size_request(400,-1);
4485 scan_dlg->set_title (_("Scanning for plugins"));
4487 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4488 cancel_button->set_name ("EditorGTKButton");
4489 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4490 cancel_button->show();
4492 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4494 scan_tbox = manage( new HBox() );
4496 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4497 scan_timeout_button->set_name ("EditorGTKButton");
4498 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4499 scan_timeout_button->show();
4501 scan_pbar = manage(new ProgressBar());
4502 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4503 scan_pbar->set_text(_("Scan Timeout"));
4506 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4507 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4509 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4512 assert(scan_dlg && scan_tbox && cancel_button);
4514 if (type == X_("closeme")) {
4518 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4521 if (!can_cancel || !cancelled) {
4522 scan_timeout_button->set_sensitive(false);
4524 cancel_button->set_sensitive(can_cancel && !cancelled);
4530 ARDOUR_UI::gui_idle_handler ()
4533 /* due to idle calls, gtk_events_pending() may always return true */
4534 while (gtk_events_pending() && --timeout) {
4535 gtk_main_iteration ();
4540 ARDOUR_UI::disk_underrun_handler ()
4542 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4544 if (!have_disk_speed_dialog_displayed) {
4545 have_disk_speed_dialog_displayed = true;
4546 MessageDialog* msg = new MessageDialog (
4547 _main_window, string_compose (_("The disk system on your computer\n\
4548 was not able to keep up with %1.\n\
4550 Specifically, it failed to read data from disk\n\
4551 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4552 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4558 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4560 have_disk_speed_dialog_displayed = false;
4565 ARDOUR_UI::session_dialog (std::string msg)
4567 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4571 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4578 ARDOUR_UI::pending_state_dialog ()
4580 HBox* hbox = manage (new HBox());
4581 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4582 ArdourDialog dialog (_("Crash Recovery"), true);
4583 Label message (string_compose (_("\
4584 This session appears to have been in the\n\
4585 middle of recording when %1 or\n\
4586 the computer was shutdown.\n\
4588 %1 can recover any captured audio for\n\
4589 you, or it can ignore it. Please decide\n\
4590 what you would like to do.\n"), PROGRAM_NAME));
4591 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4592 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4593 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4594 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4595 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4596 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4597 dialog.set_default_response (RESPONSE_ACCEPT);
4598 dialog.set_position (WIN_POS_CENTER);
4603 switch (dialog.run ()) {
4604 case RESPONSE_ACCEPT:
4612 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4614 HBox* hbox = new HBox();
4615 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4616 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4617 Label message (string_compose (_("\
4618 This session was created with a sample rate of %1 Hz, but\n\
4619 %2 is currently running at %3 Hz. If you load this session,\n\
4620 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4622 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4623 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4624 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4625 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4626 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4627 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4628 dialog.set_default_response (RESPONSE_ACCEPT);
4629 dialog.set_position (WIN_POS_CENTER);
4634 switch (dialog.run()) {
4635 case RESPONSE_ACCEPT:
4645 ARDOUR_UI::use_config ()
4647 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4649 set_transport_controllable_state (*node);
4654 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4656 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4657 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4659 primary_clock->set (pos);
4662 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4663 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4665 secondary_clock->set (pos);
4668 if (big_clock_window) {
4669 big_clock->set (pos);
4671 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4675 ARDOUR_UI::step_edit_status_change (bool yn)
4677 // XXX should really store pre-step edit status of things
4678 // we make insensitive
4681 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4682 rec_button.set_sensitive (false);
4684 rec_button.unset_active_state ();;
4685 rec_button.set_sensitive (true);
4690 ARDOUR_UI::record_state_changed ()
4692 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4694 if (!_session || !big_clock_window) {
4695 /* why bother - the clock isn't visible */
4699 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4700 big_clock->set_active (true);
4702 big_clock->set_active (false);
4707 ARDOUR_UI::first_idle ()
4710 _session->allow_auto_play (true);
4714 editor->first_idle();
4717 Keyboard::set_can_save_keybindings (true);
4722 ARDOUR_UI::store_clock_modes ()
4724 XMLNode* node = new XMLNode(X_("ClockModes"));
4726 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4727 XMLNode* child = new XMLNode (X_("Clock"));
4729 child->add_property (X_("name"), (*x)->name());
4730 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4731 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4733 node->add_child_nocopy (*child);
4736 _session->add_extra_xml (*node);
4737 _session->set_dirty ();
4740 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4741 : Controllable (name), ui (u), type(tp)
4747 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4750 /* do nothing: these are radio-style actions */
4754 const char *action = 0;
4758 action = X_("Roll");
4761 action = X_("Stop");
4764 action = X_("GotoStart");
4767 action = X_("GotoEnd");
4770 action = X_("Loop");
4773 action = X_("PlaySelection");
4776 action = X_("Record");
4786 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4794 ARDOUR_UI::TransportControllable::get_value (void) const
4821 ARDOUR_UI::setup_profile ()
4823 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4824 Profile->set_small_screen ();
4827 if (g_getenv ("ARDOUR_SAE")) {
4828 Profile->set_sae ();
4829 Profile->set_single_package ();
4832 if (g_getenv ("TRX")) {
4833 Profile->set_trx ();
4836 if (g_getenv ("MIXBUS")) {
4837 Profile->set_mixbus ();
4842 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4844 MissingFileDialog dialog (s, str, type);
4849 int result = dialog.run ();
4856 return 1; // quit entire session load
4859 result = dialog.get_action ();
4865 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4867 AmbiguousFileDialog dialog (file, hits);
4874 return dialog.get_which ();
4877 /** Allocate our thread-local buffers */
4879 ARDOUR_UI::get_process_buffers ()
4881 _process_thread->get_buffers ();
4884 /** Drop our thread-local buffers */
4886 ARDOUR_UI::drop_process_buffers ()
4888 _process_thread->drop_buffers ();
4892 ARDOUR_UI::feedback_detected ()
4894 _feedback_exists = true;
4898 ARDOUR_UI::successful_graph_sort ()
4900 _feedback_exists = false;
4904 ARDOUR_UI::midi_panic ()
4907 _session->midi_panic();
4912 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4914 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4915 const char* end_big = "</span>";
4916 const char* start_mono = "<tt>";
4917 const char* end_mono = "</tt>";
4919 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4920 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4921 "From now on, use the -2000 version with older versions of %3"),
4922 xml_path, backup_path, PROGRAM_NAME,
4924 start_mono, end_mono), true);
4931 ARDOUR_UI::reset_peak_display ()
4933 if (!_session || !_session->master_out() || !editor_meter) return;
4934 editor_meter->clear_meters();
4935 editor_meter_max_peak = -INFINITY;
4936 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4940 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4942 if (!_session || !_session->master_out()) return;
4943 if (group == _session->master_out()->route_group()) {
4944 reset_peak_display ();
4949 ARDOUR_UI::reset_route_peak_display (Route* route)
4951 if (!_session || !_session->master_out()) return;
4952 if (_session->master_out().get() == route) {
4953 reset_peak_display ();
4958 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4960 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4961 audio_midi_setup->set_position (WIN_POS_CENTER);
4966 response = audio_midi_setup->run();
4968 case Gtk::RESPONSE_OK:
4969 if (!AudioEngine::instance()->running()) {
4983 ARDOUR_UI::transport_numpad_timeout ()
4985 _numpad_locate_happening = false;
4986 if (_numpad_timeout_connection.connected() )
4987 _numpad_timeout_connection.disconnect();
4992 ARDOUR_UI::transport_numpad_decimal ()
4994 _numpad_timeout_connection.disconnect();
4996 if (_numpad_locate_happening) {
4997 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4998 _numpad_locate_happening = false;
5000 _pending_locate_num = 0;
5001 _numpad_locate_happening = true;
5002 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5007 ARDOUR_UI::transport_numpad_event (int num)
5009 if ( _numpad_locate_happening ) {
5010 _pending_locate_num = _pending_locate_num*10 + num;
5013 case 0: toggle_roll(false, false); break;
5014 case 1: transport_rewind(1); break;
5015 case 2: transport_forward(1); break;
5016 case 3: transport_record(true); break;
5017 case 4: toggle_session_auto_loop(); break;
5018 case 5: transport_record(false); toggle_session_auto_loop(); break;
5019 case 6: toggle_punch(); break;
5020 case 7: toggle_click(); break;
5021 case 8: toggle_auto_return(); break;
5022 case 9: toggle_follow_edits(); break;
5028 ARDOUR_UI::set_flat_buttons ()
5030 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5034 ARDOUR_UI::audioengine_became_silent ()
5036 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5038 Gtk::MESSAGE_WARNING,
5042 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5044 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5045 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5046 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5047 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5048 Gtk::HBox pay_button_box;
5049 Gtk::HBox subscribe_button_box;
5051 pay_button_box.pack_start (pay_button, true, false);
5052 subscribe_button_box.pack_start (subscribe_button, true, false);
5054 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 */
5056 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5057 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5059 msg.get_vbox()->pack_start (pay_label);
5060 msg.get_vbox()->pack_start (pay_button_box);
5061 msg.get_vbox()->pack_start (subscribe_label);
5062 msg.get_vbox()->pack_start (subscribe_button_box);
5064 msg.get_vbox()->show_all ();
5066 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5067 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5068 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5073 case Gtk::RESPONSE_YES:
5074 AudioEngine::instance()->reset_silence_countdown ();
5077 case Gtk::RESPONSE_NO:
5079 save_state_canfail ("");
5083 case Gtk::RESPONSE_CANCEL:
5085 /* don't reset, save session and exit */
5091 ARDOUR_UI::hide_application ()
5093 Application::instance ()-> hide ();
5097 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5099 /* icons, titles, WM stuff */
5101 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5103 if (window_icons.empty()) {
5104 Glib::RefPtr<Gdk::Pixbuf> icon;
5105 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5106 window_icons.push_back (icon);
5108 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5109 window_icons.push_back (icon);
5111 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5112 window_icons.push_back (icon);
5114 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5115 window_icons.push_back (icon);
5119 if (!window_icons.empty()) {
5120 window.set_default_icon_list (window_icons);
5123 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5125 if (!name.empty()) {
5129 window.set_title (title.get_string());
5130 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5132 window.set_flags (CAN_FOCUS);
5133 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5135 /* This is a hack to ensure that GTK-accelerators continue to
5136 * work. Once we switch over to entirely native bindings, this will be
5137 * unnecessary and should be removed
5139 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5141 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5142 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5143 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5144 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5148 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5150 Gtkmm2ext::Bindings* bindings = 0;
5151 Gtk::Window* window = 0;
5153 /* until we get ardour bindings working, we are not handling key
5157 if (ev->type != GDK_KEY_PRESS) {
5161 if (event_window == &_main_window) {
5163 window = event_window;
5165 /* find current tab contents */
5167 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5169 /* see if it uses the ardour binding system */
5172 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5174 bindings = &global_bindings;
5177 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5179 } else if (event_window != 0) {
5181 window = event_window;
5183 /* see if window uses ardour binding system */
5185 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5189 /* An empty binding set is treated as if it doesn't exist */
5191 if (bindings && bindings->empty()) {
5195 return key_press_focus_accelerator_handler (*window, ev, bindings);
5199 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5201 GtkWindow* win = window.gobj();
5202 GtkWidget* focus = gtk_window_get_focus (win);
5203 bool special_handling_of_unmodified_accelerators = false;
5204 /* consider all relevant modifiers but not LOCK or SHIFT */
5205 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5207 GdkModifierType modifier = GdkModifierType (ev->state);
5208 modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
5209 Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
5213 /* some widget has keyboard focus */
5215 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5217 /* A particular kind of focusable widget currently has keyboard
5218 * focus. All unmodified key events should go to that widget
5219 * first and not be used as an accelerator by default
5222 special_handling_of_unmodified_accelerators = true;
5226 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",
5229 show_gdk_event_state (ev->state),
5230 special_handling_of_unmodified_accelerators,
5231 Keyboard::some_magic_widget_has_focus(),
5233 (focus ? gtk_widget_get_name (focus) : "no focus widget")));
5235 /* This exists to allow us to override the way GTK handles
5236 key events. The normal sequence is:
5238 a) event is delivered to a GtkWindow
5239 b) accelerators/mnemonics are activated
5240 c) if (b) didn't handle the event, propagate to
5241 the focus widget and/or focus chain
5243 The problem with this is that if the accelerators include
5244 keys without modifiers, such as the space bar or the
5245 letter "e", then pressing the key while typing into
5246 a text entry widget results in the accelerator being
5247 activated, instead of the desired letter appearing
5250 There is no good way of fixing this, but this
5251 represents a compromise. The idea is that
5252 key events involving modifiers (not Shift)
5253 get routed into the activation pathway first, then
5254 get propagated to the focus widget if necessary.
5256 If the key event doesn't involve modifiers,
5257 we deliver to the focus widget first, thus allowing
5258 it to get "normal text" without interference
5261 Of course, this can also be problematic: if there
5262 is a widget with focus, then it will swallow
5263 all "normal text" accelerators.
5267 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5269 /* no special handling or there are modifiers in effect: accelerate first */
5271 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5272 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5273 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5275 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5276 KeyboardKey k (ev->state, ev->keyval);
5280 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5282 if (bindings->activate (k, Bindings::Press)) {
5283 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5288 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5290 if (global_bindings.activate (k, Bindings::Press)) {
5291 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5295 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5297 if (gtk_window_propagate_key_event (win, ev)) {
5298 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5304 /* no modifiers, propagate first */
5306 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5308 if (gtk_window_propagate_key_event (win, ev)) {
5309 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5313 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5314 KeyboardKey k (ev->state, ev->keyval);
5318 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5321 if (bindings->activate (k, Bindings::Press)) {
5322 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5328 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5330 if (global_bindings.activate (k, Bindings::Press)) {
5331 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5336 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5341 ARDOUR_UI::load_bindings ()
5343 global_bindings.set_action_map (global_actions);
5344 global_bindings.load (X_("global"));