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/failed_constructor.h"
52 #include "pbd/enumwriter.h"
53 #include "pbd/memento_command.h"
54 #include "pbd/openuri.h"
55 #include "pbd/stl_delete.h"
56 #include "pbd/file_utils.h"
57 #include "pbd/localtime_r.h"
58 #include "pbd/pthread_utils.h"
59 #include "pbd/replace_all.h"
60 #include "pbd/xml++.h"
62 #include "gtkmm2ext/application.h"
63 #include "gtkmm2ext/bindings.h"
64 #include "gtkmm2ext/gtk_ui.h"
65 #include "gtkmm2ext/utils.h"
66 #include "gtkmm2ext/click_box.h"
67 #include "gtkmm2ext/fastmeter.h"
68 #include "gtkmm2ext/popup.h"
69 #include "gtkmm2ext/window_title.h"
71 #include "ardour/ardour.h"
72 #include "ardour/audio_backend.h"
73 #include "ardour/audioengine.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/automation_watch.h"
76 #include "ardour/diskstream.h"
77 #include "ardour/filename_extensions.h"
78 #include "ardour/filesystem_paths.h"
79 #include "ardour/ltc_file_reader.h"
80 #include "ardour/port.h"
81 #include "ardour/plugin_manager.h"
82 #include "ardour/process_thread.h"
83 #include "ardour/profile.h"
84 #include "ardour/recent_sessions.h"
85 #include "ardour/session_directory.h"
86 #include "ardour/session_route.h"
87 #include "ardour/session_state_utils.h"
88 #include "ardour/session_utils.h"
89 #include "ardour/source_factory.h"
90 #include "ardour/slave.h"
91 #include "ardour/system_exec.h"
93 #ifdef WINDOWS_VST_SUPPORT
96 #ifdef AUDIOUNIT_SUPPORT
97 #include "ardour/audio_unit.h"
100 #include "timecode/time.h"
102 typedef uint64_t microseconds_t;
107 #include "add_route_dialog.h"
108 #include "ambiguous_file_dialog.h"
109 #include "ardour_ui.h"
110 #include "audio_clock.h"
111 #include "audio_region_view.h"
112 #include "big_clock_window.h"
113 #include "bundle_manager.h"
114 #include "duplicate_routes_dialog.h"
115 #include "engine_dialog.h"
116 #include "export_video_dialog.h"
117 #include "export_video_infobox.h"
118 #include "gain_meter.h"
119 #include "global_port_matrix.h"
120 #include "gui_object.h"
121 #include "gui_thread.h"
122 #include "keyboard.h"
123 #include "keyeditor.h"
124 #include "location_ui.h"
125 #include "main_clock.h"
126 #include "missing_file_dialog.h"
127 #include "missing_plugin_dialog.h"
128 #include "mixer_ui.h"
129 #include "meterbridge.h"
130 #include "mouse_cursors.h"
133 #include "pingback.h"
134 #include "processor_box.h"
135 #include "prompter.h"
136 #include "public_editor.h"
137 #include "rc_option_editor.h"
138 #include "route_time_axis.h"
139 #include "route_params_ui.h"
140 #include "save_as_dialog.h"
141 #include "session_dialog.h"
142 #include "session_metadata_dialog.h"
143 #include "session_option_editor.h"
144 #include "shuttle_control.h"
145 #include "speaker_dialog.h"
148 #include "theme_manager.h"
149 #include "time_axis_view_item.h"
152 #include "video_server_dialog.h"
153 #include "add_video_dialog.h"
154 #include "transcode_video_dialog.h"
158 using namespace ARDOUR;
159 using namespace ARDOUR_UI_UTILS;
161 using namespace Gtkmm2ext;
164 using namespace Editing;
166 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
168 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
169 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
172 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
174 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
175 "Would you like these files to be copied and used for %1 %2.x?\n\n"
176 "(This will require you to restart %1.)"),
177 PROGRAM_NAME, PROGRAM_VERSION, version),
178 false, /* no markup */
181 true /* modal, though it hardly matters since it is the only window */
184 msg.set_default_response (Gtk::RESPONSE_YES);
187 return (msg.run() == Gtk::RESPONSE_YES);
191 libxml_generic_error_func (void* /* parsing_context*/,
199 vsnprintf (buf, sizeof (buf), msg, ap);
200 error << buf << endmsg;
205 libxml_structured_error_func (void* /* parsing_context*/,
213 replace_all (msg, "\n", "");
215 if (err->file && err->line) {
216 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
219 error << ':' << err->int2;
226 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
228 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
229 , session_loaded (false)
230 , gui_object_state (new GUIObjectState)
231 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
232 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
233 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
235 , ignore_dual_punch (false)
240 , _mixer_on_top (false)
241 , _initial_verbose_plugin_scan (false)
242 , first_time_engine_run (true)
243 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
244 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
245 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
246 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
247 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
248 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
249 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
250 , auto_return_button (ArdourButton::led_default_elements)
251 , follow_edits_button (ArdourButton::led_default_elements)
252 , auto_input_button (ArdourButton::led_default_elements)
253 , auditioning_alert_button (_("Audition"))
254 , solo_alert_button (_("Solo"))
255 , feedback_alert_button (_("Feedback"))
256 , error_alert_button ( ArdourButton::just_led_default_elements )
258 , editor_meter_peak_display()
259 , _numpad_locate_happening (false)
260 , _session_is_new (false)
261 , last_key_press_time (0)
264 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
265 , key_editor (X_("key-editor"), _("Key Bindings"))
266 , rc_option_editor (X_("rc-options-editor"), _("Preferences"))
267 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
268 , about (X_("about"), _("About"))
269 , location_ui (X_("locations"), _("Locations"))
270 , route_params (X_("inspector"), _("Tracks and Busses"))
271 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
272 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
273 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
274 , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
275 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
276 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
277 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
278 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
279 , video_server_process (0)
281 , have_configure_timeout (false)
282 , last_configure_time (0)
284 , have_disk_speed_dialog_displayed (false)
285 , _status_bar_visibility (X_("status-bar"))
286 , _feedback_exists (false)
287 , _log_not_acknowledged (LogLevelNone)
288 , duplicate_routes_dialog (0)
290 Gtkmm2ext::init (localedir);
292 UIConfiguration::instance().post_gui_init ();
294 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
295 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
297 /* configuration was modified, exit immediately */
301 if (theArdourUI == 0) {
305 /* stop libxml from spewing to stdout/stderr */
307 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
308 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
310 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
311 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
312 UIConfiguration::instance().map_parameters (pc);
314 roll_button.set_controllable (roll_controllable);
315 stop_button.set_controllable (stop_controllable);
316 goto_start_button.set_controllable (goto_start_controllable);
317 goto_end_button.set_controllable (goto_end_controllable);
318 auto_loop_button.set_controllable (auto_loop_controllable);
319 play_selection_button.set_controllable (play_selection_controllable);
320 rec_button.set_controllable (rec_controllable);
322 roll_button.set_name ("transport button");
323 stop_button.set_name ("transport button");
324 goto_start_button.set_name ("transport button");
325 goto_end_button.set_name ("transport button");
326 auto_loop_button.set_name ("transport button");
327 play_selection_button.set_name ("transport button");
328 rec_button.set_name ("transport recenable button");
329 midi_panic_button.set_name ("transport button");
331 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
332 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
334 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
336 /* handle dialog requests */
338 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
340 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
342 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
344 /* handle Audio/MIDI setup when session requires it */
346 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
348 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
350 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
352 /* handle requests to quit (coming from JACK session) */
354 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
356 /* tell the user about feedback */
358 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
359 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
361 /* handle requests to deal with missing files */
363 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
365 /* and ambiguous files */
367 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
369 /* also plugin scan messages */
370 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
371 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
373 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
375 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
378 /* lets get this party started */
380 setup_gtk_ardour_enums ();
383 SessionEvent::create_per_thread_pool ("GUI", 4096);
385 /* we like keyboards */
387 keyboard = new ArdourKeyboard(*this);
389 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
391 keyboard->set_state (*node, Stateful::loading_state_version);
394 keyboard->GrabFocus.connect (sigc::mem_fun (*this, &ARDOUR_UI::grab_focus_after_dialog));
396 /* we don't like certain modifiers */
397 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
399 UIConfiguration::instance().reset_dpi ();
401 TimeAxisViewItem::set_constant_heights ();
403 /* Set this up so that our window proxies can register actions */
405 ActionManager::init ();
407 /* The following must happen after ARDOUR::init() so that Config is set up */
409 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
412 key_editor.set_state (*ui_xml);
413 rc_option_editor.set_state (*ui_xml);
414 session_option_editor.set_state (*ui_xml);
415 speaker_config_window.set_state (*ui_xml);
416 about.set_state (*ui_xml);
417 add_route_dialog.set_state (*ui_xml);
418 add_video_dialog.set_state (*ui_xml);
419 route_params.set_state (*ui_xml);
420 bundle_manager.set_state (*ui_xml);
421 location_ui.set_state (*ui_xml);
422 big_clock_window.set_state (*ui_xml);
423 audio_port_matrix.set_state (*ui_xml);
424 midi_port_matrix.set_state (*ui_xml);
425 export_video_dialog.set_state (*ui_xml);
428 WM::Manager::instance().register_window (&key_editor);
429 WM::Manager::instance().register_window (&rc_option_editor);
430 WM::Manager::instance().register_window (&session_option_editor);
431 WM::Manager::instance().register_window (&speaker_config_window);
432 WM::Manager::instance().register_window (&about);
433 WM::Manager::instance().register_window (&add_route_dialog);
434 WM::Manager::instance().register_window (&add_video_dialog);
435 WM::Manager::instance().register_window (&route_params);
436 WM::Manager::instance().register_window (&audio_midi_setup);
437 WM::Manager::instance().register_window (&export_video_dialog);
438 WM::Manager::instance().register_window (&bundle_manager);
439 WM::Manager::instance().register_window (&location_ui);
440 WM::Manager::instance().register_window (&big_clock_window);
441 WM::Manager::instance().register_window (&audio_port_matrix);
442 WM::Manager::instance().register_window (&midi_port_matrix);
444 /* Trigger setting up the color scheme and loading the GTK RC file */
446 UIConfiguration::instance().load_rc_file (false);
448 _process_thread = new ProcessThread ();
449 _process_thread->init ();
451 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
456 GlobalPortMatrixWindow*
457 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
462 return new GlobalPortMatrixWindow (_session, type);
466 ARDOUR_UI::attach_to_engine ()
468 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
469 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
473 ARDOUR_UI::engine_stopped ()
475 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
476 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
477 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
478 update_sample_rate (0);
483 ARDOUR_UI::engine_running ()
485 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
486 if (first_time_engine_run) {
488 first_time_engine_run = false;
492 _session->reset_xrun_count ();
494 update_disk_space ();
496 update_xrun_count ();
497 update_sample_rate (AudioEngine::instance()->sample_rate());
498 update_timecode_format ();
499 update_peak_thread_work ();
500 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
501 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
505 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
507 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
508 /* we can't rely on the original string continuing to exist when we are called
509 again in the GUI thread, so make a copy and note that we need to
512 char *copy = strdup (reason);
513 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
517 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
518 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
520 update_sample_rate (0);
524 /* if the reason is a non-empty string, it means that the backend was shutdown
525 rather than just Ardour.
528 if (strlen (reason)) {
529 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
531 msgstr = string_compose (_("\
532 The audio backend has either been shutdown or it\n\
533 disconnected %1 because %1\n\
534 was not fast enough. Try to restart\n\
535 the audio backend and save the session."), PROGRAM_NAME);
538 MessageDialog msg (*editor, msgstr);
539 pop_back_splash (msg);
543 free (const_cast<char*> (reason));
548 ARDOUR_UI::post_engine ()
550 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
552 #ifdef AUDIOUNIT_SUPPORT
554 if (AUPluginInfo::au_get_crashlog(au_msg)) {
555 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
556 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
557 info << au_msg << endmsg;
561 ARDOUR::init_post_engine ();
563 /* connect to important signals */
565 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
566 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
567 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
568 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
569 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
571 if (setup_windows ()) {
572 throw failed_constructor ();
575 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
576 XMLNode* n = Config->extra_xml (X_("UI"));
578 _status_bar_visibility.set_state (*n);
581 check_memory_locking();
583 /* this is the first point at which all the keybindings are available */
585 if (ARDOUR_COMMAND_LINE::show_key_actions) {
586 vector<string> names;
587 vector<string> paths;
588 vector<string> tooltips;
590 vector<AccelKey> bindings;
592 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
594 vector<string>::iterator n;
595 vector<string>::iterator k;
596 vector<string>::iterator p;
597 for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
598 cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
601 halt_connection.disconnect ();
602 AudioEngine::instance()->stop ();
606 /* this being a GUI and all, we want peakfiles */
608 AudioFileSource::set_build_peakfiles (true);
609 AudioFileSource::set_build_missing_peakfiles (true);
611 /* set default clock modes */
613 if (Profile->get_sae()) {
614 primary_clock->set_mode (AudioClock::BBT);
615 secondary_clock->set_mode (AudioClock::MinSec);
617 primary_clock->set_mode (AudioClock::Timecode);
618 secondary_clock->set_mode (AudioClock::BBT);
621 /* start the time-of-day-clock */
624 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
625 update_wall_clock ();
626 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
631 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
632 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
633 Config->map_parameters (pc);
635 UIConfiguration::instance().map_parameters (pc);
639 ARDOUR_UI::~ARDOUR_UI ()
641 UIConfiguration::instance().save_state();
645 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
646 // don't bother at 'real' exit. the OS cleans up for us.
648 delete primary_clock;
649 delete secondary_clock;
650 delete _process_thread;
655 delete gui_object_state;
656 FastMeter::flush_pattern_cache ();
657 PixFader::flush_pattern_cache ();
661 /* Small trick to flush main-thread event pool.
662 * Other thread-pools are destroyed at pthread_exit(),
663 * but tmain thread termination is too late to trigger Pool::~Pool()
665 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.
666 delete ev->event_pool();
671 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
673 if (Splash::instance()) {
674 Splash::instance()->pop_back_for (win);
679 ARDOUR_UI::configure_timeout ()
681 if (last_configure_time == 0) {
682 /* no configure events yet */
686 /* force a gap of 0.5 seconds since the last configure event
689 if (get_microseconds() - last_configure_time < 500000) {
692 have_configure_timeout = false;
693 save_ardour_state ();
699 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
701 if (have_configure_timeout) {
702 last_configure_time = get_microseconds();
704 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
705 have_configure_timeout = true;
712 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
714 const XMLProperty* prop;
716 if ((prop = node.property ("roll")) != 0) {
717 roll_controllable->set_id (prop->value());
719 if ((prop = node.property ("stop")) != 0) {
720 stop_controllable->set_id (prop->value());
722 if ((prop = node.property ("goto-start")) != 0) {
723 goto_start_controllable->set_id (prop->value());
725 if ((prop = node.property ("goto-end")) != 0) {
726 goto_end_controllable->set_id (prop->value());
728 if ((prop = node.property ("auto-loop")) != 0) {
729 auto_loop_controllable->set_id (prop->value());
731 if ((prop = node.property ("play-selection")) != 0) {
732 play_selection_controllable->set_id (prop->value());
734 if ((prop = node.property ("rec")) != 0) {
735 rec_controllable->set_id (prop->value());
737 if ((prop = node.property ("shuttle")) != 0) {
738 shuttle_box->controllable()->set_id (prop->value());
743 ARDOUR_UI::get_transport_controllable_state ()
745 XMLNode* node = new XMLNode(X_("TransportControllables"));
748 roll_controllable->id().print (buf, sizeof (buf));
749 node->add_property (X_("roll"), buf);
750 stop_controllable->id().print (buf, sizeof (buf));
751 node->add_property (X_("stop"), buf);
752 goto_start_controllable->id().print (buf, sizeof (buf));
753 node->add_property (X_("goto_start"), buf);
754 goto_end_controllable->id().print (buf, sizeof (buf));
755 node->add_property (X_("goto_end"), buf);
756 auto_loop_controllable->id().print (buf, sizeof (buf));
757 node->add_property (X_("auto_loop"), buf);
758 play_selection_controllable->id().print (buf, sizeof (buf));
759 node->add_property (X_("play_selection"), buf);
760 rec_controllable->id().print (buf, sizeof (buf));
761 node->add_property (X_("rec"), buf);
762 shuttle_box->controllable()->id().print (buf, sizeof (buf));
763 node->add_property (X_("shuttle"), buf);
769 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
772 _session->save_state (snapshot_name);
777 ARDOUR_UI::autosave_session ()
779 if (g_main_depth() > 1) {
780 /* inside a recursive main loop,
781 give up because we may not be able to
787 if (!Config->get_periodic_safety_backups()) {
792 _session->maybe_write_autosave();
799 ARDOUR_UI::update_autosave ()
801 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
803 if (_session && _session->dirty()) {
804 if (_autosave_connection.connected()) {
805 _autosave_connection.disconnect();
808 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
809 Config->get_periodic_safety_backup_interval() * 1000);
812 if (_autosave_connection.connected()) {
813 _autosave_connection.disconnect();
819 ARDOUR_UI::check_announcements ()
822 string _annc_filename;
825 _annc_filename = PROGRAM_NAME "_announcements_osx_";
826 #elif defined PLATFORM_WINDOWS
827 _annc_filename = PROGRAM_NAME "_announcements_windows_";
829 _annc_filename = PROGRAM_NAME "_announcements_linux_";
831 _annc_filename.append (VERSIONSTRING);
833 _announce_string = "";
835 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
836 FILE* fin = g_fopen (path.c_str(), "rb");
838 while (!feof (fin)) {
841 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
844 _announce_string.append (tmp, len);
849 pingback (VERSIONSTRING, path);
854 ARDOUR_UI::starting ()
856 Application* app = Application::instance ();
858 bool brand_new_user = ArdourStartup::required ();
860 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
861 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
863 if (ARDOUR_COMMAND_LINE::check_announcements) {
864 check_announcements ();
869 /* we need to create this early because it may need to set the
870 * audio backend end up.
874 audio_midi_setup.get (true);
876 std::cerr << "audio-midi engine setup failed."<< std::endl;
880 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
881 nsm = new NSM_Client;
882 if (!nsm->init (nsm_url)) {
883 /* the ardour executable may have different names:
885 * waf's obj.target for distro versions: eg ardour4, ardourvst4
886 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
887 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
889 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
891 const char *process_name = g_getenv ("ARDOUR_SELF");
892 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
895 // wait for announce reply from nsm server
896 for ( i = 0; i < 5000; ++i) {
900 if (nsm->is_active()) {
905 error << _("NSM server did not announce itself") << endmsg;
908 // wait for open command from nsm server
909 for ( i = 0; i < 5000; ++i) {
912 if (nsm->client_id ()) {
918 error << _("NSM: no client ID provided") << endmsg;
922 if (_session && nsm) {
923 _session->set_nsm_state( nsm->is_active() );
925 error << _("NSM: no session created") << endmsg;
929 // nsm requires these actions disabled
930 vector<string> action_names;
931 action_names.push_back("SaveAs");
932 action_names.push_back("Rename");
933 action_names.push_back("New");
934 action_names.push_back("Open");
935 action_names.push_back("Recent");
936 action_names.push_back("Close");
938 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
939 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
941 act->set_sensitive (false);
948 error << _("NSM: initialization failed") << endmsg;
954 if (brand_new_user) {
955 _initial_verbose_plugin_scan = true;
960 _initial_verbose_plugin_scan = false;
961 switch (s.response ()) {
962 case Gtk::RESPONSE_OK:
969 #ifdef NO_PLUGIN_STATE
971 ARDOUR::RecentSessions rs;
972 ARDOUR::read_recent_sessions (rs);
974 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
976 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
978 /* already used Ardour, have sessions ... warn about plugin state */
980 ArdourDialog d (_("Free/Demo Version Warning"), true);
982 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
983 CheckButton c (_("Don't warn me about this again"));
985 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"),
986 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
987 _("It will not restore OR save any plugin settings"),
988 _("If you load an existing session with plugin settings\n"
989 "they will not be used and will be lost."),
990 _("To get full access to updates without this limitation\n"
991 "consider becoming a subscriber for a low cost every month.")));
992 l.set_justify (JUSTIFY_CENTER);
994 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
996 d.get_vbox()->pack_start (l, true, true);
997 d.get_vbox()->pack_start (b, false, false, 12);
998 d.get_vbox()->pack_start (c, false, false, 12);
1000 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1001 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1005 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1007 if (d.run () != RESPONSE_OK) {
1013 /* go get a session */
1015 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1017 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1018 std::cerr << "Cannot get session parameters."<< std::endl;
1025 goto_editor_window ();
1027 WM::Manager::instance().show_visible ();
1029 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1030 * editor window, and we may want stuff to be hidden.
1032 _status_bar_visibility.update ();
1034 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1039 ARDOUR_UI::check_memory_locking ()
1041 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1042 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1046 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1048 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1050 struct rlimit limits;
1052 long pages, page_size;
1054 size_t pages_len=sizeof(pages);
1055 if ((page_size = getpagesize()) < 0 ||
1056 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1058 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1063 ram = (int64_t) pages * (int64_t) page_size;
1066 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1070 if (limits.rlim_cur != RLIM_INFINITY) {
1072 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1076 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1077 "This might cause %1 to run out of memory before your system "
1078 "runs out of memory. \n\n"
1079 "You can view the memory limit with 'ulimit -l', "
1080 "and it is normally controlled by %2"),
1083 X_("/etc/login.conf")
1085 X_(" /etc/security/limits.conf")
1089 msg.set_default_response (RESPONSE_OK);
1091 VBox* vbox = msg.get_vbox();
1093 CheckButton cb (_("Do not show this window again"));
1094 hbox.pack_start (cb, true, false);
1095 vbox->pack_start (hbox);
1100 pop_back_splash (msg);
1102 editor->ensure_float (msg);
1105 if (cb.get_active()) {
1106 XMLNode node (X_("no-memory-warning"));
1107 Config->add_instant_xml (node);
1112 #endif // !__APPLE__
1117 ARDOUR_UI::queue_finish ()
1119 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1123 ARDOUR_UI::idle_finish ()
1126 return false; /* do not call again */
1133 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1135 if (_session->dirty()) {
1136 vector<string> actions;
1137 actions.push_back (_("Don't quit"));
1138 actions.push_back (_("Just quit"));
1139 actions.push_back (_("Save and quit"));
1140 switch (ask_about_saving_session(actions)) {
1145 /* use the default name */
1146 if (save_state_canfail ("")) {
1147 /* failed - don't quit */
1148 MessageDialog msg (*editor,
1149 string_compose (_("\
1150 %1 was unable to save your session.\n\n\
1151 If you still wish to quit, please use the\n\n\
1152 \"Just quit\" option."), PROGRAM_NAME));
1153 pop_back_splash(msg);
1163 second_connection.disconnect ();
1164 point_one_second_connection.disconnect ();
1165 point_zero_something_second_connection.disconnect();
1166 fps_connection.disconnect();
1169 delete ARDOUR_UI::instance()->video_timeline;
1170 ARDOUR_UI::instance()->video_timeline = NULL;
1171 stop_video_server();
1173 /* Save state before deleting the session, as that causes some
1174 windows to be destroyed before their visible state can be
1177 save_ardour_state ();
1179 close_all_dialogs ();
1182 _session->set_clean ();
1183 _session->remove_pending_capture_state ();
1188 halt_connection.disconnect ();
1189 AudioEngine::instance()->stop ();
1190 #ifdef WINDOWS_VST_SUPPORT
1191 fst_stop_threading();
1197 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1199 ArdourDialog window (_("Unsaved Session"));
1200 Gtk::HBox dhbox; // the hbox for the image and text
1201 Gtk::Label prompt_label;
1202 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1206 assert (actions.size() >= 3);
1208 window.add_button (actions[0], RESPONSE_REJECT);
1209 window.add_button (actions[1], RESPONSE_APPLY);
1210 window.add_button (actions[2], RESPONSE_ACCEPT);
1212 window.set_default_response (RESPONSE_ACCEPT);
1214 Gtk::Button noquit_button (msg);
1215 noquit_button.set_name ("EditorGTKButton");
1219 if (_session->snap_name() == _session->name()) {
1220 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?"),
1221 _session->snap_name());
1223 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?"),
1224 _session->snap_name());
1227 prompt_label.set_text (prompt);
1228 prompt_label.set_name (X_("PrompterLabel"));
1229 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1231 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1232 dhbox.set_homogeneous (false);
1233 dhbox.pack_start (*dimage, false, false, 5);
1234 dhbox.pack_start (prompt_label, true, false, 5);
1235 window.get_vbox()->pack_start (dhbox);
1237 window.set_name (_("Prompter"));
1238 window.set_modal (true);
1239 window.set_resizable (false);
1242 prompt_label.show();
1247 ResponseType r = (ResponseType) window.run();
1252 case RESPONSE_ACCEPT: // save and get out of here
1254 case RESPONSE_APPLY: // get out of here
1265 ARDOUR_UI::every_second ()
1268 update_xrun_count ();
1269 update_buffer_load ();
1270 update_disk_space ();
1271 update_timecode_format ();
1272 update_peak_thread_work ();
1274 if (nsm && nsm->is_active ()) {
1277 if (!_was_dirty && _session->dirty ()) {
1281 else if (_was_dirty && !_session->dirty ()){
1289 ARDOUR_UI::every_point_one_seconds ()
1291 // TODO get rid of this..
1292 // ShuttleControl is updated directly via TransportStateChange signal
1296 ARDOUR_UI::every_point_zero_something_seconds ()
1298 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1300 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1301 float mpeak = editor_meter->update_meters();
1302 if (mpeak > editor_meter_max_peak) {
1303 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1304 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1311 ARDOUR_UI::set_fps_timeout_connection ()
1313 unsigned int interval = 40;
1314 if (!_session) return;
1315 if (_session->timecode_frames_per_second() != 0) {
1316 /* ideally we'll use a select() to sleep and not accumulate
1317 * idle time to provide a regular periodic signal.
1318 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1319 * However, that'll require a dedicated thread and cross-thread
1320 * signals to the GUI Thread..
1322 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1323 * _session->frame_rate() / _session->nominal_frame_rate()
1324 / _session->timecode_frames_per_second()
1326 #ifdef PLATFORM_WINDOWS
1327 // the smallest windows scheduler time-slice is ~15ms.
1328 // periodic GUI timeouts shorter than that will cause
1329 // WaitForSingleObject to spinlock (100% of one CPU Core)
1330 // and gtk never enters idle mode.
1331 // also changing timeBeginPeriod(1) does not affect that in
1332 // any beneficial way, so we just limit the max rate for now.
1333 interval = std::max(30u, interval); // at most ~33Hz.
1335 interval = std::max(8u, interval); // at most 120Hz.
1338 fps_connection.disconnect();
1339 Timers::set_fps_interval (interval);
1343 ARDOUR_UI::update_sample_rate (framecnt_t)
1347 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1349 if (!AudioEngine::instance()->connected()) {
1351 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1355 framecnt_t rate = AudioEngine::instance()->sample_rate();
1358 /* no sample rate available */
1359 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1362 if (fmod (rate, 1000.0) != 0.0) {
1363 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1364 (float) rate / 1000.0f,
1365 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1367 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1369 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1373 sample_rate_label.set_markup (buf);
1377 ARDOUR_UI::update_format ()
1380 format_label.set_text ("");
1385 s << _("File:") << X_(" <span foreground=\"green\">");
1387 switch (_session->config.get_native_file_header_format ()) {
1419 switch (_session->config.get_native_file_data_format ()) {
1433 format_label.set_markup (s.str ());
1437 ARDOUR_UI::update_xrun_count ()
1441 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1442 should also be changed.
1446 const unsigned int x = _session->get_xrun_count ();
1448 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1450 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1453 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1455 xrun_label.set_markup (buf);
1456 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1460 ARDOUR_UI::update_cpu_load ()
1464 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1465 should also be changed.
1468 double const c = AudioEngine::instance()->get_dsp_load ();
1469 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1470 cpu_load_label.set_markup (buf);
1474 ARDOUR_UI::update_peak_thread_work ()
1477 const int c = SourceFactory::peak_work_queue_length ();
1479 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1480 peak_thread_work_label.set_markup (buf);
1482 peak_thread_work_label.set_markup (X_(""));
1487 ARDOUR_UI::update_buffer_load ()
1491 uint32_t const playback = _session ? _session->playback_load () : 100;
1492 uint32_t const capture = _session ? _session->capture_load () : 100;
1494 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1495 should also be changed.
1501 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1502 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1503 playback <= 5 ? X_("red") : X_("green"),
1505 capture <= 5 ? X_("red") : X_("green"),
1509 buffer_load_label.set_markup (buf);
1511 buffer_load_label.set_text ("");
1516 ARDOUR_UI::count_recenabled_streams (Route& route)
1518 Track* track = dynamic_cast<Track*>(&route);
1519 if (track && track->record_enabled()) {
1520 rec_enabled_streams += track->n_inputs().n_total();
1525 ARDOUR_UI::update_disk_space()
1527 if (_session == 0) {
1531 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1533 framecnt_t fr = _session->frame_rate();
1536 /* skip update - no SR available */
1541 /* Available space is unknown */
1542 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1543 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1544 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1546 rec_enabled_streams = 0;
1547 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1549 framecnt_t frames = opt_frames.get_value_or (0);
1551 if (rec_enabled_streams) {
1552 frames /= rec_enabled_streams;
1559 hrs = frames / (fr * 3600);
1562 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1564 frames -= hrs * fr * 3600;
1565 mins = frames / (fr * 60);
1566 frames -= mins * fr * 60;
1569 bool const low = (hrs == 0 && mins <= 30);
1573 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1574 low ? X_("red") : X_("green"),
1580 disk_space_label.set_markup (buf);
1584 ARDOUR_UI::update_timecode_format ()
1590 TimecodeSlave* tcslave;
1591 SyncSource sync_src = Config->get_sync_source();
1593 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1594 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1599 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1600 matching ? X_("green") : X_("red"),
1601 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1603 snprintf (buf, sizeof (buf), "TC: n/a");
1606 timecode_format_label.set_markup (buf);
1610 ARDOUR_UI::update_wall_clock ()
1614 static int last_min = -1;
1617 tm_now = localtime (&now);
1618 if (last_min != tm_now->tm_min) {
1620 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1621 wall_clock_label.set_text (buf);
1622 last_min = tm_now->tm_min;
1629 ARDOUR_UI::open_recent_session ()
1631 bool can_return = (_session != 0);
1633 SessionDialog recent_session_dialog;
1637 ResponseType r = (ResponseType) recent_session_dialog.run ();
1640 case RESPONSE_ACCEPT:
1644 recent_session_dialog.hide();
1651 recent_session_dialog.hide();
1655 std::string path = recent_session_dialog.session_folder();
1656 std::string state = recent_session_dialog.session_name (should_be_new);
1658 if (should_be_new == true) {
1662 _session_is_new = false;
1664 if (load_session (path, state) == 0) {
1673 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1675 if (!AudioEngine::instance()->connected()) {
1676 MessageDialog msg (parent, string_compose (
1677 _("%1 is not connected to any audio backend.\n"
1678 "You cannot open or close sessions in this condition"),
1680 pop_back_splash (msg);
1688 ARDOUR_UI::open_session ()
1690 if (!check_audioengine(*editor)) {
1694 /* ardour sessions are folders */
1695 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1696 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1697 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1698 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1701 string session_parent_dir = Glib::path_get_dirname(_session->path());
1702 open_session_selector.set_current_folder(session_parent_dir);
1704 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1707 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1709 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1710 string default_session_folder = Config->get_default_session_parent_dir();
1711 open_session_selector.add_shortcut_folder (default_session_folder);
1713 catch (Glib::Error & e) {
1714 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1717 FileFilter session_filter;
1718 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1719 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1720 open_session_selector.add_filter (session_filter);
1721 open_session_selector.set_filter (session_filter);
1723 int response = open_session_selector.run();
1724 open_session_selector.hide ();
1726 if (response == Gtk::RESPONSE_CANCEL) {
1730 string session_path = open_session_selector.get_filename();
1734 if (session_path.length() > 0) {
1735 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1736 _session_is_new = isnew;
1737 load_session (path, name);
1744 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1745 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1747 list<boost::shared_ptr<MidiTrack> > tracks;
1749 if (_session == 0) {
1750 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1755 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1757 if (tracks.size() != how_many) {
1758 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1763 MessageDialog msg (*editor,
1764 string_compose (_("There are insufficient ports available\n\
1765 to create a new track or bus.\n\
1766 You should save %1, exit and\n\
1767 restart with more ports."), PROGRAM_NAME));
1774 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1776 ChanCount one_midi_channel;
1777 one_midi_channel.set (DataType::MIDI, 1);
1780 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1785 ARDOUR_UI::session_add_audio_route (
1787 int32_t input_channels,
1788 int32_t output_channels,
1789 ARDOUR::TrackMode mode,
1790 RouteGroup* route_group,
1792 string const & name_template
1795 list<boost::shared_ptr<AudioTrack> > tracks;
1798 if (_session == 0) {
1799 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1805 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1807 if (tracks.size() != how_many) {
1808 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1814 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1816 if (routes.size() != how_many) {
1817 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1824 MessageDialog msg (*editor,
1825 string_compose (_("There are insufficient ports available\n\
1826 to create a new track or bus.\n\
1827 You should save %1, exit and\n\
1828 restart with more ports."), PROGRAM_NAME));
1829 pop_back_splash (msg);
1835 ARDOUR_UI::transport_goto_start ()
1838 _session->goto_start();
1840 /* force displayed area in editor to start no matter
1841 what "follow playhead" setting is.
1845 editor->center_screen (_session->current_start_frame ());
1851 ARDOUR_UI::transport_goto_zero ()
1854 _session->request_locate (0);
1856 /* force displayed area in editor to start no matter
1857 what "follow playhead" setting is.
1861 editor->reset_x_origin (0);
1867 ARDOUR_UI::transport_goto_wallclock ()
1869 if (_session && editor) {
1876 localtime_r (&now, &tmnow);
1878 framecnt_t frame_rate = _session->frame_rate();
1880 if (frame_rate == 0) {
1881 /* no frame rate available */
1885 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1886 frames += tmnow.tm_min * (60 * frame_rate);
1887 frames += tmnow.tm_sec * frame_rate;
1889 _session->request_locate (frames, _session->transport_rolling ());
1891 /* force displayed area in editor to start no matter
1892 what "follow playhead" setting is.
1896 editor->center_screen (frames);
1902 ARDOUR_UI::transport_goto_end ()
1905 framepos_t const frame = _session->current_end_frame();
1906 _session->request_locate (frame);
1908 /* force displayed area in editor to start no matter
1909 what "follow playhead" setting is.
1913 editor->center_screen (frame);
1919 ARDOUR_UI::transport_stop ()
1925 if (_session->is_auditioning()) {
1926 _session->cancel_audition ();
1930 _session->request_stop (false, true);
1933 /** Check if any tracks are record enabled. If none are, record enable all of them.
1934 * @return true if track record-enabled status was changed, false otherwise.
1937 ARDOUR_UI::trx_record_enable_all_tracks ()
1943 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1944 bool none_record_enabled = true;
1946 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1947 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1950 if (t->record_enabled()) {
1951 none_record_enabled = false;
1956 if (none_record_enabled) {
1957 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1960 return none_record_enabled;
1964 ARDOUR_UI::transport_record (bool roll)
1967 switch (_session->record_status()) {
1968 case Session::Disabled:
1969 if (_session->ntracks() == 0) {
1970 MessageDialog msg (*editor, _("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."));
1974 if (Profile->get_trx()) {
1975 roll = trx_record_enable_all_tracks ();
1977 _session->maybe_enable_record ();
1982 case Session::Recording:
1984 _session->request_stop();
1986 _session->disable_record (false, true);
1990 case Session::Enabled:
1991 _session->disable_record (false, true);
1997 ARDOUR_UI::transport_roll ()
2003 if (_session->is_auditioning()) {
2008 if (_session->config.get_external_sync()) {
2009 switch (Config->get_sync_source()) {
2013 /* transport controlled by the master */
2019 bool rolling = _session->transport_rolling();
2021 if (_session->get_play_loop()) {
2023 /* If loop playback is not a mode, then we should cancel
2024 it when this action is requested. If it is a mode
2025 we just leave it in place.
2028 if (!Config->get_loop_is_mode()) {
2029 /* XXX it is not possible to just leave seamless loop and keep
2030 playing at present (nov 4th 2009)
2032 if (!Config->get_seamless_loop()) {
2033 /* stop loop playback and stop rolling */
2034 _session->request_play_loop (false, true);
2035 } else if (rolling) {
2036 /* stop loop playback but keep rolling */
2037 _session->request_play_loop (false, false);
2041 } else if (_session->get_play_range () ) {
2042 /* stop playing a range if we currently are */
2043 _session->request_play_range (0, true);
2047 _session->request_transport_speed (1.0f);
2052 ARDOUR_UI::get_smart_mode() const
2054 return ( editor->get_smart_mode() );
2059 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2065 if (_session->is_auditioning()) {
2066 _session->cancel_audition ();
2070 if (_session->config.get_external_sync()) {
2071 switch (Config->get_sync_source()) {
2075 /* transport controlled by the master */
2080 bool rolling = _session->transport_rolling();
2081 bool affect_transport = true;
2083 if (rolling && roll_out_of_bounded_mode) {
2084 /* drop out of loop/range playback but leave transport rolling */
2085 if (_session->get_play_loop()) {
2086 if (_session->actively_recording()) {
2088 /* just stop using the loop, then actually stop
2091 _session->request_play_loop (false, affect_transport);
2094 if (Config->get_seamless_loop()) {
2095 /* the disk buffers contain copies of the loop - we can't
2096 just keep playing, so stop the transport. the user
2097 can restart as they wish.
2099 affect_transport = true;
2101 /* disk buffers are normal, so we can keep playing */
2102 affect_transport = false;
2104 _session->request_play_loop (false, affect_transport);
2106 } else if (_session->get_play_range ()) {
2107 affect_transport = false;
2108 _session->request_play_range (0, true);
2112 if (affect_transport) {
2114 _session->request_stop (with_abort, true);
2116 /* the only external sync condition we can be in here
2117 * would be Engine (JACK) sync, in which case we still
2121 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
2122 _session->request_play_range (&editor->get_selection().time, true);
2123 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2125 _session->request_transport_speed (1.0f);
2131 ARDOUR_UI::toggle_session_auto_loop ()
2137 Location * looploc = _session->locations()->auto_loop_location();
2143 if (_session->get_play_loop()) {
2145 /* looping enabled, our job is to disable it */
2147 _session->request_play_loop (false);
2151 /* looping not enabled, our job is to enable it.
2153 loop-is-NOT-mode: this action always starts the transport rolling.
2154 loop-IS-mode: this action simply sets the loop play mechanism, but
2155 does not start transport.
2157 if (Config->get_loop_is_mode()) {
2158 _session->request_play_loop (true, false);
2160 _session->request_play_loop (true, true);
2164 //show the loop markers
2165 looploc->set_hidden (false, this);
2169 ARDOUR_UI::transport_play_selection ()
2175 editor->play_selection ();
2179 ARDOUR_UI::transport_play_preroll ()
2184 editor->play_with_preroll ();
2188 ARDOUR_UI::transport_rewind (int option)
2190 float current_transport_speed;
2193 current_transport_speed = _session->transport_speed();
2195 if (current_transport_speed >= 0.0f) {
2198 _session->request_transport_speed (-1.0f);
2201 _session->request_transport_speed (-4.0f);
2204 _session->request_transport_speed (-0.5f);
2209 _session->request_transport_speed (current_transport_speed * 1.5f);
2215 ARDOUR_UI::transport_forward (int option)
2221 float current_transport_speed = _session->transport_speed();
2223 if (current_transport_speed <= 0.0f) {
2226 _session->request_transport_speed (1.0f);
2229 _session->request_transport_speed (4.0f);
2232 _session->request_transport_speed (0.5f);
2237 _session->request_transport_speed (current_transport_speed * 1.5f);
2242 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2248 boost::shared_ptr<Route> r;
2250 if ((r = _session->route_by_remote_id (rid)) != 0) {
2252 boost::shared_ptr<Track> t;
2254 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2255 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2261 ARDOUR_UI::map_transport_state ()
2264 auto_loop_button.unset_active_state ();
2265 play_selection_button.unset_active_state ();
2266 roll_button.unset_active_state ();
2267 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2271 shuttle_box->map_transport_state ();
2273 float sp = _session->transport_speed();
2279 if (_session->get_play_range()) {
2281 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2282 roll_button.unset_active_state ();
2283 auto_loop_button.unset_active_state ();
2285 } else if (_session->get_play_loop ()) {
2287 auto_loop_button.set_active (true);
2288 play_selection_button.set_active (false);
2289 if (Config->get_loop_is_mode()) {
2290 roll_button.set_active (true);
2292 roll_button.set_active (false);
2297 roll_button.set_active (true);
2298 play_selection_button.set_active (false);
2299 auto_loop_button.set_active (false);
2302 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2303 /* light up both roll and play-selection if they are joined */
2304 roll_button.set_active (true);
2305 play_selection_button.set_active (true);
2308 stop_button.set_active (false);
2312 stop_button.set_active (true);
2313 roll_button.set_active (false);
2314 play_selection_button.set_active (false);
2315 if (Config->get_loop_is_mode ()) {
2316 auto_loop_button.set_active (_session->get_play_loop());
2318 auto_loop_button.set_active (false);
2320 update_disk_space ();
2325 ARDOUR_UI::blink_handler (bool blink_on)
2327 transport_rec_enable_blink (blink_on);
2328 solo_blink (blink_on);
2329 sync_blink (blink_on);
2330 audition_blink (blink_on);
2331 feedback_blink (blink_on);
2332 error_blink (blink_on);
2336 ARDOUR_UI::update_clocks ()
2338 if (!_session) return;
2340 if (editor && !editor->dragging_playhead()) {
2341 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2346 ARDOUR_UI::start_clocking ()
2348 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2349 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2351 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2356 ARDOUR_UI::stop_clocking ()
2358 clock_signal_connection.disconnect ();
2362 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2366 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2368 label->set_text (buf);
2369 bar->set_fraction (fraction);
2371 /* process events, redraws, etc. */
2373 while (gtk_events_pending()) {
2374 gtk_main_iteration ();
2377 return true; /* continue with save-as */
2381 ARDOUR_UI::save_session_as ()
2387 if (!save_as_dialog) {
2388 save_as_dialog = new SaveAsDialog;
2391 save_as_dialog->set_name (_session->name());
2393 int response = save_as_dialog->run ();
2395 save_as_dialog->hide ();
2398 case Gtk::RESPONSE_OK:
2407 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2408 sa.new_name = save_as_dialog->new_name ();
2409 sa.switch_to = save_as_dialog->switch_to();
2410 sa.copy_media = save_as_dialog->copy_media();
2411 sa.copy_external = save_as_dialog->copy_external();
2412 sa.include_media = save_as_dialog->include_media ();
2414 /* Only bother with a progress dialog if we're going to copy
2415 media into the save-as target. Without that choice, this
2416 will be very fast because we're only talking about a few kB's to
2417 perhaps a couple of MB's of data.
2420 ArdourDialog progress_dialog (_("Save As"), true);
2422 if (sa.include_media && sa.copy_media) {
2425 Gtk::ProgressBar progress_bar;
2427 progress_dialog.get_vbox()->pack_start (label);
2428 progress_dialog.get_vbox()->pack_start (progress_bar);
2430 progress_bar.show ();
2432 /* this signal will be emitted from within this, the calling thread,
2433 * after every file is copied. It provides information on percentage
2434 * complete (in terms of total data to copy), the number of files
2435 * copied so far, and the total number to copy.
2440 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2442 progress_dialog.show_all ();
2443 progress_dialog.present ();
2446 if (_session->save_as (sa)) {
2448 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2452 if (!sa.include_media) {
2453 unload_session (false);
2454 load_session (sa.final_session_folder_name, sa.new_name);
2459 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2463 struct tm local_time;
2466 localtime_r (&n, &local_time);
2467 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2469 save_state (timebuf, switch_to_it);
2474 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2478 prompter.get_result (snapname);
2480 bool do_save = (snapname.length() != 0);
2483 char illegal = Session::session_name_is_legal(snapname);
2485 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2486 "snapshot names may not contain a '%1' character"), illegal));
2492 vector<std::string> p;
2493 get_state_files_in_directory (_session->session_directory().root_path(), p);
2494 vector<string> n = get_file_names_no_extension (p);
2496 if (find (n.begin(), n.end(), snapname) != n.end()) {
2498 do_save = overwrite_file_dialog (prompter,
2499 _("Confirm Snapshot Overwrite"),
2500 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2504 save_state (snapname, switch_to_it);
2514 /** Ask the user for the name of a new snapshot and then take it.
2518 ARDOUR_UI::snapshot_session (bool switch_to_it)
2520 ArdourPrompter prompter (true);
2522 prompter.set_name ("Prompter");
2523 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2525 prompter.set_title (_("Save as..."));
2526 prompter.set_prompt (_("New session name"));
2528 prompter.set_title (_("Take Snapshot"));
2529 prompter.set_prompt (_("Name of new snapshot"));
2533 prompter.set_initial_text (_session->snap_name());
2537 struct tm local_time;
2540 localtime_r (&n, &local_time);
2541 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2542 prompter.set_initial_text (timebuf);
2545 bool finished = false;
2547 switch (prompter.run()) {
2548 case RESPONSE_ACCEPT:
2550 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2561 /** Ask the user for a new session name and then rename the session to it.
2565 ARDOUR_UI::rename_session ()
2571 ArdourPrompter prompter (true);
2574 prompter.set_name ("Prompter");
2575 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2576 prompter.set_title (_("Rename Session"));
2577 prompter.set_prompt (_("New session name"));
2580 switch (prompter.run()) {
2581 case RESPONSE_ACCEPT:
2583 prompter.get_result (name);
2585 bool do_rename = (name.length() != 0);
2588 char illegal = Session::session_name_is_legal (name);
2591 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2592 "session names may not contain a '%1' character"), illegal));
2597 switch (_session->rename (name)) {
2599 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2600 msg.set_position (WIN_POS_MOUSE);
2608 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2609 msg.set_position (WIN_POS_MOUSE);
2625 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2627 if (!_session || _session->deletion_in_progress()) {
2631 XMLNode* node = new XMLNode (X_("UI"));
2633 WM::Manager::instance().add_state (*node);
2635 node->add_child_nocopy (gui_object_state->get_state());
2637 _session->add_extra_xml (*node);
2639 if (export_video_dialog) {
2640 _session->add_extra_xml (export_video_dialog->get_state());
2643 save_state_canfail (name, switch_to_it);
2647 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2652 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2657 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2662 ARDOUR_UI::primary_clock_value_changed ()
2665 _session->request_locate (primary_clock->current_time ());
2670 ARDOUR_UI::big_clock_value_changed ()
2673 _session->request_locate (big_clock->current_time ());
2678 ARDOUR_UI::secondary_clock_value_changed ()
2681 _session->request_locate (secondary_clock->current_time ());
2686 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2688 if (_session == 0) {
2692 if (_session->step_editing()) {
2696 Session::RecordState const r = _session->record_status ();
2697 bool const h = _session->have_rec_enabled_track ();
2699 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2701 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2703 rec_button.set_active_state (Gtkmm2ext::Off);
2705 } else if (r == Session::Recording && h) {
2706 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2708 rec_button.unset_active_state ();
2713 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2717 prompter.get_result (name);
2719 if (name.length()) {
2720 int failed = _session->save_template (name);
2722 if (failed == -2) { /* file already exists. */
2723 bool overwrite = overwrite_file_dialog (prompter,
2724 _("Confirm Template Overwrite"),
2725 _("A template already exists with that name. Do you want to overwrite it?"));
2728 _session->save_template (name, true);
2740 ARDOUR_UI::save_template ()
2742 ArdourPrompter prompter (true);
2744 if (!check_audioengine(*editor)) {
2748 prompter.set_name (X_("Prompter"));
2749 prompter.set_title (_("Save Template"));
2750 prompter.set_prompt (_("Name for template:"));
2751 prompter.set_initial_text(_session->name() + _("-template"));
2752 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2754 bool finished = false;
2756 switch (prompter.run()) {
2757 case RESPONSE_ACCEPT:
2758 finished = process_save_template_prompter (prompter);
2769 ARDOUR_UI::edit_metadata ()
2771 SessionMetadataEditor dialog;
2772 dialog.set_session (_session);
2773 dialog.grab_focus ();
2778 ARDOUR_UI::import_metadata ()
2780 SessionMetadataImporter dialog;
2781 dialog.set_session (_session);
2786 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2788 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2790 MessageDialog msg (str,
2792 Gtk::MESSAGE_WARNING,
2793 Gtk::BUTTONS_YES_NO,
2797 msg.set_name (X_("OpenExistingDialog"));
2798 msg.set_title (_("Open Existing Session"));
2799 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2800 msg.set_position (Gtk::WIN_POS_CENTER);
2801 pop_back_splash (msg);
2803 switch (msg.run()) {
2812 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2814 BusProfile bus_profile;
2816 if (nsm || Profile->get_sae()) {
2818 bus_profile.master_out_channels = 2;
2819 bus_profile.input_ac = AutoConnectPhysical;
2820 bus_profile.output_ac = AutoConnectMaster;
2821 bus_profile.requested_physical_in = 0; // use all available
2822 bus_profile.requested_physical_out = 0; // use all available
2826 /* get settings from advanced section of NSD */
2828 if (sd.create_master_bus()) {
2829 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2831 bus_profile.master_out_channels = 0;
2834 if (sd.connect_inputs()) {
2835 bus_profile.input_ac = AutoConnectPhysical;
2837 bus_profile.input_ac = AutoConnectOption (0);
2840 bus_profile.output_ac = AutoConnectOption (0);
2842 if (sd.connect_outputs ()) {
2843 if (sd.connect_outs_to_master()) {
2844 bus_profile.output_ac = AutoConnectMaster;
2845 } else if (sd.connect_outs_to_physical()) {
2846 bus_profile.output_ac = AutoConnectPhysical;
2850 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2851 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2854 if (build_session (session_path, session_name, bus_profile)) {
2862 ARDOUR_UI::load_from_application_api (const std::string& path)
2864 ARDOUR_COMMAND_LINE::session_name = path;
2865 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2867 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2869 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2870 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2871 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2872 * -> SessionDialog is not displayed
2875 if (_session_dialog) {
2876 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2877 std::string session_path = path;
2878 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2879 session_path = Glib::path_get_dirname (session_path);
2881 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2882 _session_dialog->set_provided_session (session_name, session_path);
2883 _session_dialog->response (RESPONSE_NONE);
2884 _session_dialog->hide();
2889 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2890 /* /path/to/foo => /path/to/foo, foo */
2891 rv = load_session (path, basename_nosuffix (path));
2893 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2894 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2897 // if load_session fails -> pop up SessionDialog.
2899 ARDOUR_COMMAND_LINE::session_name = "";
2901 if (get_session_parameters (true, false)) {
2905 goto_editor_window ();
2909 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2911 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2913 string session_name;
2914 string session_path;
2915 string template_name;
2917 bool likely_new = false;
2918 bool cancel_not_quit;
2920 /* deal with any existing DIRTY session now, rather than later. don't
2921 * treat a non-dirty session this way, so that it stays visible
2922 * as we bring up the new session dialog.
2925 if (_session && ARDOUR_UI::instance()->video_timeline) {
2926 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2929 /* if there is already a session, relabel the button
2930 on the SessionDialog so that we don't Quit directly
2932 cancel_not_quit = (_session != 0);
2934 if (_session && _session->dirty()) {
2935 if (unload_session (false)) {
2936 /* unload cancelled by user */
2939 ARDOUR_COMMAND_LINE::session_name = "";
2942 if (!load_template.empty()) {
2943 should_be_new = true;
2944 template_name = load_template;
2947 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2948 session_path = ARDOUR_COMMAND_LINE::session_name;
2950 if (!session_path.empty()) {
2951 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2952 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2953 /* session/snapshot file, change path to be dir */
2954 session_path = Glib::path_get_dirname (session_path);
2959 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2961 _session_dialog = &session_dialog;
2964 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2966 /* if they named a specific statefile, use it, otherwise they are
2967 just giving a session folder, and we want to use it as is
2968 to find the session.
2971 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2973 if (suffix != string::npos) {
2974 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2975 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2976 session_name = Glib::path_get_basename (session_name);
2978 session_path = ARDOUR_COMMAND_LINE::session_name;
2979 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2984 session_dialog.clear_given ();
2987 if (should_be_new || session_name.empty()) {
2988 /* need the dialog to get info from user */
2990 cerr << "run dialog\n";
2992 switch (session_dialog.run()) {
2993 case RESPONSE_ACCEPT:
2996 /* this is used for async * app->ShouldLoad(). */
2997 continue; // while loop
3000 if (quit_on_cancel) {
3001 // JE - Currently (July 2014) this section can only get reached if the
3002 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3003 // point does NOT indicate an abnormal termination). Therefore, let's
3004 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3006 pthread_cancel_all ();
3014 session_dialog.hide ();
3017 /* if we run the startup dialog again, offer more than just "new session" */
3019 should_be_new = false;
3021 session_name = session_dialog.session_name (likely_new);
3022 session_path = session_dialog.session_folder ();
3028 string::size_type suffix = session_name.find (statefile_suffix);
3030 if (suffix != string::npos) {
3031 session_name = session_name.substr (0, suffix);
3034 /* this shouldn't happen, but we catch it just in case it does */
3036 if (session_name.empty()) {
3040 if (session_dialog.use_session_template()) {
3041 template_name = session_dialog.session_template_name();
3042 _session_is_new = true;
3045 if (session_name[0] == G_DIR_SEPARATOR ||
3046 #ifdef PLATFORM_WINDOWS
3047 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3049 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3050 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3055 /* absolute path or cwd-relative path specified for session name: infer session folder
3056 from what was given.
3059 session_path = Glib::path_get_dirname (session_name);
3060 session_name = Glib::path_get_basename (session_name);
3064 session_path = session_dialog.session_folder();
3066 char illegal = Session::session_name_is_legal (session_name);
3069 MessageDialog msg (session_dialog,
3070 string_compose (_("To ensure compatibility with various systems\n"
3071 "session names may not contain a '%1' character"),
3074 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3079 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3082 if (likely_new && !nsm) {
3084 std::string existing = Glib::build_filename (session_path, session_name);
3086 if (!ask_about_loading_existing_session (existing)) {
3087 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3092 _session_is_new = false;
3097 pop_back_splash (session_dialog);
3098 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3100 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3104 char illegal = Session::session_name_is_legal(session_name);
3107 pop_back_splash (session_dialog);
3108 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3109 "session names may not contain a '%1' character"), illegal));
3111 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3115 _session_is_new = true;
3118 if (likely_new && template_name.empty()) {
3120 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3124 ret = load_session (session_path, session_name, template_name);
3127 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3131 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3132 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3136 /* clear this to avoid endless attempts to load the
3140 ARDOUR_COMMAND_LINE::session_name = "";
3144 _session_dialog = NULL;
3150 ARDOUR_UI::close_session()
3152 if (!check_audioengine(*editor)) {
3156 if (unload_session (true)) {
3160 ARDOUR_COMMAND_LINE::session_name = "";
3162 if (get_session_parameters (true, false)) {
3166 goto_editor_window ();
3169 /** @param snap_name Snapshot name (without .ardour suffix).
3170 * @return -2 if the load failed because we are not connected to the AudioEngine.
3173 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3175 Session *new_session;
3180 unload_status = unload_session ();
3182 if (unload_status < 0) {
3184 } else if (unload_status > 0) {
3190 session_loaded = false;
3192 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3195 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3198 /* this one is special */
3200 catch (AudioEngine::PortRegistrationFailure& err) {
3202 MessageDialog msg (err.what(),
3205 Gtk::BUTTONS_CLOSE);
3207 msg.set_title (_("Port Registration Error"));
3208 msg.set_secondary_text (_("Click the Close button to try again."));
3209 msg.set_position (Gtk::WIN_POS_CENTER);
3210 pop_back_splash (msg);
3213 int response = msg.run ();
3218 case RESPONSE_CANCEL:
3225 catch (SessionException e) {
3226 MessageDialog msg (string_compose(
3227 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3228 path, snap_name, e.what()),
3233 msg.set_title (_("Loading Error"));
3234 msg.set_position (Gtk::WIN_POS_CENTER);
3235 pop_back_splash (msg);
3247 MessageDialog msg (string_compose(
3248 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3254 msg.set_title (_("Loading Error"));
3255 msg.set_position (Gtk::WIN_POS_CENTER);
3256 pop_back_splash (msg);
3268 list<string> const u = new_session->unknown_processors ();
3270 MissingPluginDialog d (_session, u);
3275 if (!new_session->writable()) {
3276 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3281 msg.set_title (_("Read-only Session"));
3282 msg.set_position (Gtk::WIN_POS_CENTER);
3283 pop_back_splash (msg);
3290 /* Now the session been created, add the transport controls */
3291 new_session->add_controllable(roll_controllable);
3292 new_session->add_controllable(stop_controllable);
3293 new_session->add_controllable(goto_start_controllable);
3294 new_session->add_controllable(goto_end_controllable);
3295 new_session->add_controllable(auto_loop_controllable);
3296 new_session->add_controllable(play_selection_controllable);
3297 new_session->add_controllable(rec_controllable);
3299 set_session (new_session);
3301 session_loaded = true;
3303 goto_editor_window ();
3306 _session->set_clean ();
3309 #ifdef WINDOWS_VST_SUPPORT
3310 fst_stop_threading();
3314 Timers::TimerSuspender t;
3318 #ifdef WINDOWS_VST_SUPPORT
3319 fst_start_threading();
3328 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3330 Session *new_session;
3333 session_loaded = false;
3334 x = unload_session ();
3342 _session_is_new = true;
3345 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3348 catch (SessionException e) {
3350 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3351 msg.set_title (_("Loading Error"));
3352 msg.set_position (Gtk::WIN_POS_CENTER);
3353 pop_back_splash (msg);
3359 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3360 msg.set_title (_("Loading Error"));
3361 msg.set_position (Gtk::WIN_POS_CENTER);
3362 pop_back_splash (msg);
3367 /* Give the new session the default GUI state, if such things exist */
3370 n = Config->instant_xml (X_("Editor"));
3372 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3373 new_session->add_instant_xml (*n, false);
3375 n = Config->instant_xml (X_("Mixer"));
3377 new_session->add_instant_xml (*n, false);
3380 /* Put the playhead at 0 and scroll fully left */
3381 n = new_session->instant_xml (X_("Editor"));
3383 n->add_property (X_("playhead"), X_("0"));
3384 n->add_property (X_("left-frame"), X_("0"));
3387 set_session (new_session);
3389 session_loaded = true;
3391 new_session->save_state(new_session->name());
3397 ARDOUR_UI::launch_chat ()
3399 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3401 dialog.set_title (_("About the Chat"));
3402 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."));
3404 switch (dialog.run()) {
3407 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3408 #elif defined PLATFORM_WINDOWS
3409 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3411 open_uri("http://webchat.freenode.net/?channels=ardour");
3420 ARDOUR_UI::launch_manual ()
3422 PBD::open_uri (Config->get_tutorial_manual_url());
3426 ARDOUR_UI::launch_reference ()
3428 PBD::open_uri (Config->get_reference_manual_url());
3432 ARDOUR_UI::launch_tracker ()
3434 PBD::open_uri ("http://tracker.ardour.org");
3438 ARDOUR_UI::launch_subscribe ()
3440 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3444 ARDOUR_UI::launch_cheat_sheet ()
3447 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3449 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3454 ARDOUR_UI::launch_website ()
3456 PBD::open_uri ("http://ardour.org");
3460 ARDOUR_UI::launch_website_dev ()
3462 PBD::open_uri ("http://ardour.org/development.html");
3466 ARDOUR_UI::launch_forums ()
3468 PBD::open_uri ("https://community.ardour.org/forums");
3472 ARDOUR_UI::launch_howto_report ()
3474 PBD::open_uri ("http://ardour.org/reporting_bugs");
3478 ARDOUR_UI::loading_message (const std::string& msg)
3480 if (ARDOUR_COMMAND_LINE::no_splash) {
3488 splash->message (msg);
3492 ARDOUR_UI::show_splash ()
3496 splash = new Splash;
3506 ARDOUR_UI::hide_splash ()
3513 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3517 removed = rep.paths.size();
3520 MessageDialog msgd (*editor,
3521 _("No files were ready for clean-up"),
3525 msgd.set_title (_("Clean-up"));
3526 msgd.set_secondary_text (_("If this seems suprising, \n\
3527 check for any existing snapshots.\n\
3528 These may still include regions that\n\
3529 require some unused files to continue to exist."));
3535 ArdourDialog results (_("Clean-up"), true, false);
3537 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3538 CleanupResultsModelColumns() {
3542 Gtk::TreeModelColumn<std::string> visible_name;
3543 Gtk::TreeModelColumn<std::string> fullpath;
3547 CleanupResultsModelColumns results_columns;
3548 Glib::RefPtr<Gtk::ListStore> results_model;
3549 Gtk::TreeView results_display;
3551 results_model = ListStore::create (results_columns);
3552 results_display.set_model (results_model);
3553 results_display.append_column (list_title, results_columns.visible_name);
3555 results_display.set_name ("CleanupResultsList");
3556 results_display.set_headers_visible (true);
3557 results_display.set_headers_clickable (false);
3558 results_display.set_reorderable (false);
3560 Gtk::ScrolledWindow list_scroller;
3563 Gtk::HBox dhbox; // the hbox for the image and text
3564 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3565 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3567 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3569 const string dead_directory = _session->session_directory().dead_path();
3572 %1 - number of files removed
3573 %2 - location of "dead"
3574 %3 - size of files affected
3575 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3578 const char* bprefix;
3579 double space_adjusted = 0;
3581 if (rep.space < 1000) {
3583 space_adjusted = rep.space;
3584 } else if (rep.space < 1000000) {
3585 bprefix = _("kilo");
3586 space_adjusted = floorf((float)rep.space / 1000.0);
3587 } else if (rep.space < 1000000 * 1000) {
3588 bprefix = _("mega");
3589 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3591 bprefix = _("giga");
3592 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3596 txt.set_markup (string_compose (P_("\
3597 The following file was deleted from %2,\n\
3598 releasing %3 %4bytes of disk space", "\
3599 The following %1 files were deleted from %2,\n\
3600 releasing %3 %4bytes of disk space", removed),
3601 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3603 txt.set_markup (string_compose (P_("\
3604 The following file was not in use and \n\
3605 has been moved to: %2\n\n\
3606 After a restart of %5\n\n\
3607 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3608 will release an additional %3 %4bytes of disk space.\n", "\
3609 The following %1 files were not in use and \n\
3610 have been moved to: %2\n\n\
3611 After a restart of %5\n\n\
3612 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3613 will release an additional %3 %4bytes of disk space.\n", removed),
3614 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3617 dhbox.pack_start (*dimage, true, false, 5);
3618 dhbox.pack_start (txt, true, false, 5);
3620 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3621 TreeModel::Row row = *(results_model->append());
3622 row[results_columns.visible_name] = *i;
3623 row[results_columns.fullpath] = *i;
3626 list_scroller.add (results_display);
3627 list_scroller.set_size_request (-1, 150);
3628 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3630 dvbox.pack_start (dhbox, true, false, 5);
3631 dvbox.pack_start (list_scroller, true, false, 5);
3632 ddhbox.pack_start (dvbox, true, false, 5);
3634 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3635 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3636 results.set_default_response (RESPONSE_CLOSE);
3637 results.set_position (Gtk::WIN_POS_MOUSE);
3639 results_display.show();
3640 list_scroller.show();
3647 //results.get_vbox()->show();
3648 results.set_resizable (false);
3655 ARDOUR_UI::cleanup ()
3657 if (_session == 0) {
3658 /* shouldn't happen: menu item is insensitive */
3663 MessageDialog checker (_("Are you sure you want to clean-up?"),
3665 Gtk::MESSAGE_QUESTION,
3668 checker.set_title (_("Clean-up"));
3670 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3671 ALL undo/redo information will be lost if you clean-up.\n\
3672 Clean-up will move all unused files to a \"dead\" location."));
3674 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3675 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3676 checker.set_default_response (RESPONSE_CANCEL);
3678 checker.set_name (_("CleanupDialog"));
3679 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3680 checker.set_position (Gtk::WIN_POS_MOUSE);
3682 switch (checker.run()) {
3683 case RESPONSE_ACCEPT:
3689 ARDOUR::CleanupReport rep;
3691 editor->prepare_for_cleanup ();
3693 /* do not allow flush until a session is reloaded */
3695 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3697 act->set_sensitive (false);
3700 if (_session->cleanup_sources (rep)) {
3701 editor->finish_cleanup ();
3705 editor->finish_cleanup ();
3708 display_cleanup_results (rep, _("Cleaned Files"), false);
3712 ARDOUR_UI::flush_trash ()
3714 if (_session == 0) {
3715 /* shouldn't happen: menu item is insensitive */
3719 ARDOUR::CleanupReport rep;
3721 if (_session->cleanup_trash_sources (rep)) {
3725 display_cleanup_results (rep, _("deleted file"), true);
3729 ARDOUR_UI::cleanup_peakfiles ()
3731 if (_session == 0) {
3732 /* shouldn't happen: menu item is insensitive */
3736 if (! _session->can_cleanup_peakfiles ()) {
3740 // get all region-views in this session
3742 TrackViewList empty;
3744 editor->get_regions_after(rs, (framepos_t) 0, empty);
3745 std::list<RegionView*> views = rs.by_layer();
3747 // remove displayed audio-region-views waveforms
3748 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3749 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3750 if (!arv) { continue ; }
3751 arv->delete_waves();
3754 // cleanup peak files:
3755 // - stop pending peakfile threads
3756 // - close peakfiles if any
3757 // - remove peak dir in session
3758 // - setup peakfiles (background thread)
3759 _session->cleanup_peakfiles ();
3761 // re-add waves to ARV
3762 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3763 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3764 if (!arv) { continue ; }
3765 arv->create_waves();
3770 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3772 uint32_t order_hint = UINT32_MAX;
3774 if (editor->get_selection().tracks.empty()) {
3779 we want the new routes to have their order keys set starting from
3780 the highest order key in the selection + 1 (if available).
3783 if (place == AddRouteDialog::AfterSelection) {
3784 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3786 order_hint = rtav->route()->order_key();
3789 } else if (place == AddRouteDialog::BeforeSelection) {
3790 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3792 order_hint = rtav->route()->order_key();
3794 } else if (place == AddRouteDialog::First) {
3797 /* leave order_hint at UINT32_MAX */
3800 if (order_hint == UINT32_MAX) {
3801 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3802 * not setting an order hint will place new routes last.
3807 _session->set_order_hint (order_hint);
3809 /* create a gap in the existing route order keys to accomodate new routes.*/
3810 boost::shared_ptr <RouteList> rd = _session->get_routes();
3811 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3812 boost::shared_ptr<Route> rt (*ri);
3814 if (rt->is_monitor()) {
3818 if (rt->order_key () >= order_hint) {
3819 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3825 ARDOUR_UI::start_duplicate_routes ()
3827 if (!duplicate_routes_dialog) {
3828 duplicate_routes_dialog = new DuplicateRouteDialog;
3831 if (duplicate_routes_dialog->restart (_session)) {
3835 duplicate_routes_dialog->present ();
3839 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3847 if (add_route_dialog->is_visible()) {
3848 /* we're already doing this */
3852 ResponseType r = (ResponseType) add_route_dialog->run ();
3854 add_route_dialog->hide();
3857 case RESPONSE_ACCEPT:
3864 if ((count = add_route_dialog->count()) <= 0) {
3868 setup_order_hint(add_route_dialog->insert_at());
3870 string template_path = add_route_dialog->track_template();
3871 DisplaySuspender ds;
3873 if (!template_path.empty()) {
3874 if (add_route_dialog->name_template_is_default()) {
3875 _session->new_route_from_template (count, template_path, string());
3877 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3882 ChanCount input_chan= add_route_dialog->channels ();
3883 ChanCount output_chan;
3884 string name_template = add_route_dialog->name_template ();
3885 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3886 RouteGroup* route_group = add_route_dialog->route_group ();
3887 AutoConnectOption oac = Config->get_output_auto_connect();
3889 if (oac & AutoConnectMaster) {
3890 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3891 output_chan.set (DataType::MIDI, 0);
3893 output_chan = input_chan;
3896 /* XXX do something with name template */
3898 switch (add_route_dialog->type_wanted()) {
3899 case AddRouteDialog::AudioTrack:
3900 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3902 case AddRouteDialog::MidiTrack:
3903 session_add_midi_track (route_group, count, name_template, instrument);
3905 case AddRouteDialog::MixedTrack:
3906 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3908 case AddRouteDialog::AudioBus:
3909 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3915 ARDOUR_UI::stop_video_server (bool ask_confirm)
3917 if (!video_server_process && ask_confirm) {
3918 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3920 if (video_server_process) {
3922 ArdourDialog confirm (_("Stop Video-Server"), true);
3923 Label m (_("Do you really want to stop the Video Server?"));
3924 confirm.get_vbox()->pack_start (m, true, true);
3925 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3926 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3927 confirm.show_all ();
3928 if (confirm.run() == RESPONSE_CANCEL) {
3932 delete video_server_process;
3933 video_server_process =0;
3938 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3940 ARDOUR_UI::start_video_server( float_window, true);
3944 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3950 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3951 if (video_server_process) {
3952 popup_error(_("The Video Server is already started."));
3954 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3960 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3962 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3964 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3966 video_server_dialog->set_transient_for (*float_window);
3969 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3970 video_server_dialog->hide();
3972 ResponseType r = (ResponseType) video_server_dialog->run ();
3973 video_server_dialog->hide();
3974 if (r != RESPONSE_ACCEPT) { return false; }
3975 if (video_server_dialog->show_again()) {
3976 Config->set_show_video_server_dialog(false);
3980 std::string icsd_exec = video_server_dialog->get_exec_path();
3981 std::string icsd_docroot = video_server_dialog->get_docroot();
3982 if (icsd_docroot.empty()) {
3983 #ifndef PLATFORM_WINDOWS
3984 icsd_docroot = X_("/");
3986 icsd_docroot = X_("C:\\");
3991 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
3992 warning << _("Specified docroot is not an existing directory.") << endmsg;
3995 #ifndef PLATFORM_WINDOWS
3996 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
3997 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
3998 warning << _("Given Video Server is not an executable file.") << endmsg;
4002 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4003 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4004 warning << _("Given Video Server is not an executable file.") << endmsg;
4010 argp=(char**) calloc(9,sizeof(char*));
4011 argp[0] = strdup(icsd_exec.c_str());
4012 argp[1] = strdup("-P");
4013 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4014 argp[3] = strdup("-p");
4015 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4016 argp[5] = strdup("-C");
4017 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4018 argp[7] = strdup(icsd_docroot.c_str());
4020 stop_video_server();
4022 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4023 Config->set_video_advanced_setup(false);
4025 std::ostringstream osstream;
4026 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4027 Config->set_video_server_url(osstream.str());
4028 Config->set_video_server_docroot(icsd_docroot);
4029 Config->set_video_advanced_setup(true);
4032 if (video_server_process) {
4033 delete video_server_process;
4036 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4037 if (video_server_process->start()) {
4038 warning << _("Cannot launch the video-server") << endmsg;
4041 int timeout = 120; // 6 sec
4042 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4043 Glib::usleep (50000);
4045 if (--timeout <= 0 || !video_server_process->is_running()) break;
4048 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4050 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4051 delete video_server_process;
4052 video_server_process = 0;
4060 ARDOUR_UI::add_video (Gtk::Window* float_window)
4066 if (!start_video_server(float_window, false)) {
4067 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4072 add_video_dialog->set_transient_for (*float_window);
4075 if (add_video_dialog->is_visible()) {
4076 /* we're already doing this */
4080 ResponseType r = (ResponseType) add_video_dialog->run ();
4081 add_video_dialog->hide();
4082 if (r != RESPONSE_ACCEPT) { return; }
4084 bool local_file, orig_local_file;
4085 std::string path = add_video_dialog->file_name(local_file);
4087 std::string orig_path = path;
4088 orig_local_file = local_file;
4090 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4092 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4093 warning << string_compose(_("could not open %1"), path) << endmsg;
4096 if (!local_file && path.length() == 0) {
4097 warning << _("no video-file selected") << endmsg;
4101 std::string audio_from_video;
4102 bool detect_ltc = false;
4104 switch (add_video_dialog->import_option()) {
4105 case VTL_IMPORT_TRANSCODE:
4107 TranscodeVideoDialog *transcode_video_dialog;
4108 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4109 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4110 transcode_video_dialog->hide();
4111 if (r != RESPONSE_ACCEPT) {
4112 delete transcode_video_dialog;
4116 audio_from_video = transcode_video_dialog->get_audiofile();
4118 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4121 else if (!audio_from_video.empty()) {
4122 editor->embed_audio_from_video(
4124 video_timeline->get_offset(),
4125 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4128 switch (transcode_video_dialog->import_option()) {
4129 case VTL_IMPORT_TRANSCODED:
4130 path = transcode_video_dialog->get_filename();
4133 case VTL_IMPORT_REFERENCE:
4136 delete transcode_video_dialog;
4139 delete transcode_video_dialog;
4143 case VTL_IMPORT_NONE:
4147 /* strip _session->session_directory().video_path() from video file if possible */
4148 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4149 path=path.substr(_session->session_directory().video_path().size());
4150 if (path.at(0) == G_DIR_SEPARATOR) {
4151 path=path.substr(1);
4155 video_timeline->set_update_session_fps(auto_set_session_fps);
4157 if (video_timeline->video_file_info(path, local_file)) {
4158 XMLNode* node = new XMLNode(X_("Videotimeline"));
4159 node->add_property (X_("Filename"), path);
4160 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4161 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4162 if (orig_local_file) {
4163 node->add_property (X_("OriginalVideoFile"), orig_path);
4165 node->remove_property (X_("OriginalVideoFile"));
4167 _session->add_extra_xml (*node);
4168 _session->set_dirty ();
4170 if (!audio_from_video.empty() && detect_ltc) {
4171 std::vector<LTCFileReader::LTCMap> ltc_seq;
4174 /* TODO ask user about TV standard (LTC alignment if any) */
4175 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4176 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4178 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4180 /* TODO seek near end of file, and read LTC until end.
4181 * if it fails to find any LTC frames, scan complete file
4183 * calculate drift of LTC compared to video-duration,
4184 * ask user for reference (timecode from start/mid/end)
4187 // LTCFileReader will have written error messages
4190 ::g_unlink(audio_from_video.c_str());
4192 if (ltc_seq.size() == 0) {
4193 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4195 /* the very first TC in the file is somteimes not aligned properly */
4196 int i = ltc_seq.size() -1;
4197 ARDOUR::frameoffset_t video_start_offset =
4198 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4199 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4200 video_timeline->set_offset(video_start_offset);
4204 _session->maybe_update_session_range(
4205 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4206 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4209 if (add_video_dialog->launch_xjadeo() && local_file) {
4210 editor->set_xjadeo_sensitive(true);
4211 editor->toggle_xjadeo_proc(1);
4213 editor->toggle_xjadeo_proc(0);
4215 editor->toggle_ruler_video(true);
4220 ARDOUR_UI::remove_video ()
4222 video_timeline->close_session();
4223 editor->toggle_ruler_video(false);
4226 video_timeline->set_offset_locked(false);
4227 video_timeline->set_offset(0);
4229 /* delete session state */
4230 XMLNode* node = new XMLNode(X_("Videotimeline"));
4231 _session->add_extra_xml(*node);
4232 node = new XMLNode(X_("Videomonitor"));
4233 _session->add_extra_xml(*node);
4234 node = new XMLNode(X_("Videoexport"));
4235 _session->add_extra_xml(*node);
4236 stop_video_server();
4240 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4242 if (localcacheonly) {
4243 video_timeline->vmon_update();
4245 video_timeline->flush_cache();
4247 editor->queue_visual_videotimeline_update();
4251 ARDOUR_UI::export_video (bool range)
4253 if (ARDOUR::Config->get_show_video_export_info()) {
4254 ExportVideoInfobox infobox (_session);
4255 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4256 if (infobox.show_again()) {
4257 ARDOUR::Config->set_show_video_export_info(false);
4260 case GTK_RESPONSE_YES:
4261 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4267 export_video_dialog->set_session (_session);
4268 export_video_dialog->apply_state(editor->get_selection().time, range);
4269 export_video_dialog->run ();
4270 export_video_dialog->hide ();
4274 ARDOUR_UI::mixer_settings () const
4279 node = _session->instant_xml(X_("Mixer"));
4281 node = Config->instant_xml(X_("Mixer"));
4285 node = new XMLNode (X_("Mixer"));
4292 ARDOUR_UI::editor_settings () const
4297 node = _session->instant_xml(X_("Editor"));
4299 node = Config->instant_xml(X_("Editor"));
4303 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4304 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4309 node = new XMLNode (X_("Editor"));
4316 ARDOUR_UI::keyboard_settings () const
4320 node = Config->extra_xml(X_("Keyboard"));
4323 node = new XMLNode (X_("Keyboard"));
4330 ARDOUR_UI::create_xrun_marker (framepos_t where)
4333 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4334 _session->locations()->add (location);
4339 ARDOUR_UI::halt_on_xrun_message ()
4341 cerr << "HALT on xrun\n";
4342 MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up."));
4347 ARDOUR_UI::xrun_handler (framepos_t where)
4353 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4355 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4356 create_xrun_marker(where);
4359 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4360 halt_on_xrun_message ();
4365 ARDOUR_UI::disk_overrun_handler ()
4367 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4369 if (!have_disk_speed_dialog_displayed) {
4370 have_disk_speed_dialog_displayed = true;
4371 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
4372 The disk system on your computer\n\
4373 was not able to keep up with %1.\n\
4375 Specifically, it failed to write data to disk\n\
4376 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4377 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4383 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4384 static MessageDialog *scan_dlg = NULL;
4385 static ProgressBar *scan_pbar = NULL;
4386 static HBox *scan_tbox = NULL;
4387 static Gtk::Button *scan_timeout_button;
4390 ARDOUR_UI::cancel_plugin_scan ()
4392 PluginManager::instance().cancel_plugin_scan();
4396 ARDOUR_UI::cancel_plugin_timeout ()
4398 PluginManager::instance().cancel_plugin_timeout();
4399 scan_timeout_button->set_sensitive (false);
4403 ARDOUR_UI::plugin_scan_timeout (int timeout)
4405 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4409 scan_pbar->set_sensitive (false);
4410 scan_timeout_button->set_sensitive (true);
4411 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4414 scan_pbar->set_sensitive (false);
4415 scan_timeout_button->set_sensitive (false);
4421 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4423 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4427 const bool cancelled = PluginManager::instance().cancelled();
4428 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4429 if (cancelled && scan_dlg->is_mapped()) {
4434 if (cancelled || !can_cancel) {
4439 static Gtk::Button *cancel_button;
4441 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4442 VBox* vbox = scan_dlg->get_vbox();
4443 vbox->set_size_request(400,-1);
4444 scan_dlg->set_title (_("Scanning for plugins"));
4446 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4447 cancel_button->set_name ("EditorGTKButton");
4448 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4449 cancel_button->show();
4451 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4453 scan_tbox = manage( new HBox() );
4455 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4456 scan_timeout_button->set_name ("EditorGTKButton");
4457 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4458 scan_timeout_button->show();
4460 scan_pbar = manage(new ProgressBar());
4461 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4462 scan_pbar->set_text(_("Scan Timeout"));
4465 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4466 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4468 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4471 assert(scan_dlg && scan_tbox && cancel_button);
4473 if (type == X_("closeme")) {
4477 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4480 if (!can_cancel || !cancelled) {
4481 scan_timeout_button->set_sensitive(false);
4483 cancel_button->set_sensitive(can_cancel && !cancelled);
4489 ARDOUR_UI::gui_idle_handler ()
4492 /* due to idle calls, gtk_events_pending() may always return true */
4493 while (gtk_events_pending() && --timeout) {
4494 gtk_main_iteration ();
4499 ARDOUR_UI::disk_underrun_handler ()
4501 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4503 if (!have_disk_speed_dialog_displayed) {
4504 have_disk_speed_dialog_displayed = true;
4505 MessageDialog* msg = new MessageDialog (
4506 *editor, string_compose (_("The disk system on your computer\n\
4507 was not able to keep up with %1.\n\
4509 Specifically, it failed to read data from disk\n\
4510 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4511 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4517 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4519 have_disk_speed_dialog_displayed = false;
4524 ARDOUR_UI::session_dialog (std::string msg)
4526 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4531 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4533 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4542 ARDOUR_UI::pending_state_dialog ()
4544 HBox* hbox = manage (new HBox());
4545 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4546 ArdourDialog dialog (_("Crash Recovery"), true);
4547 Label message (string_compose (_("\
4548 This session appears to have been in the\n\
4549 middle of recording when %1 or\n\
4550 the computer was shutdown.\n\
4552 %1 can recover any captured audio for\n\
4553 you, or it can ignore it. Please decide\n\
4554 what you would like to do.\n"), PROGRAM_NAME));
4555 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4556 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4557 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4558 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4559 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4560 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4561 dialog.set_default_response (RESPONSE_ACCEPT);
4562 dialog.set_position (WIN_POS_CENTER);
4567 switch (dialog.run ()) {
4568 case RESPONSE_ACCEPT:
4576 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4578 HBox* hbox = new HBox();
4579 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4580 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4581 Label message (string_compose (_("\
4582 This session was created with a sample rate of %1 Hz, but\n\
4583 %2 is currently running at %3 Hz. If you load this session,\n\
4584 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4586 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4587 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4588 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4589 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4590 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4591 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4592 dialog.set_default_response (RESPONSE_ACCEPT);
4593 dialog.set_position (WIN_POS_CENTER);
4598 switch (dialog.run()) {
4599 case RESPONSE_ACCEPT:
4609 ARDOUR_UI::use_config ()
4611 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4613 set_transport_controllable_state (*node);
4618 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4620 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4621 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4623 primary_clock->set (pos);
4626 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4627 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4629 secondary_clock->set (pos);
4632 if (big_clock_window) {
4633 big_clock->set (pos);
4635 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4639 ARDOUR_UI::step_edit_status_change (bool yn)
4641 // XXX should really store pre-step edit status of things
4642 // we make insensitive
4645 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4646 rec_button.set_sensitive (false);
4648 rec_button.unset_active_state ();;
4649 rec_button.set_sensitive (true);
4654 ARDOUR_UI::record_state_changed ()
4656 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4658 if (!_session || !big_clock_window) {
4659 /* why bother - the clock isn't visible */
4663 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4664 big_clock->set_active (true);
4666 big_clock->set_active (false);
4671 ARDOUR_UI::first_idle ()
4674 _session->allow_auto_play (true);
4678 editor->first_idle();
4681 Keyboard::set_can_save_keybindings (true);
4686 ARDOUR_UI::store_clock_modes ()
4688 XMLNode* node = new XMLNode(X_("ClockModes"));
4690 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4691 XMLNode* child = new XMLNode (X_("Clock"));
4693 child->add_property (X_("name"), (*x)->name());
4694 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4695 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4697 node->add_child_nocopy (*child);
4700 _session->add_extra_xml (*node);
4701 _session->set_dirty ();
4704 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4705 : Controllable (name), ui (u), type(tp)
4711 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4714 /* do nothing: these are radio-style actions */
4718 const char *action = 0;
4722 action = X_("Roll");
4725 action = X_("Stop");
4728 action = X_("GotoStart");
4731 action = X_("GotoEnd");
4734 action = X_("Loop");
4737 action = X_("PlaySelection");
4740 action = X_("Record");
4750 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4758 ARDOUR_UI::TransportControllable::get_value (void) const
4785 ARDOUR_UI::setup_profile ()
4787 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4788 Profile->set_small_screen ();
4791 if (g_getenv ("ARDOUR_SAE")) {
4792 Profile->set_sae ();
4793 Profile->set_single_package ();
4796 if (g_getenv ("TRX")) {
4797 Profile->set_trx ();
4800 if (g_getenv ("MIXBUS")) {
4801 Profile->set_mixbus ();
4806 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4808 MissingFileDialog dialog (s, str, type);
4813 int result = dialog.run ();
4820 return 1; // quit entire session load
4823 result = dialog.get_action ();
4829 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4831 AmbiguousFileDialog dialog (file, hits);
4838 return dialog.get_which ();
4841 /** Allocate our thread-local buffers */
4843 ARDOUR_UI::get_process_buffers ()
4845 _process_thread->get_buffers ();
4848 /** Drop our thread-local buffers */
4850 ARDOUR_UI::drop_process_buffers ()
4852 _process_thread->drop_buffers ();
4856 ARDOUR_UI::feedback_detected ()
4858 _feedback_exists = true;
4862 ARDOUR_UI::successful_graph_sort ()
4864 _feedback_exists = false;
4868 ARDOUR_UI::midi_panic ()
4871 _session->midi_panic();
4876 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4878 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4879 const char* end_big = "</span>";
4880 const char* start_mono = "<tt>";
4881 const char* end_mono = "</tt>";
4883 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4884 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4885 "From now on, use the -2000 version with older versions of %3"),
4886 xml_path, backup_path, PROGRAM_NAME,
4888 start_mono, end_mono), true);
4895 ARDOUR_UI::reset_peak_display ()
4897 if (!_session || !_session->master_out() || !editor_meter) return;
4898 editor_meter->clear_meters();
4899 editor_meter_max_peak = -INFINITY;
4900 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4904 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4906 if (!_session || !_session->master_out()) return;
4907 if (group == _session->master_out()->route_group()) {
4908 reset_peak_display ();
4913 ARDOUR_UI::reset_route_peak_display (Route* route)
4915 if (!_session || !_session->master_out()) return;
4916 if (_session->master_out().get() == route) {
4917 reset_peak_display ();
4922 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4924 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4925 audio_midi_setup->set_position (WIN_POS_CENTER);
4930 response = audio_midi_setup->run();
4932 case Gtk::RESPONSE_OK:
4933 if (!AudioEngine::instance()->running()) {
4947 ARDOUR_UI::transport_numpad_timeout ()
4949 _numpad_locate_happening = false;
4950 if (_numpad_timeout_connection.connected() )
4951 _numpad_timeout_connection.disconnect();
4956 ARDOUR_UI::transport_numpad_decimal ()
4958 _numpad_timeout_connection.disconnect();
4960 if (_numpad_locate_happening) {
4961 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4962 _numpad_locate_happening = false;
4964 _pending_locate_num = 0;
4965 _numpad_locate_happening = true;
4966 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
4971 ARDOUR_UI::transport_numpad_event (int num)
4973 if ( _numpad_locate_happening ) {
4974 _pending_locate_num = _pending_locate_num*10 + num;
4977 case 0: toggle_roll(false, false); break;
4978 case 1: transport_rewind(1); break;
4979 case 2: transport_forward(1); break;
4980 case 3: transport_record(true); break;
4981 case 4: toggle_session_auto_loop(); break;
4982 case 5: transport_record(false); toggle_session_auto_loop(); break;
4983 case 6: toggle_punch(); break;
4984 case 7: toggle_click(); break;
4985 case 8: toggle_auto_return(); break;
4986 case 9: toggle_follow_edits(); break;
4992 ARDOUR_UI::set_flat_buttons ()
4994 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
4998 ARDOUR_UI::audioengine_became_silent ()
5000 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5002 Gtk::MESSAGE_WARNING,
5006 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5008 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5009 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5010 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5011 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5012 Gtk::HBox pay_button_box;
5013 Gtk::HBox subscribe_button_box;
5015 pay_button_box.pack_start (pay_button, true, false);
5016 subscribe_button_box.pack_start (subscribe_button, true, false);
5018 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 */
5020 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5021 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5023 msg.get_vbox()->pack_start (pay_label);
5024 msg.get_vbox()->pack_start (pay_button_box);
5025 msg.get_vbox()->pack_start (subscribe_label);
5026 msg.get_vbox()->pack_start (subscribe_button_box);
5028 msg.get_vbox()->show_all ();
5030 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5031 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5032 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5037 case Gtk::RESPONSE_YES:
5038 AudioEngine::instance()->reset_silence_countdown ();
5041 case Gtk::RESPONSE_NO:
5043 save_state_canfail ("");
5047 case Gtk::RESPONSE_CANCEL:
5049 /* don't reset, save session and exit */
5055 ARDOUR_UI::hide_application ()
5057 Application::instance ()-> hide ();
5061 ARDOUR_UI::cancel_solo ()
5064 if (_session->soloing()) {
5065 _session->set_solo (_session->get_routes(), false);
5066 } else if (_session->listening()) {
5067 _session->set_listen (_session->get_routes(), false);
5070 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
5075 ARDOUR_UI::grab_focus_after_dialog ()
5077 if (mixer && mixer->fully_visible()) {
5078 mixer->grab_focus ();
5079 } else if (editor) {
5080 editor->grab_focus ();