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, 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 /* we don't like certain modifiers */
395 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
397 UIConfiguration::instance().reset_dpi ();
399 TimeAxisViewItem::set_constant_heights ();
401 /* Set this up so that our window proxies can register actions */
403 ActionManager::init ();
405 /* The following must happen after ARDOUR::init() so that Config is set up */
407 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
410 key_editor.set_state (*ui_xml);
411 rc_option_editor.set_state (*ui_xml);
412 session_option_editor.set_state (*ui_xml);
413 speaker_config_window.set_state (*ui_xml);
414 about.set_state (*ui_xml);
415 add_route_dialog.set_state (*ui_xml);
416 add_video_dialog.set_state (*ui_xml);
417 route_params.set_state (*ui_xml);
418 bundle_manager.set_state (*ui_xml);
419 location_ui.set_state (*ui_xml);
420 big_clock_window.set_state (*ui_xml);
421 audio_port_matrix.set_state (*ui_xml);
422 midi_port_matrix.set_state (*ui_xml);
423 export_video_dialog.set_state (*ui_xml);
426 WM::Manager::instance().register_window (&key_editor);
427 WM::Manager::instance().register_window (&rc_option_editor);
428 WM::Manager::instance().register_window (&session_option_editor);
429 WM::Manager::instance().register_window (&speaker_config_window);
430 WM::Manager::instance().register_window (&about);
431 WM::Manager::instance().register_window (&add_route_dialog);
432 WM::Manager::instance().register_window (&add_video_dialog);
433 WM::Manager::instance().register_window (&route_params);
434 WM::Manager::instance().register_window (&audio_midi_setup);
435 WM::Manager::instance().register_window (&export_video_dialog);
436 WM::Manager::instance().register_window (&bundle_manager);
437 WM::Manager::instance().register_window (&location_ui);
438 WM::Manager::instance().register_window (&big_clock_window);
439 WM::Manager::instance().register_window (&audio_port_matrix);
440 WM::Manager::instance().register_window (&midi_port_matrix);
442 /* Trigger setting up the color scheme and loading the GTK RC file */
444 UIConfiguration::instance().load_rc_file (false);
446 _process_thread = new ProcessThread ();
447 _process_thread->init ();
449 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
454 GlobalPortMatrixWindow*
455 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
460 return new GlobalPortMatrixWindow (_session, type);
464 ARDOUR_UI::attach_to_engine ()
466 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
467 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
471 ARDOUR_UI::engine_stopped ()
473 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
474 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
475 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
476 update_sample_rate (0);
481 ARDOUR_UI::engine_running ()
483 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
484 if (first_time_engine_run) {
486 first_time_engine_run = false;
490 _session->reset_xrun_count ();
492 update_disk_space ();
494 update_xrun_count ();
495 update_sample_rate (AudioEngine::instance()->sample_rate());
496 update_timecode_format ();
497 update_peak_thread_work ();
498 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
499 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
503 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
505 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
506 /* we can't rely on the original string continuing to exist when we are called
507 again in the GUI thread, so make a copy and note that we need to
510 char *copy = strdup (reason);
511 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
515 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
516 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
518 update_sample_rate (0);
522 /* if the reason is a non-empty string, it means that the backend was shutdown
523 rather than just Ardour.
526 if (strlen (reason)) {
527 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
529 msgstr = string_compose (_("\
530 The audio backend has either been shutdown or it\n\
531 disconnected %1 because %1\n\
532 was not fast enough. Try to restart\n\
533 the audio backend and save the session."), PROGRAM_NAME);
536 MessageDialog msg (*editor, msgstr);
537 pop_back_splash (msg);
541 free (const_cast<char*> (reason));
546 ARDOUR_UI::post_engine ()
548 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
550 #ifdef AUDIOUNIT_SUPPORT
552 if (AUPluginInfo::au_get_crashlog(au_msg)) {
553 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
554 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
555 info << au_msg << endmsg;
559 ARDOUR::init_post_engine ();
561 /* connect to important signals */
563 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
564 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
565 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
566 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
567 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
569 if (setup_windows ()) {
570 throw failed_constructor ();
573 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
574 XMLNode* n = Config->extra_xml (X_("UI"));
576 _status_bar_visibility.set_state (*n);
579 check_memory_locking();
581 /* this is the first point at which all the keybindings are available */
583 if (ARDOUR_COMMAND_LINE::show_key_actions) {
584 vector<string> names;
585 vector<string> paths;
586 vector<string> tooltips;
588 vector<AccelKey> bindings;
590 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
592 vector<string>::iterator n;
593 vector<string>::iterator k;
594 vector<string>::iterator p;
595 for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
596 cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
599 halt_connection.disconnect ();
600 AudioEngine::instance()->stop ();
604 /* this being a GUI and all, we want peakfiles */
606 AudioFileSource::set_build_peakfiles (true);
607 AudioFileSource::set_build_missing_peakfiles (true);
609 /* set default clock modes */
611 if (Profile->get_sae()) {
612 primary_clock->set_mode (AudioClock::BBT);
613 secondary_clock->set_mode (AudioClock::MinSec);
615 primary_clock->set_mode (AudioClock::Timecode);
616 secondary_clock->set_mode (AudioClock::BBT);
619 /* start the time-of-day-clock */
622 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
623 update_wall_clock ();
624 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
629 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
630 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
631 Config->map_parameters (pc);
633 UIConfiguration::instance().map_parameters (pc);
637 ARDOUR_UI::~ARDOUR_UI ()
639 UIConfiguration::instance().save_state();
643 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
644 // don't bother at 'real' exit. the OS cleans up for us.
646 delete primary_clock;
647 delete secondary_clock;
648 delete _process_thread;
653 delete gui_object_state;
654 FastMeter::flush_pattern_cache ();
655 PixFader::flush_pattern_cache ();
659 /* Small trick to flush main-thread event pool.
660 * Other thread-pools are destroyed at pthread_exit(),
661 * but tmain thread termination is too late to trigger Pool::~Pool()
663 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.
664 delete ev->event_pool();
669 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
671 if (Splash::instance()) {
672 Splash::instance()->pop_back_for (win);
677 ARDOUR_UI::configure_timeout ()
679 if (last_configure_time == 0) {
680 /* no configure events yet */
684 /* force a gap of 0.5 seconds since the last configure event
687 if (get_microseconds() - last_configure_time < 500000) {
690 have_configure_timeout = false;
691 save_ardour_state ();
697 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
699 if (have_configure_timeout) {
700 last_configure_time = get_microseconds();
702 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
703 have_configure_timeout = true;
710 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
712 const XMLProperty* prop;
714 if ((prop = node.property ("roll")) != 0) {
715 roll_controllable->set_id (prop->value());
717 if ((prop = node.property ("stop")) != 0) {
718 stop_controllable->set_id (prop->value());
720 if ((prop = node.property ("goto-start")) != 0) {
721 goto_start_controllable->set_id (prop->value());
723 if ((prop = node.property ("goto-end")) != 0) {
724 goto_end_controllable->set_id (prop->value());
726 if ((prop = node.property ("auto-loop")) != 0) {
727 auto_loop_controllable->set_id (prop->value());
729 if ((prop = node.property ("play-selection")) != 0) {
730 play_selection_controllable->set_id (prop->value());
732 if ((prop = node.property ("rec")) != 0) {
733 rec_controllable->set_id (prop->value());
735 if ((prop = node.property ("shuttle")) != 0) {
736 shuttle_box->controllable()->set_id (prop->value());
741 ARDOUR_UI::get_transport_controllable_state ()
743 XMLNode* node = new XMLNode(X_("TransportControllables"));
746 roll_controllable->id().print (buf, sizeof (buf));
747 node->add_property (X_("roll"), buf);
748 stop_controllable->id().print (buf, sizeof (buf));
749 node->add_property (X_("stop"), buf);
750 goto_start_controllable->id().print (buf, sizeof (buf));
751 node->add_property (X_("goto_start"), buf);
752 goto_end_controllable->id().print (buf, sizeof (buf));
753 node->add_property (X_("goto_end"), buf);
754 auto_loop_controllable->id().print (buf, sizeof (buf));
755 node->add_property (X_("auto_loop"), buf);
756 play_selection_controllable->id().print (buf, sizeof (buf));
757 node->add_property (X_("play_selection"), buf);
758 rec_controllable->id().print (buf, sizeof (buf));
759 node->add_property (X_("rec"), buf);
760 shuttle_box->controllable()->id().print (buf, sizeof (buf));
761 node->add_property (X_("shuttle"), buf);
767 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
770 _session->save_state (snapshot_name);
775 ARDOUR_UI::autosave_session ()
777 if (g_main_depth() > 1) {
778 /* inside a recursive main loop,
779 give up because we may not be able to
785 if (!Config->get_periodic_safety_backups()) {
790 _session->maybe_write_autosave();
797 ARDOUR_UI::update_autosave ()
799 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
801 if (_session && _session->dirty()) {
802 if (_autosave_connection.connected()) {
803 _autosave_connection.disconnect();
806 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
807 Config->get_periodic_safety_backup_interval() * 1000);
810 if (_autosave_connection.connected()) {
811 _autosave_connection.disconnect();
817 ARDOUR_UI::check_announcements ()
820 string _annc_filename;
823 _annc_filename = PROGRAM_NAME "_announcements_osx_";
824 #elif defined PLATFORM_WINDOWS
825 _annc_filename = PROGRAM_NAME "_announcements_windows_";
827 _annc_filename = PROGRAM_NAME "_announcements_linux_";
829 _annc_filename.append (VERSIONSTRING);
831 _announce_string = "";
833 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
834 FILE* fin = g_fopen (path.c_str(), "rb");
836 while (!feof (fin)) {
839 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
842 _announce_string.append (tmp, len);
847 pingback (VERSIONSTRING, path);
852 ARDOUR_UI::starting ()
854 Application* app = Application::instance ();
856 bool brand_new_user = ArdourStartup::required ();
858 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
859 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
861 if (ARDOUR_COMMAND_LINE::check_announcements) {
862 check_announcements ();
867 /* we need to create this early because it may need to set the
868 * audio backend end up.
872 audio_midi_setup.get (true);
874 std::cerr << "audio-midi engine setup failed."<< std::endl;
878 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
879 nsm = new NSM_Client;
880 if (!nsm->init (nsm_url)) {
881 /* the ardour executable may have different names:
883 * waf's obj.target for distro versions: eg ardour4, ardourvst4
884 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
885 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
887 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
889 const char *process_name = g_getenv ("ARDOUR_SELF");
890 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
893 // wait for announce reply from nsm server
894 for ( i = 0; i < 5000; ++i) {
898 if (nsm->is_active()) {
903 error << _("NSM server did not announce itself") << endmsg;
906 // wait for open command from nsm server
907 for ( i = 0; i < 5000; ++i) {
910 if (nsm->client_id ()) {
916 error << _("NSM: no client ID provided") << endmsg;
920 if (_session && nsm) {
921 _session->set_nsm_state( nsm->is_active() );
923 error << _("NSM: no session created") << endmsg;
927 // nsm requires these actions disabled
928 vector<string> action_names;
929 action_names.push_back("SaveAs");
930 action_names.push_back("Rename");
931 action_names.push_back("New");
932 action_names.push_back("Open");
933 action_names.push_back("Recent");
934 action_names.push_back("Close");
936 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
937 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
939 act->set_sensitive (false);
946 error << _("NSM: initialization failed") << endmsg;
952 if (brand_new_user) {
953 _initial_verbose_plugin_scan = true;
958 _initial_verbose_plugin_scan = false;
959 switch (s.response ()) {
960 case Gtk::RESPONSE_OK:
967 #ifdef NO_PLUGIN_STATE
969 ARDOUR::RecentSessions rs;
970 ARDOUR::read_recent_sessions (rs);
972 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
974 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
976 /* already used Ardour, have sessions ... warn about plugin state */
978 ArdourDialog d (_("Free/Demo Version Warning"), true);
980 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
981 CheckButton c (_("Don't warn me about this again"));
983 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"),
984 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
985 _("It will not restore OR save any plugin settings"),
986 _("If you load an existing session with plugin settings\n"
987 "they will not be used and will be lost."),
988 _("To get full access to updates without this limitation\n"
989 "consider becoming a subscriber for a low cost every month.")));
990 l.set_justify (JUSTIFY_CENTER);
992 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
994 d.get_vbox()->pack_start (l, true, true);
995 d.get_vbox()->pack_start (b, false, false, 12);
996 d.get_vbox()->pack_start (c, false, false, 12);
998 d.add_button (_("Quit now"), RESPONSE_CANCEL);
999 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1003 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1005 if (d.run () != RESPONSE_OK) {
1011 /* go get a session */
1013 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1015 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1016 std::cerr << "Cannot get session parameters."<< std::endl;
1023 goto_editor_window ();
1025 WM::Manager::instance().show_visible ();
1027 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1028 * editor window, and we may want stuff to be hidden.
1030 _status_bar_visibility.update ();
1032 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1037 ARDOUR_UI::check_memory_locking ()
1039 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1040 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1044 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1046 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1048 struct rlimit limits;
1050 long pages, page_size;
1052 size_t pages_len=sizeof(pages);
1053 if ((page_size = getpagesize()) < 0 ||
1054 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1056 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1061 ram = (int64_t) pages * (int64_t) page_size;
1064 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1068 if (limits.rlim_cur != RLIM_INFINITY) {
1070 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1074 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1075 "This might cause %1 to run out of memory before your system "
1076 "runs out of memory. \n\n"
1077 "You can view the memory limit with 'ulimit -l', "
1078 "and it is normally controlled by %2"),
1081 X_("/etc/login.conf")
1083 X_(" /etc/security/limits.conf")
1087 msg.set_default_response (RESPONSE_OK);
1089 VBox* vbox = msg.get_vbox();
1091 CheckButton cb (_("Do not show this window again"));
1092 hbox.pack_start (cb, true, false);
1093 vbox->pack_start (hbox);
1098 pop_back_splash (msg);
1100 editor->ensure_float (msg);
1103 if (cb.get_active()) {
1104 XMLNode node (X_("no-memory-warning"));
1105 Config->add_instant_xml (node);
1110 #endif // !__APPLE__
1115 ARDOUR_UI::queue_finish ()
1117 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1121 ARDOUR_UI::idle_finish ()
1124 return false; /* do not call again */
1131 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1133 if (_session->dirty()) {
1134 vector<string> actions;
1135 actions.push_back (_("Don't quit"));
1136 actions.push_back (_("Just quit"));
1137 actions.push_back (_("Save and quit"));
1138 switch (ask_about_saving_session(actions)) {
1143 /* use the default name */
1144 if (save_state_canfail ("")) {
1145 /* failed - don't quit */
1146 MessageDialog msg (*editor,
1147 string_compose (_("\
1148 %1 was unable to save your session.\n\n\
1149 If you still wish to quit, please use the\n\n\
1150 \"Just quit\" option."), PROGRAM_NAME));
1151 pop_back_splash(msg);
1161 second_connection.disconnect ();
1162 point_one_second_connection.disconnect ();
1163 point_zero_something_second_connection.disconnect();
1164 fps_connection.disconnect();
1167 delete ARDOUR_UI::instance()->video_timeline;
1168 ARDOUR_UI::instance()->video_timeline = NULL;
1169 stop_video_server();
1171 /* Save state before deleting the session, as that causes some
1172 windows to be destroyed before their visible state can be
1175 save_ardour_state ();
1177 close_all_dialogs ();
1180 _session->set_clean ();
1181 _session->remove_pending_capture_state ();
1186 halt_connection.disconnect ();
1187 AudioEngine::instance()->stop ();
1188 #ifdef WINDOWS_VST_SUPPORT
1189 fst_stop_threading();
1195 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1197 ArdourDialog window (_("Unsaved Session"));
1198 Gtk::HBox dhbox; // the hbox for the image and text
1199 Gtk::Label prompt_label;
1200 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1204 assert (actions.size() >= 3);
1206 window.add_button (actions[0], RESPONSE_REJECT);
1207 window.add_button (actions[1], RESPONSE_APPLY);
1208 window.add_button (actions[2], RESPONSE_ACCEPT);
1210 window.set_default_response (RESPONSE_ACCEPT);
1212 Gtk::Button noquit_button (msg);
1213 noquit_button.set_name ("EditorGTKButton");
1217 if (_session->snap_name() == _session->name()) {
1218 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?"),
1219 _session->snap_name());
1221 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?"),
1222 _session->snap_name());
1225 prompt_label.set_text (prompt);
1226 prompt_label.set_name (X_("PrompterLabel"));
1227 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1229 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1230 dhbox.set_homogeneous (false);
1231 dhbox.pack_start (*dimage, false, false, 5);
1232 dhbox.pack_start (prompt_label, true, false, 5);
1233 window.get_vbox()->pack_start (dhbox);
1235 window.set_name (_("Prompter"));
1236 window.set_modal (true);
1237 window.set_resizable (false);
1240 prompt_label.show();
1245 ResponseType r = (ResponseType) window.run();
1250 case RESPONSE_ACCEPT: // save and get out of here
1252 case RESPONSE_APPLY: // get out of here
1263 ARDOUR_UI::every_second ()
1266 update_xrun_count ();
1267 update_buffer_load ();
1268 update_disk_space ();
1269 update_timecode_format ();
1270 update_peak_thread_work ();
1272 if (nsm && nsm->is_active ()) {
1275 if (!_was_dirty && _session->dirty ()) {
1279 else if (_was_dirty && !_session->dirty ()){
1287 ARDOUR_UI::every_point_one_seconds ()
1289 // TODO get rid of this..
1290 // ShuttleControl is updated directly via TransportStateChange signal
1294 ARDOUR_UI::every_point_zero_something_seconds ()
1296 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1298 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1299 float mpeak = editor_meter->update_meters();
1300 if (mpeak > editor_meter_max_peak) {
1301 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1302 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1309 ARDOUR_UI::set_fps_timeout_connection ()
1311 unsigned int interval = 40;
1312 if (!_session) return;
1313 if (_session->timecode_frames_per_second() != 0) {
1314 /* ideally we'll use a select() to sleep and not accumulate
1315 * idle time to provide a regular periodic signal.
1316 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1317 * However, that'll require a dedicated thread and cross-thread
1318 * signals to the GUI Thread..
1320 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1321 * _session->frame_rate() / _session->nominal_frame_rate()
1322 / _session->timecode_frames_per_second()
1324 #ifdef PLATFORM_WINDOWS
1325 // the smallest windows scheduler time-slice is ~15ms.
1326 // periodic GUI timeouts shorter than that will cause
1327 // WaitForSingleObject to spinlock (100% of one CPU Core)
1328 // and gtk never enters idle mode.
1329 // also changing timeBeginPeriod(1) does not affect that in
1330 // any beneficial way, so we just limit the max rate for now.
1331 interval = std::max(30u, interval); // at most ~33Hz.
1333 interval = std::max(8u, interval); // at most 120Hz.
1336 fps_connection.disconnect();
1337 Timers::set_fps_interval (interval);
1341 ARDOUR_UI::update_sample_rate (framecnt_t)
1345 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1347 if (!AudioEngine::instance()->connected()) {
1349 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1353 framecnt_t rate = AudioEngine::instance()->sample_rate();
1356 /* no sample rate available */
1357 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1360 if (fmod (rate, 1000.0) != 0.0) {
1361 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1362 (float) rate / 1000.0f,
1363 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1365 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1367 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1371 sample_rate_label.set_markup (buf);
1375 ARDOUR_UI::update_format ()
1378 format_label.set_text ("");
1383 s << _("File:") << X_(" <span foreground=\"green\">");
1385 switch (_session->config.get_native_file_header_format ()) {
1417 switch (_session->config.get_native_file_data_format ()) {
1431 format_label.set_markup (s.str ());
1435 ARDOUR_UI::update_xrun_count ()
1439 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1440 should also be changed.
1444 const unsigned int x = _session->get_xrun_count ();
1446 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1448 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1451 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1453 xrun_label.set_markup (buf);
1454 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1458 ARDOUR_UI::update_cpu_load ()
1462 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1463 should also be changed.
1466 double const c = AudioEngine::instance()->get_dsp_load ();
1467 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1468 cpu_load_label.set_markup (buf);
1472 ARDOUR_UI::update_peak_thread_work ()
1475 const int c = SourceFactory::peak_work_queue_length ();
1477 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1478 peak_thread_work_label.set_markup (buf);
1480 peak_thread_work_label.set_markup (X_(""));
1485 ARDOUR_UI::update_buffer_load ()
1489 uint32_t const playback = _session ? _session->playback_load () : 100;
1490 uint32_t const capture = _session ? _session->capture_load () : 100;
1492 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1493 should also be changed.
1499 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1500 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1501 playback <= 5 ? X_("red") : X_("green"),
1503 capture <= 5 ? X_("red") : X_("green"),
1507 buffer_load_label.set_markup (buf);
1509 buffer_load_label.set_text ("");
1514 ARDOUR_UI::count_recenabled_streams (Route& route)
1516 Track* track = dynamic_cast<Track*>(&route);
1517 if (track && track->record_enabled()) {
1518 rec_enabled_streams += track->n_inputs().n_total();
1523 ARDOUR_UI::update_disk_space()
1525 if (_session == 0) {
1529 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1531 framecnt_t fr = _session->frame_rate();
1534 /* skip update - no SR available */
1539 /* Available space is unknown */
1540 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1541 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1542 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1544 rec_enabled_streams = 0;
1545 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1547 framecnt_t frames = opt_frames.get_value_or (0);
1549 if (rec_enabled_streams) {
1550 frames /= rec_enabled_streams;
1557 hrs = frames / (fr * 3600);
1560 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1562 frames -= hrs * fr * 3600;
1563 mins = frames / (fr * 60);
1564 frames -= mins * fr * 60;
1567 bool const low = (hrs == 0 && mins <= 30);
1571 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1572 low ? X_("red") : X_("green"),
1578 disk_space_label.set_markup (buf);
1582 ARDOUR_UI::update_timecode_format ()
1588 TimecodeSlave* tcslave;
1589 SyncSource sync_src = Config->get_sync_source();
1591 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1592 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1597 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1598 matching ? X_("green") : X_("red"),
1599 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1601 snprintf (buf, sizeof (buf), "TC: n/a");
1604 timecode_format_label.set_markup (buf);
1608 ARDOUR_UI::update_wall_clock ()
1612 static int last_min = -1;
1615 tm_now = localtime (&now);
1616 if (last_min != tm_now->tm_min) {
1618 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1619 wall_clock_label.set_text (buf);
1620 last_min = tm_now->tm_min;
1627 ARDOUR_UI::open_recent_session ()
1629 bool can_return = (_session != 0);
1631 SessionDialog recent_session_dialog;
1635 ResponseType r = (ResponseType) recent_session_dialog.run ();
1638 case RESPONSE_ACCEPT:
1642 recent_session_dialog.hide();
1649 recent_session_dialog.hide();
1653 std::string path = recent_session_dialog.session_folder();
1654 std::string state = recent_session_dialog.session_name (should_be_new);
1656 if (should_be_new == true) {
1660 _session_is_new = false;
1662 if (load_session (path, state) == 0) {
1671 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1673 if (!AudioEngine::instance()->connected()) {
1674 MessageDialog msg (parent, string_compose (
1675 _("%1 is not connected to any audio backend.\n"
1676 "You cannot open or close sessions in this condition"),
1678 pop_back_splash (msg);
1686 ARDOUR_UI::open_session ()
1688 if (!check_audioengine(*editor)) {
1692 /* ardour sessions are folders */
1693 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1694 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1695 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1696 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1699 string session_parent_dir = Glib::path_get_dirname(_session->path());
1700 open_session_selector.set_current_folder(session_parent_dir);
1702 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1705 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1707 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1708 string default_session_folder = Config->get_default_session_parent_dir();
1709 open_session_selector.add_shortcut_folder (default_session_folder);
1711 catch (Glib::Error & e) {
1712 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1715 FileFilter session_filter;
1716 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1717 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1718 open_session_selector.add_filter (session_filter);
1719 open_session_selector.set_filter (session_filter);
1721 int response = open_session_selector.run();
1722 open_session_selector.hide ();
1724 if (response == Gtk::RESPONSE_CANCEL) {
1728 string session_path = open_session_selector.get_filename();
1732 if (session_path.length() > 0) {
1733 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1734 _session_is_new = isnew;
1735 load_session (path, name);
1742 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1743 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1745 list<boost::shared_ptr<MidiTrack> > tracks;
1747 if (_session == 0) {
1748 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1753 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1755 if (tracks.size() != how_many) {
1756 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1761 MessageDialog msg (*editor,
1762 string_compose (_("There are insufficient ports available\n\
1763 to create a new track or bus.\n\
1764 You should save %1, exit and\n\
1765 restart with more ports."), PROGRAM_NAME));
1772 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1774 ChanCount one_midi_channel;
1775 one_midi_channel.set (DataType::MIDI, 1);
1778 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1783 ARDOUR_UI::session_add_audio_route (
1785 int32_t input_channels,
1786 int32_t output_channels,
1787 ARDOUR::TrackMode mode,
1788 RouteGroup* route_group,
1790 string const & name_template
1793 list<boost::shared_ptr<AudioTrack> > tracks;
1796 if (_session == 0) {
1797 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1803 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1805 if (tracks.size() != how_many) {
1806 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1812 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1814 if (routes.size() != how_many) {
1815 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1822 MessageDialog msg (*editor,
1823 string_compose (_("There are insufficient ports available\n\
1824 to create a new track or bus.\n\
1825 You should save %1, exit and\n\
1826 restart with more ports."), PROGRAM_NAME));
1827 pop_back_splash (msg);
1833 ARDOUR_UI::transport_goto_start ()
1836 _session->goto_start();
1838 /* force displayed area in editor to start no matter
1839 what "follow playhead" setting is.
1843 editor->center_screen (_session->current_start_frame ());
1849 ARDOUR_UI::transport_goto_zero ()
1852 _session->request_locate (0);
1854 /* force displayed area in editor to start no matter
1855 what "follow playhead" setting is.
1859 editor->reset_x_origin (0);
1865 ARDOUR_UI::transport_goto_wallclock ()
1867 if (_session && editor) {
1874 localtime_r (&now, &tmnow);
1876 framecnt_t frame_rate = _session->frame_rate();
1878 if (frame_rate == 0) {
1879 /* no frame rate available */
1883 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1884 frames += tmnow.tm_min * (60 * frame_rate);
1885 frames += tmnow.tm_sec * frame_rate;
1887 _session->request_locate (frames, _session->transport_rolling ());
1889 /* force displayed area in editor to start no matter
1890 what "follow playhead" setting is.
1894 editor->center_screen (frames);
1900 ARDOUR_UI::transport_goto_end ()
1903 framepos_t const frame = _session->current_end_frame();
1904 _session->request_locate (frame);
1906 /* force displayed area in editor to start no matter
1907 what "follow playhead" setting is.
1911 editor->center_screen (frame);
1917 ARDOUR_UI::transport_stop ()
1923 if (_session->is_auditioning()) {
1924 _session->cancel_audition ();
1928 _session->request_stop (false, true);
1931 /** Check if any tracks are record enabled. If none are, record enable all of them.
1932 * @return true if track record-enabled status was changed, false otherwise.
1935 ARDOUR_UI::trx_record_enable_all_tracks ()
1941 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1942 bool none_record_enabled = true;
1944 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1945 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1948 if (t->record_enabled()) {
1949 none_record_enabled = false;
1954 if (none_record_enabled) {
1955 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1958 return none_record_enabled;
1962 ARDOUR_UI::transport_record (bool roll)
1965 switch (_session->record_status()) {
1966 case Session::Disabled:
1967 if (_session->ntracks() == 0) {
1968 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."));
1972 if (Profile->get_trx()) {
1973 roll = trx_record_enable_all_tracks ();
1975 _session->maybe_enable_record ();
1980 case Session::Recording:
1982 _session->request_stop();
1984 _session->disable_record (false, true);
1988 case Session::Enabled:
1989 _session->disable_record (false, true);
1995 ARDOUR_UI::transport_roll ()
2001 if (_session->is_auditioning()) {
2006 if (_session->config.get_external_sync()) {
2007 switch (Config->get_sync_source()) {
2011 /* transport controlled by the master */
2017 bool rolling = _session->transport_rolling();
2019 if (_session->get_play_loop()) {
2021 /* If loop playback is not a mode, then we should cancel
2022 it when this action is requested. If it is a mode
2023 we just leave it in place.
2026 if (!Config->get_loop_is_mode()) {
2027 /* XXX it is not possible to just leave seamless loop and keep
2028 playing at present (nov 4th 2009)
2030 if (!Config->get_seamless_loop()) {
2031 /* stop loop playback and stop rolling */
2032 _session->request_play_loop (false, true);
2033 } else if (rolling) {
2034 /* stop loop playback but keep rolling */
2035 _session->request_play_loop (false, false);
2039 } else if (_session->get_play_range () ) {
2040 /* stop playing a range if we currently are */
2041 _session->request_play_range (0, true);
2045 _session->request_transport_speed (1.0f);
2050 ARDOUR_UI::get_smart_mode() const
2052 return ( editor->get_smart_mode() );
2057 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2063 if (_session->is_auditioning()) {
2064 _session->cancel_audition ();
2068 if (_session->config.get_external_sync()) {
2069 switch (Config->get_sync_source()) {
2073 /* transport controlled by the master */
2078 bool rolling = _session->transport_rolling();
2079 bool affect_transport = true;
2081 if (rolling && roll_out_of_bounded_mode) {
2082 /* drop out of loop/range playback but leave transport rolling */
2083 if (_session->get_play_loop()) {
2084 if (_session->actively_recording()) {
2086 /* just stop using the loop, then actually stop
2089 _session->request_play_loop (false, affect_transport);
2092 if (Config->get_seamless_loop()) {
2093 /* the disk buffers contain copies of the loop - we can't
2094 just keep playing, so stop the transport. the user
2095 can restart as they wish.
2097 affect_transport = true;
2099 /* disk buffers are normal, so we can keep playing */
2100 affect_transport = false;
2102 _session->request_play_loop (false, affect_transport);
2104 } else if (_session->get_play_range ()) {
2105 affect_transport = false;
2106 _session->request_play_range (0, true);
2110 if (affect_transport) {
2112 _session->request_stop (with_abort, true);
2113 } else if (!_session->config.get_external_sync()) {
2114 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
2115 _session->request_play_range (&editor->get_selection().time, true);
2116 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2118 _session->request_transport_speed (1.0f);
2124 ARDOUR_UI::toggle_session_auto_loop ()
2126 Location * looploc = _session->locations()->auto_loop_location();
2128 if (!_session || !looploc) {
2132 if (_session->get_play_loop()) {
2134 /* looping enabled, our job is to disable it */
2136 _session->request_play_loop (false);
2140 /* looping not enabled, our job is to enable it.
2142 loop-is-NOT-mode: this action always starts the transport rolling.
2143 loop-IS-mode: this action simply sets the loop play mechanism, but
2144 does not start transport.
2146 if (Config->get_loop_is_mode()) {
2147 _session->request_play_loop (true, false);
2149 _session->request_play_loop (true, true);
2153 //show the loop markers
2154 looploc->set_hidden (false, this);
2158 ARDOUR_UI::transport_play_selection ()
2164 editor->play_selection ();
2168 ARDOUR_UI::transport_play_preroll ()
2173 editor->play_with_preroll ();
2177 ARDOUR_UI::transport_rewind (int option)
2179 float current_transport_speed;
2182 current_transport_speed = _session->transport_speed();
2184 if (current_transport_speed >= 0.0f) {
2187 _session->request_transport_speed (-1.0f);
2190 _session->request_transport_speed (-4.0f);
2193 _session->request_transport_speed (-0.5f);
2198 _session->request_transport_speed (current_transport_speed * 1.5f);
2204 ARDOUR_UI::transport_forward (int option)
2210 float current_transport_speed = _session->transport_speed();
2212 if (current_transport_speed <= 0.0f) {
2215 _session->request_transport_speed (1.0f);
2218 _session->request_transport_speed (4.0f);
2221 _session->request_transport_speed (0.5f);
2226 _session->request_transport_speed (current_transport_speed * 1.5f);
2231 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2237 boost::shared_ptr<Route> r;
2239 if ((r = _session->route_by_remote_id (rid)) != 0) {
2243 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
2244 t->set_record_enabled (!t->record_enabled(), this);
2250 ARDOUR_UI::map_transport_state ()
2253 auto_loop_button.unset_active_state ();
2254 play_selection_button.unset_active_state ();
2255 roll_button.unset_active_state ();
2256 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2260 shuttle_box->map_transport_state ();
2262 float sp = _session->transport_speed();
2268 if (_session->get_play_range()) {
2270 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2271 roll_button.unset_active_state ();
2272 auto_loop_button.unset_active_state ();
2274 } else if (_session->get_play_loop ()) {
2276 auto_loop_button.set_active (true);
2277 play_selection_button.set_active (false);
2278 if (Config->get_loop_is_mode()) {
2279 roll_button.set_active (true);
2281 roll_button.set_active (false);
2286 roll_button.set_active (true);
2287 play_selection_button.set_active (false);
2288 auto_loop_button.set_active (false);
2291 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2292 /* light up both roll and play-selection if they are joined */
2293 roll_button.set_active (true);
2294 play_selection_button.set_active (true);
2297 stop_button.set_active (false);
2301 stop_button.set_active (true);
2302 roll_button.set_active (false);
2303 play_selection_button.set_active (false);
2304 if (Config->get_loop_is_mode ()) {
2305 auto_loop_button.set_active (_session->get_play_loop());
2307 auto_loop_button.set_active (false);
2309 update_disk_space ();
2314 ARDOUR_UI::blink_handler (bool blink_on)
2316 transport_rec_enable_blink (blink_on);
2317 solo_blink (blink_on);
2318 sync_blink (blink_on);
2319 audition_blink (blink_on);
2320 feedback_blink (blink_on);
2321 error_blink (blink_on);
2325 ARDOUR_UI::update_clocks ()
2327 if (!_session) return;
2329 if (editor && !editor->dragging_playhead()) {
2330 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2335 ARDOUR_UI::start_clocking ()
2337 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2338 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2340 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2345 ARDOUR_UI::stop_clocking ()
2347 clock_signal_connection.disconnect ();
2351 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2355 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2357 label->set_text (buf);
2358 bar->set_fraction (fraction);
2360 /* process events, redraws, etc. */
2362 while (gtk_events_pending()) {
2363 gtk_main_iteration ();
2366 return true; /* continue with save-as */
2370 ARDOUR_UI::save_session_as ()
2376 if (!save_as_dialog) {
2377 save_as_dialog = new SaveAsDialog;
2380 save_as_dialog->set_name (_session->name());
2382 int response = save_as_dialog->run ();
2384 save_as_dialog->hide ();
2387 case Gtk::RESPONSE_OK:
2396 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2397 sa.new_name = save_as_dialog->new_name ();
2398 sa.switch_to = save_as_dialog->switch_to();
2399 sa.copy_media = save_as_dialog->copy_media();
2400 sa.copy_external = save_as_dialog->copy_external();
2401 sa.include_media = save_as_dialog->include_media ();
2403 /* Only bother with a progress dialog if we're going to copy
2404 media into the save-as target. Without that choice, this
2405 will be very fast because we're only talking about a few kB's to
2406 perhaps a couple of MB's of data.
2409 ArdourDialog progress_dialog (_("Save As"), true);
2411 if (sa.include_media && sa.copy_media) {
2414 Gtk::ProgressBar progress_bar;
2416 progress_dialog.get_vbox()->pack_start (label);
2417 progress_dialog.get_vbox()->pack_start (progress_bar);
2419 progress_bar.show ();
2421 /* this signal will be emitted from within this, the calling thread,
2422 * after every file is copied. It provides information on percentage
2423 * complete (in terms of total data to copy), the number of files
2424 * copied so far, and the total number to copy.
2429 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2431 progress_dialog.show_all ();
2432 progress_dialog.present ();
2435 if (_session->save_as (sa)) {
2437 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2441 if (!sa.include_media) {
2442 unload_session (false);
2443 load_session (sa.final_session_folder_name, sa.new_name);
2448 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2452 prompter.get_result (snapname);
2454 bool do_save = (snapname.length() != 0);
2457 char illegal = Session::session_name_is_legal(snapname);
2459 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2460 "snapshot names may not contain a '%1' character"), illegal));
2466 vector<std::string> p;
2467 get_state_files_in_directory (_session->session_directory().root_path(), p);
2468 vector<string> n = get_file_names_no_extension (p);
2470 if (find (n.begin(), n.end(), snapname) != n.end()) {
2472 do_save = overwrite_file_dialog (prompter,
2473 _("Confirm Snapshot Overwrite"),
2474 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2478 save_state (snapname, switch_to_it);
2488 /** Ask the user for the name of a new snapshot and then take it.
2492 ARDOUR_UI::snapshot_session (bool switch_to_it)
2494 ArdourPrompter prompter (true);
2496 prompter.set_name ("Prompter");
2497 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2499 prompter.set_title (_("Save as..."));
2500 prompter.set_prompt (_("New session name"));
2502 prompter.set_title (_("Take Snapshot"));
2503 prompter.set_prompt (_("Name of new snapshot"));
2506 if (!switch_to_it) {
2509 struct tm local_time;
2512 localtime_r (&n, &local_time);
2513 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2514 prompter.set_initial_text (timebuf);
2517 bool finished = false;
2519 switch (prompter.run()) {
2520 case RESPONSE_ACCEPT:
2522 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2533 /** Ask the user for a new session name and then rename the session to it.
2537 ARDOUR_UI::rename_session ()
2543 ArdourPrompter prompter (true);
2546 prompter.set_name ("Prompter");
2547 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2548 prompter.set_title (_("Rename Session"));
2549 prompter.set_prompt (_("New session name"));
2552 switch (prompter.run()) {
2553 case RESPONSE_ACCEPT:
2555 prompter.get_result (name);
2557 bool do_rename = (name.length() != 0);
2560 char illegal = Session::session_name_is_legal (name);
2563 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2564 "session names may not contain a '%1' character"), illegal));
2569 switch (_session->rename (name)) {
2571 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2572 msg.set_position (WIN_POS_MOUSE);
2580 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2581 msg.set_position (WIN_POS_MOUSE);
2597 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2599 if (!_session || _session->deletion_in_progress()) {
2603 XMLNode* node = new XMLNode (X_("UI"));
2605 WM::Manager::instance().add_state (*node);
2607 node->add_child_nocopy (gui_object_state->get_state());
2609 _session->add_extra_xml (*node);
2611 if (export_video_dialog) {
2612 _session->add_extra_xml (export_video_dialog->get_state());
2615 save_state_canfail (name, switch_to_it);
2619 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2624 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2629 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2634 ARDOUR_UI::primary_clock_value_changed ()
2637 _session->request_locate (primary_clock->current_time ());
2642 ARDOUR_UI::big_clock_value_changed ()
2645 _session->request_locate (big_clock->current_time ());
2650 ARDOUR_UI::secondary_clock_value_changed ()
2653 _session->request_locate (secondary_clock->current_time ());
2658 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2660 if (_session == 0) {
2664 if (_session->step_editing()) {
2668 Session::RecordState const r = _session->record_status ();
2669 bool const h = _session->have_rec_enabled_track ();
2671 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2673 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2675 rec_button.set_active_state (Gtkmm2ext::Off);
2677 } else if (r == Session::Recording && h) {
2678 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2680 rec_button.unset_active_state ();
2685 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2689 prompter.get_result (name);
2691 if (name.length()) {
2692 int failed = _session->save_template (name);
2694 if (failed == -2) { /* file already exists. */
2695 bool overwrite = overwrite_file_dialog (prompter,
2696 _("Confirm Template Overwrite"),
2697 _("A template already exists with that name. Do you want to overwrite it?"));
2700 _session->save_template (name, true);
2712 ARDOUR_UI::save_template ()
2714 ArdourPrompter prompter (true);
2716 if (!check_audioengine(*editor)) {
2720 prompter.set_name (X_("Prompter"));
2721 prompter.set_title (_("Save Template"));
2722 prompter.set_prompt (_("Name for template:"));
2723 prompter.set_initial_text(_session->name() + _("-template"));
2724 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2726 bool finished = false;
2728 switch (prompter.run()) {
2729 case RESPONSE_ACCEPT:
2730 finished = process_save_template_prompter (prompter);
2741 ARDOUR_UI::edit_metadata ()
2743 SessionMetadataEditor dialog;
2744 dialog.set_session (_session);
2745 dialog.grab_focus ();
2750 ARDOUR_UI::import_metadata ()
2752 SessionMetadataImporter dialog;
2753 dialog.set_session (_session);
2758 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2760 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2762 MessageDialog msg (str,
2764 Gtk::MESSAGE_WARNING,
2765 Gtk::BUTTONS_YES_NO,
2769 msg.set_name (X_("OpenExistingDialog"));
2770 msg.set_title (_("Open Existing Session"));
2771 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2772 msg.set_position (Gtk::WIN_POS_CENTER);
2773 pop_back_splash (msg);
2775 switch (msg.run()) {
2784 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2786 BusProfile bus_profile;
2788 if (nsm || Profile->get_sae()) {
2790 bus_profile.master_out_channels = 2;
2791 bus_profile.input_ac = AutoConnectPhysical;
2792 bus_profile.output_ac = AutoConnectMaster;
2793 bus_profile.requested_physical_in = 0; // use all available
2794 bus_profile.requested_physical_out = 0; // use all available
2798 /* get settings from advanced section of NSD */
2800 if (sd.create_master_bus()) {
2801 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2803 bus_profile.master_out_channels = 0;
2806 if (sd.connect_inputs()) {
2807 bus_profile.input_ac = AutoConnectPhysical;
2809 bus_profile.input_ac = AutoConnectOption (0);
2812 bus_profile.output_ac = AutoConnectOption (0);
2814 if (sd.connect_outputs ()) {
2815 if (sd.connect_outs_to_master()) {
2816 bus_profile.output_ac = AutoConnectMaster;
2817 } else if (sd.connect_outs_to_physical()) {
2818 bus_profile.output_ac = AutoConnectPhysical;
2822 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2823 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2826 if (build_session (session_path, session_name, bus_profile)) {
2834 ARDOUR_UI::load_from_application_api (const std::string& path)
2836 ARDOUR_COMMAND_LINE::session_name = path;
2838 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2839 /* /path/to/foo => /path/to/foo, foo */
2840 load_session (path, basename_nosuffix (path));
2842 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2843 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2847 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2849 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2851 string session_name;
2852 string session_path;
2853 string template_name;
2855 bool likely_new = false;
2856 bool cancel_not_quit;
2858 /* deal with any existing DIRTY session now, rather than later. don't
2859 * treat a non-dirty session this way, so that it stays visible
2860 * as we bring up the new session dialog.
2863 if (_session && ARDOUR_UI::instance()->video_timeline) {
2864 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2867 /* if there is already a session, relabel the button
2868 on the SessionDialog so that we don't Quit directly
2870 cancel_not_quit = (_session != 0);
2872 if (_session && _session->dirty()) {
2873 if (unload_session (false)) {
2874 /* unload cancelled by user */
2877 ARDOUR_COMMAND_LINE::session_name = "";
2880 if (!load_template.empty()) {
2881 should_be_new = true;
2882 template_name = load_template;
2885 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2886 session_path = ARDOUR_COMMAND_LINE::session_name;
2888 if (!session_path.empty()) {
2889 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2890 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2891 /* session/snapshot file, change path to be dir */
2892 session_path = Glib::path_get_dirname (session_path);
2897 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2901 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2903 /* if they named a specific statefile, use it, otherwise they are
2904 just giving a session folder, and we want to use it as is
2905 to find the session.
2908 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2910 if (suffix != string::npos) {
2911 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2912 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2913 session_name = Glib::path_get_basename (session_name);
2915 session_path = ARDOUR_COMMAND_LINE::session_name;
2916 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2921 session_dialog.clear_given ();
2924 if (should_be_new || session_name.empty()) {
2925 /* need the dialog to get info from user */
2927 cerr << "run dialog\n";
2929 switch (session_dialog.run()) {
2930 case RESPONSE_ACCEPT:
2933 if (quit_on_cancel) {
2934 // JE - Currently (July 2014) this section can only get reached if the
2935 // user quits from the main 'Session Setup' dialog (i.e. reaching this
2936 // point does NOT indicate an abnormal termination). Therefore, let's
2937 // behave gracefully (i.e. let's do some cleanup) before we call exit()
2939 pthread_cancel_all ();
2947 session_dialog.hide ();
2950 /* if we run the startup dialog again, offer more than just "new session" */
2952 should_be_new = false;
2954 session_name = session_dialog.session_name (likely_new);
2955 session_path = session_dialog.session_folder ();
2961 string::size_type suffix = session_name.find (statefile_suffix);
2963 if (suffix != string::npos) {
2964 session_name = session_name.substr (0, suffix);
2967 /* this shouldn't happen, but we catch it just in case it does */
2969 if (session_name.empty()) {
2973 if (session_dialog.use_session_template()) {
2974 template_name = session_dialog.session_template_name();
2975 _session_is_new = true;
2978 if (session_name[0] == G_DIR_SEPARATOR ||
2979 #ifdef PLATFORM_WINDOWS
2980 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
2982 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2983 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
2988 /* absolute path or cwd-relative path specified for session name: infer session folder
2989 from what was given.
2992 session_path = Glib::path_get_dirname (session_name);
2993 session_name = Glib::path_get_basename (session_name);
2997 session_path = session_dialog.session_folder();
2999 char illegal = Session::session_name_is_legal (session_name);
3002 MessageDialog msg (session_dialog,
3003 string_compose (_("To ensure compatibility with various systems\n"
3004 "session names may not contain a '%1' character"),
3007 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3012 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3015 if (likely_new && !nsm) {
3017 std::string existing = Glib::build_filename (session_path, session_name);
3019 if (!ask_about_loading_existing_session (existing)) {
3020 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3025 _session_is_new = false;
3030 pop_back_splash (session_dialog);
3031 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3033 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3037 char illegal = Session::session_name_is_legal(session_name);
3040 pop_back_splash (session_dialog);
3041 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3042 "session names may not contain a '%1' character"), illegal));
3044 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3048 _session_is_new = true;
3051 if (likely_new && template_name.empty()) {
3053 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3057 ret = load_session (session_path, session_name, template_name);
3060 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3064 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3065 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3069 /* clear this to avoid endless attempts to load the
3073 ARDOUR_COMMAND_LINE::session_name = "";
3081 ARDOUR_UI::close_session()
3083 if (!check_audioengine(*editor)) {
3087 if (unload_session (true)) {
3091 ARDOUR_COMMAND_LINE::session_name = "";
3093 if (get_session_parameters (true, false)) {
3097 goto_editor_window ();
3100 /** @param snap_name Snapshot name (without .ardour suffix).
3101 * @return -2 if the load failed because we are not connected to the AudioEngine.
3104 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3106 Session *new_session;
3111 unload_status = unload_session ();
3113 if (unload_status < 0) {
3115 } else if (unload_status > 0) {
3121 session_loaded = false;
3123 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3126 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3129 /* this one is special */
3131 catch (AudioEngine::PortRegistrationFailure& err) {
3133 MessageDialog msg (err.what(),
3136 Gtk::BUTTONS_CLOSE);
3138 msg.set_title (_("Port Registration Error"));
3139 msg.set_secondary_text (_("Click the Close button to try again."));
3140 msg.set_position (Gtk::WIN_POS_CENTER);
3141 pop_back_splash (msg);
3144 int response = msg.run ();
3149 case RESPONSE_CANCEL:
3156 catch (SessionException e) {
3157 MessageDialog msg (string_compose(
3158 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3159 path, snap_name, e.what()),
3164 msg.set_title (_("Loading Error"));
3165 msg.set_position (Gtk::WIN_POS_CENTER);
3166 pop_back_splash (msg);
3178 MessageDialog msg (string_compose(
3179 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3185 msg.set_title (_("Loading Error"));
3186 msg.set_position (Gtk::WIN_POS_CENTER);
3187 pop_back_splash (msg);
3199 list<string> const u = new_session->unknown_processors ();
3201 MissingPluginDialog d (_session, u);
3206 if (!new_session->writable()) {
3207 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3212 msg.set_title (_("Read-only Session"));
3213 msg.set_position (Gtk::WIN_POS_CENTER);
3214 pop_back_splash (msg);
3221 /* Now the session been created, add the transport controls */
3222 new_session->add_controllable(roll_controllable);
3223 new_session->add_controllable(stop_controllable);
3224 new_session->add_controllable(goto_start_controllable);
3225 new_session->add_controllable(goto_end_controllable);
3226 new_session->add_controllable(auto_loop_controllable);
3227 new_session->add_controllable(play_selection_controllable);
3228 new_session->add_controllable(rec_controllable);
3230 set_session (new_session);
3232 session_loaded = true;
3234 goto_editor_window ();
3237 _session->set_clean ();
3240 #ifdef WINDOWS_VST_SUPPORT
3241 fst_stop_threading();
3245 Timers::TimerSuspender t;
3249 #ifdef WINDOWS_VST_SUPPORT
3250 fst_start_threading();
3259 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3261 Session *new_session;
3264 session_loaded = false;
3265 x = unload_session ();
3273 _session_is_new = true;
3276 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3279 catch (SessionException e) {
3281 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3282 msg.set_title (_("Loading Error"));
3283 msg.set_position (Gtk::WIN_POS_CENTER);
3284 pop_back_splash (msg);
3290 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3291 msg.set_title (_("Loading Error"));
3292 msg.set_position (Gtk::WIN_POS_CENTER);
3293 pop_back_splash (msg);
3298 /* Give the new session the default GUI state, if such things exist */
3301 n = Config->instant_xml (X_("Editor"));
3303 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3304 new_session->add_instant_xml (*n, false);
3306 n = Config->instant_xml (X_("Mixer"));
3308 new_session->add_instant_xml (*n, false);
3311 /* Put the playhead at 0 and scroll fully left */
3312 n = new_session->instant_xml (X_("Editor"));
3314 n->add_property (X_("playhead"), X_("0"));
3315 n->add_property (X_("left-frame"), X_("0"));
3318 set_session (new_session);
3320 session_loaded = true;
3322 new_session->save_state(new_session->name());
3328 ARDOUR_UI::launch_chat ()
3330 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3332 dialog.set_title (_("About the Chat"));
3333 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."));
3335 switch (dialog.run()) {
3338 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3339 #elif defined PLATFORM_WINDOWS
3340 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3342 open_uri("http://webchat.freenode.net/?channels=ardour");
3351 ARDOUR_UI::launch_manual ()
3353 PBD::open_uri (Config->get_tutorial_manual_url());
3357 ARDOUR_UI::launch_reference ()
3359 PBD::open_uri (Config->get_reference_manual_url());
3363 ARDOUR_UI::launch_tracker ()
3365 PBD::open_uri ("http://tracker.ardour.org/bug_report_page.php");
3369 ARDOUR_UI::launch_subscribe ()
3371 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3375 ARDOUR_UI::launch_cheat_sheet ()
3378 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3380 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3385 ARDOUR_UI::launch_website ()
3387 PBD::open_uri ("http://ardour.org");
3391 ARDOUR_UI::launch_website_dev ()
3393 PBD::open_uri ("http://ardour.org/development.html");
3397 ARDOUR_UI::launch_forums ()
3399 PBD::open_uri ("https://community.ardour.org/forums");
3403 ARDOUR_UI::launch_howto_report ()
3405 PBD::open_uri ("http://ardour.org/reporting_bugs");
3409 ARDOUR_UI::loading_message (const std::string& msg)
3411 if (ARDOUR_COMMAND_LINE::no_splash) {
3419 splash->message (msg);
3423 ARDOUR_UI::show_splash ()
3427 splash = new Splash;
3437 ARDOUR_UI::hide_splash ()
3444 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3448 removed = rep.paths.size();
3451 MessageDialog msgd (*editor,
3452 _("No files were ready for clean-up"),
3456 msgd.set_title (_("Clean-up"));
3457 msgd.set_secondary_text (_("If this seems suprising, \n\
3458 check for any existing snapshots.\n\
3459 These may still include regions that\n\
3460 require some unused files to continue to exist."));
3466 ArdourDialog results (_("Clean-up"), true, false);
3468 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3469 CleanupResultsModelColumns() {
3473 Gtk::TreeModelColumn<std::string> visible_name;
3474 Gtk::TreeModelColumn<std::string> fullpath;
3478 CleanupResultsModelColumns results_columns;
3479 Glib::RefPtr<Gtk::ListStore> results_model;
3480 Gtk::TreeView results_display;
3482 results_model = ListStore::create (results_columns);
3483 results_display.set_model (results_model);
3484 results_display.append_column (list_title, results_columns.visible_name);
3486 results_display.set_name ("CleanupResultsList");
3487 results_display.set_headers_visible (true);
3488 results_display.set_headers_clickable (false);
3489 results_display.set_reorderable (false);
3491 Gtk::ScrolledWindow list_scroller;
3494 Gtk::HBox dhbox; // the hbox for the image and text
3495 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3496 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3498 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3500 const string dead_directory = _session->session_directory().dead_path();
3503 %1 - number of files removed
3504 %2 - location of "dead"
3505 %3 - size of files affected
3506 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3509 const char* bprefix;
3510 double space_adjusted = 0;
3512 if (rep.space < 1000) {
3514 space_adjusted = rep.space;
3515 } else if (rep.space < 1000000) {
3516 bprefix = _("kilo");
3517 space_adjusted = floorf((float)rep.space / 1000.0);
3518 } else if (rep.space < 1000000 * 1000) {
3519 bprefix = _("mega");
3520 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3522 bprefix = _("giga");
3523 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3527 txt.set_markup (string_compose (P_("\
3528 The following file was deleted from %2,\n\
3529 releasing %3 %4bytes of disk space", "\
3530 The following %1 files were deleted from %2,\n\
3531 releasing %3 %4bytes of disk space", removed),
3532 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3534 txt.set_markup (string_compose (P_("\
3535 The following file was not in use and \n\
3536 has been moved to: %2\n\n\
3537 After a restart of %5\n\n\
3538 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3539 will release an additional %3 %4bytes of disk space.\n", "\
3540 The following %1 files were not in use and \n\
3541 have been moved to: %2\n\n\
3542 After a restart of %5\n\n\
3543 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3544 will release an additional %3 %4bytes of disk space.\n", removed),
3545 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3548 dhbox.pack_start (*dimage, true, false, 5);
3549 dhbox.pack_start (txt, true, false, 5);
3551 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3552 TreeModel::Row row = *(results_model->append());
3553 row[results_columns.visible_name] = *i;
3554 row[results_columns.fullpath] = *i;
3557 list_scroller.add (results_display);
3558 list_scroller.set_size_request (-1, 150);
3559 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3561 dvbox.pack_start (dhbox, true, false, 5);
3562 dvbox.pack_start (list_scroller, true, false, 5);
3563 ddhbox.pack_start (dvbox, true, false, 5);
3565 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3566 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3567 results.set_default_response (RESPONSE_CLOSE);
3568 results.set_position (Gtk::WIN_POS_MOUSE);
3570 results_display.show();
3571 list_scroller.show();
3578 //results.get_vbox()->show();
3579 results.set_resizable (false);
3586 ARDOUR_UI::cleanup ()
3588 if (_session == 0) {
3589 /* shouldn't happen: menu item is insensitive */
3594 MessageDialog checker (_("Are you sure you want to clean-up?"),
3596 Gtk::MESSAGE_QUESTION,
3599 checker.set_title (_("Clean-up"));
3601 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3602 ALL undo/redo information will be lost if you clean-up.\n\
3603 Clean-up will move all unused files to a \"dead\" location."));
3605 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3606 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3607 checker.set_default_response (RESPONSE_CANCEL);
3609 checker.set_name (_("CleanupDialog"));
3610 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3611 checker.set_position (Gtk::WIN_POS_MOUSE);
3613 switch (checker.run()) {
3614 case RESPONSE_ACCEPT:
3620 ARDOUR::CleanupReport rep;
3622 editor->prepare_for_cleanup ();
3624 /* do not allow flush until a session is reloaded */
3626 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3628 act->set_sensitive (false);
3631 if (_session->cleanup_sources (rep)) {
3632 editor->finish_cleanup ();
3636 editor->finish_cleanup ();
3639 display_cleanup_results (rep, _("Cleaned Files"), false);
3643 ARDOUR_UI::flush_trash ()
3645 if (_session == 0) {
3646 /* shouldn't happen: menu item is insensitive */
3650 ARDOUR::CleanupReport rep;
3652 if (_session->cleanup_trash_sources (rep)) {
3656 display_cleanup_results (rep, _("deleted file"), true);
3660 ARDOUR_UI::cleanup_peakfiles ()
3662 if (_session == 0) {
3663 /* shouldn't happen: menu item is insensitive */
3667 if (! _session->can_cleanup_peakfiles ()) {
3671 // get all region-views in this session
3673 TrackViewList empty;
3675 editor->get_regions_after(rs, (framepos_t) 0, empty);
3676 std::list<RegionView*> views = rs.by_layer();
3678 // remove displayed audio-region-views waveforms
3679 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3680 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3681 if (!arv) { continue ; }
3682 arv->delete_waves();
3685 // cleanup peak files:
3686 // - stop pending peakfile threads
3687 // - close peakfiles if any
3688 // - remove peak dir in session
3689 // - setup peakfiles (background thread)
3690 _session->cleanup_peakfiles ();
3692 // re-add waves to ARV
3693 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3694 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3695 if (!arv) { continue ; }
3696 arv->create_waves();
3701 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3703 uint32_t order_hint = UINT32_MAX;
3705 if (editor->get_selection().tracks.empty()) {
3710 we want the new routes to have their order keys set starting from
3711 the highest order key in the selection + 1 (if available).
3714 if (place == AddRouteDialog::AfterSelection) {
3715 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3717 order_hint = rtav->route()->order_key();
3720 } else if (place == AddRouteDialog::BeforeSelection) {
3721 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3723 order_hint = rtav->route()->order_key();
3725 } else if (place == AddRouteDialog::First) {
3728 /* leave order_hint at UINT32_MAX */
3731 if (order_hint == UINT32_MAX) {
3732 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3733 * not setting an order hint will place new routes last.
3738 _session->set_order_hint (order_hint);
3740 /* create a gap in the existing route order keys to accomodate new routes.*/
3741 boost::shared_ptr <RouteList> rd = _session->get_routes();
3742 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3743 boost::shared_ptr<Route> rt (*ri);
3745 if (rt->is_monitor()) {
3749 if (rt->order_key () >= order_hint) {
3750 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3756 ARDOUR_UI::start_duplicate_routes ()
3758 if (!duplicate_routes_dialog) {
3759 duplicate_routes_dialog = new DuplicateRouteDialog;
3760 duplicate_routes_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::finish_duplicate_routes));
3763 TrackSelection& tracks (editor->get_selection().tracks);
3764 uint32_t ntracks = 0;
3765 uint32_t nbusses = 0;
3767 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
3769 RouteUI* rui = dynamic_cast<RouteUI*> (*t);
3772 /* some other type of timeaxis view, not a route */
3776 boost::shared_ptr<Route> r (rui->route());
3778 if (boost::dynamic_pointer_cast<Track> (r)) {
3781 if (!r->is_master() && !r->is_monitor()) {
3787 if (ntracks == 0 && nbusses == 0) {
3788 cerr << "You can't do this\n";
3792 duplicate_routes_dialog->setup (ntracks, nbusses);
3793 duplicate_routes_dialog->present ();
3797 ARDOUR_UI::finish_duplicate_routes (int response)
3799 if (!duplicate_routes_dialog) {
3800 /* how could this happen? */
3804 duplicate_routes_dialog->hide ();
3806 if (response != Gtk::RESPONSE_OK) {
3810 ARDOUR::PlaylistDisposition playlist_disposition = duplicate_routes_dialog->playlist_disposition ();
3811 uint32_t count = duplicate_routes_dialog->count ();
3813 /* Copy the track selection because it will/may change as we add new ones */
3814 TrackSelection tracks (editor->get_selection().tracks);
3817 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
3819 RouteUI* rui = dynamic_cast<RouteUI*> (*t);
3822 /* some other type of timeaxis view, not a route */
3826 if (rui->route()->is_master() || rui->route()->is_monitor()) {
3827 /* no option to duplicate these */
3831 XMLNode& state (rui->route()->get_state());
3832 RouteList rl = _session->new_route_from_template (count, state, string(), playlist_disposition);
3834 /* normally the state node would be added to a parent, and
3835 * ownership would transfer. Because we don't do that here,
3836 * we need to delete the node ourselves.
3848 MessageDialog msg (_("1 or more tracks/busses could not be duplicated"),
3849 true, MESSAGE_ERROR, BUTTONS_OK, true);
3850 msg.set_position (WIN_POS_MOUSE);
3856 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3864 if (add_route_dialog->is_visible()) {
3865 /* we're already doing this */
3869 ResponseType r = (ResponseType) add_route_dialog->run ();
3871 add_route_dialog->hide();
3874 case RESPONSE_ACCEPT:
3881 if ((count = add_route_dialog->count()) <= 0) {
3885 setup_order_hint(add_route_dialog->insert_at());
3887 string template_path = add_route_dialog->track_template();
3888 DisplaySuspender ds;
3890 if (!template_path.empty()) {
3891 if (add_route_dialog->name_template_is_default()) {
3892 _session->new_route_from_template (count, template_path, string());
3894 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3899 ChanCount input_chan= add_route_dialog->channels ();
3900 ChanCount output_chan;
3901 string name_template = add_route_dialog->name_template ();
3902 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3903 RouteGroup* route_group = add_route_dialog->route_group ();
3904 AutoConnectOption oac = Config->get_output_auto_connect();
3906 if (oac & AutoConnectMaster) {
3907 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3908 output_chan.set (DataType::MIDI, 0);
3910 output_chan = input_chan;
3913 /* XXX do something with name template */
3915 switch (add_route_dialog->type_wanted()) {
3916 case AddRouteDialog::AudioTrack:
3917 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3919 case AddRouteDialog::MidiTrack:
3920 session_add_midi_track (route_group, count, name_template, instrument);
3922 case AddRouteDialog::MixedTrack:
3923 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3925 case AddRouteDialog::AudioBus:
3926 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3932 ARDOUR_UI::stop_video_server (bool ask_confirm)
3934 if (!video_server_process && ask_confirm) {
3935 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3937 if (video_server_process) {
3939 ArdourDialog confirm (_("Stop Video-Server"), true);
3940 Label m (_("Do you really want to stop the Video Server?"));
3941 confirm.get_vbox()->pack_start (m, true, true);
3942 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3943 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3944 confirm.show_all ();
3945 if (confirm.run() == RESPONSE_CANCEL) {
3949 delete video_server_process;
3950 video_server_process =0;
3955 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3957 ARDOUR_UI::start_video_server( float_window, true);
3961 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3967 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3968 if (video_server_process) {
3969 popup_error(_("The Video Server is already started."));
3971 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3977 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3979 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3981 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3983 video_server_dialog->set_transient_for (*float_window);
3986 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3987 video_server_dialog->hide();
3989 ResponseType r = (ResponseType) video_server_dialog->run ();
3990 video_server_dialog->hide();
3991 if (r != RESPONSE_ACCEPT) { return false; }
3992 if (video_server_dialog->show_again()) {
3993 Config->set_show_video_server_dialog(false);
3997 std::string icsd_exec = video_server_dialog->get_exec_path();
3998 std::string icsd_docroot = video_server_dialog->get_docroot();
3999 if (icsd_docroot.empty()) {
4000 #ifndef PLATFORM_WINDOWS
4001 icsd_docroot = X_("/");
4003 icsd_docroot = X_("C:\\");
4008 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4009 warning << _("Specified docroot is not an existing directory.") << endmsg;
4012 #ifndef PLATFORM_WINDOWS
4013 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4014 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4015 warning << _("Given Video Server is not an executable file.") << endmsg;
4019 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4020 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4021 warning << _("Given Video Server is not an executable file.") << endmsg;
4027 argp=(char**) calloc(9,sizeof(char*));
4028 argp[0] = strdup(icsd_exec.c_str());
4029 argp[1] = strdup("-P");
4030 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4031 argp[3] = strdup("-p");
4032 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4033 argp[5] = strdup("-C");
4034 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4035 argp[7] = strdup(icsd_docroot.c_str());
4037 stop_video_server();
4039 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4040 Config->set_video_advanced_setup(false);
4042 std::ostringstream osstream;
4043 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4044 Config->set_video_server_url(osstream.str());
4045 Config->set_video_server_docroot(icsd_docroot);
4046 Config->set_video_advanced_setup(true);
4049 if (video_server_process) {
4050 delete video_server_process;
4053 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4054 if (video_server_process->start()) {
4055 warning << _("Cannot launch the video-server") << endmsg;
4058 int timeout = 120; // 6 sec
4059 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4060 Glib::usleep (50000);
4062 if (--timeout <= 0 || !video_server_process->is_running()) break;
4065 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4067 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4068 delete video_server_process;
4069 video_server_process = 0;
4077 ARDOUR_UI::add_video (Gtk::Window* float_window)
4083 if (!start_video_server(float_window, false)) {
4084 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4089 add_video_dialog->set_transient_for (*float_window);
4092 if (add_video_dialog->is_visible()) {
4093 /* we're already doing this */
4097 ResponseType r = (ResponseType) add_video_dialog->run ();
4098 add_video_dialog->hide();
4099 if (r != RESPONSE_ACCEPT) { return; }
4101 bool local_file, orig_local_file;
4102 std::string path = add_video_dialog->file_name(local_file);
4104 std::string orig_path = path;
4105 orig_local_file = local_file;
4107 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4109 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4110 warning << string_compose(_("could not open %1"), path) << endmsg;
4113 if (!local_file && path.length() == 0) {
4114 warning << _("no video-file selected") << endmsg;
4118 std::string audio_from_video;
4119 bool detect_ltc = false;
4121 switch (add_video_dialog->import_option()) {
4122 case VTL_IMPORT_TRANSCODE:
4124 TranscodeVideoDialog *transcode_video_dialog;
4125 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4126 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4127 transcode_video_dialog->hide();
4128 if (r != RESPONSE_ACCEPT) {
4129 delete transcode_video_dialog;
4133 audio_from_video = transcode_video_dialog->get_audiofile();
4135 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4138 else if (!audio_from_video.empty()) {
4139 editor->embed_audio_from_video(
4141 video_timeline->get_offset(),
4142 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4145 switch (transcode_video_dialog->import_option()) {
4146 case VTL_IMPORT_TRANSCODED:
4147 path = transcode_video_dialog->get_filename();
4150 case VTL_IMPORT_REFERENCE:
4153 delete transcode_video_dialog;
4156 delete transcode_video_dialog;
4160 case VTL_IMPORT_NONE:
4164 /* strip _session->session_directory().video_path() from video file if possible */
4165 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4166 path=path.substr(_session->session_directory().video_path().size());
4167 if (path.at(0) == G_DIR_SEPARATOR) {
4168 path=path.substr(1);
4172 video_timeline->set_update_session_fps(auto_set_session_fps);
4174 if (video_timeline->video_file_info(path, local_file)) {
4175 XMLNode* node = new XMLNode(X_("Videotimeline"));
4176 node->add_property (X_("Filename"), path);
4177 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4178 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4179 if (orig_local_file) {
4180 node->add_property (X_("OriginalVideoFile"), orig_path);
4182 node->remove_property (X_("OriginalVideoFile"));
4184 _session->add_extra_xml (*node);
4185 _session->set_dirty ();
4187 if (!audio_from_video.empty() && detect_ltc) {
4188 std::vector<LTCFileReader::LTCMap> ltc_seq;
4191 /* TODO ask user about TV standard (LTC alignment if any) */
4192 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4193 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4195 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4197 /* TODO seek near end of file, and read LTC until end.
4198 * if it fails to find any LTC frames, scan complete file
4200 * calculate drift of LTC compared to video-duration,
4201 * ask user for reference (timecode from start/mid/end)
4204 // LTCFileReader will have written error messages
4207 ::g_unlink(audio_from_video.c_str());
4209 if (ltc_seq.size() == 0) {
4210 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4212 /* the very first TC in the file is somteimes not aligned properly */
4213 int i = ltc_seq.size() -1;
4214 ARDOUR::frameoffset_t video_start_offset =
4215 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4216 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4217 video_timeline->set_offset(video_start_offset);
4221 _session->maybe_update_session_range(
4222 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4223 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4226 if (add_video_dialog->launch_xjadeo() && local_file) {
4227 editor->set_xjadeo_sensitive(true);
4228 editor->toggle_xjadeo_proc(1);
4230 editor->toggle_xjadeo_proc(0);
4232 editor->toggle_ruler_video(true);
4237 ARDOUR_UI::remove_video ()
4239 video_timeline->close_session();
4240 editor->toggle_ruler_video(false);
4243 video_timeline->set_offset_locked(false);
4244 video_timeline->set_offset(0);
4246 /* delete session state */
4247 XMLNode* node = new XMLNode(X_("Videotimeline"));
4248 _session->add_extra_xml(*node);
4249 node = new XMLNode(X_("Videomonitor"));
4250 _session->add_extra_xml(*node);
4251 node = new XMLNode(X_("Videoexport"));
4252 _session->add_extra_xml(*node);
4253 stop_video_server();
4257 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4259 if (localcacheonly) {
4260 video_timeline->vmon_update();
4262 video_timeline->flush_cache();
4264 editor->queue_visual_videotimeline_update();
4268 ARDOUR_UI::export_video (bool range)
4270 if (ARDOUR::Config->get_show_video_export_info()) {
4271 ExportVideoInfobox infobox (_session);
4272 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4273 if (infobox.show_again()) {
4274 ARDOUR::Config->set_show_video_export_info(false);
4277 case GTK_RESPONSE_YES:
4278 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4284 export_video_dialog->set_session (_session);
4285 export_video_dialog->apply_state(editor->get_selection().time, range);
4286 export_video_dialog->run ();
4287 export_video_dialog->hide ();
4291 ARDOUR_UI::mixer_settings () const
4296 node = _session->instant_xml(X_("Mixer"));
4298 node = Config->instant_xml(X_("Mixer"));
4302 node = new XMLNode (X_("Mixer"));
4309 ARDOUR_UI::editor_settings () const
4314 node = _session->instant_xml(X_("Editor"));
4316 node = Config->instant_xml(X_("Editor"));
4320 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4321 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4326 node = new XMLNode (X_("Editor"));
4333 ARDOUR_UI::keyboard_settings () const
4337 node = Config->extra_xml(X_("Keyboard"));
4340 node = new XMLNode (X_("Keyboard"));
4347 ARDOUR_UI::create_xrun_marker (framepos_t where)
4350 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4351 _session->locations()->add (location);
4356 ARDOUR_UI::halt_on_xrun_message ()
4358 cerr << "HALT on xrun\n";
4359 MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up."));
4364 ARDOUR_UI::xrun_handler (framepos_t where)
4370 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4372 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4373 create_xrun_marker(where);
4376 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4377 halt_on_xrun_message ();
4382 ARDOUR_UI::disk_overrun_handler ()
4384 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4386 if (!have_disk_speed_dialog_displayed) {
4387 have_disk_speed_dialog_displayed = true;
4388 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
4389 The disk system on your computer\n\
4390 was not able to keep up with %1.\n\
4392 Specifically, it failed to write data to disk\n\
4393 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4394 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4400 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4401 static MessageDialog *scan_dlg = NULL;
4402 static ProgressBar *scan_pbar = NULL;
4403 static HBox *scan_tbox = NULL;
4404 static Gtk::Button *scan_timeout_button;
4407 ARDOUR_UI::cancel_plugin_scan ()
4409 PluginManager::instance().cancel_plugin_scan();
4413 ARDOUR_UI::cancel_plugin_timeout ()
4415 PluginManager::instance().cancel_plugin_timeout();
4416 scan_timeout_button->set_sensitive (false);
4420 ARDOUR_UI::plugin_scan_timeout (int timeout)
4422 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4426 scan_pbar->set_sensitive (false);
4427 scan_timeout_button->set_sensitive (true);
4428 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4431 scan_pbar->set_sensitive (false);
4432 scan_timeout_button->set_sensitive (false);
4438 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4440 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4444 const bool cancelled = PluginManager::instance().cancelled();
4445 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4446 if (cancelled && scan_dlg->is_mapped()) {
4451 if (cancelled || !can_cancel) {
4456 static Gtk::Button *cancel_button;
4458 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4459 VBox* vbox = scan_dlg->get_vbox();
4460 vbox->set_size_request(400,-1);
4461 scan_dlg->set_title (_("Scanning for plugins"));
4463 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4464 cancel_button->set_name ("EditorGTKButton");
4465 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4466 cancel_button->show();
4468 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4470 scan_tbox = manage( new HBox() );
4472 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4473 scan_timeout_button->set_name ("EditorGTKButton");
4474 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4475 scan_timeout_button->show();
4477 scan_pbar = manage(new ProgressBar());
4478 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4479 scan_pbar->set_text(_("Scan Timeout"));
4482 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4483 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4485 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4488 assert(scan_dlg && scan_tbox && cancel_button);
4490 if (type == X_("closeme")) {
4494 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4497 if (!can_cancel || !cancelled) {
4498 scan_timeout_button->set_sensitive(false);
4500 cancel_button->set_sensitive(can_cancel && !cancelled);
4506 ARDOUR_UI::gui_idle_handler ()
4509 /* due to idle calls, gtk_events_pending() may always return true */
4510 while (gtk_events_pending() && --timeout) {
4511 gtk_main_iteration ();
4516 ARDOUR_UI::disk_underrun_handler ()
4518 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4520 if (!have_disk_speed_dialog_displayed) {
4521 have_disk_speed_dialog_displayed = true;
4522 MessageDialog* msg = new MessageDialog (
4523 *editor, string_compose (_("The disk system on your computer\n\
4524 was not able to keep up with %1.\n\
4526 Specifically, it failed to read data from disk\n\
4527 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4528 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4534 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4536 have_disk_speed_dialog_displayed = false;
4541 ARDOUR_UI::session_dialog (std::string msg)
4543 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4548 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4550 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4559 ARDOUR_UI::pending_state_dialog ()
4561 HBox* hbox = manage (new HBox());
4562 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4563 ArdourDialog dialog (_("Crash Recovery"), true);
4564 Label message (string_compose (_("\
4565 This session appears to have been in the\n\
4566 middle of recording when %1 or\n\
4567 the computer was shutdown.\n\
4569 %1 can recover any captured audio for\n\
4570 you, or it can ignore it. Please decide\n\
4571 what you would like to do.\n"), PROGRAM_NAME));
4572 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4573 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4574 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4575 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4576 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4577 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4578 dialog.set_default_response (RESPONSE_ACCEPT);
4579 dialog.set_position (WIN_POS_CENTER);
4584 switch (dialog.run ()) {
4585 case RESPONSE_ACCEPT:
4593 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4595 HBox* hbox = new HBox();
4596 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4597 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4598 Label message (string_compose (_("\
4599 This session was created with a sample rate of %1 Hz, but\n\
4600 %2 is currently running at %3 Hz. If you load this session,\n\
4601 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4603 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4604 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4605 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4606 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4607 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4608 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4609 dialog.set_default_response (RESPONSE_ACCEPT);
4610 dialog.set_position (WIN_POS_CENTER);
4615 switch (dialog.run()) {
4616 case RESPONSE_ACCEPT:
4626 ARDOUR_UI::use_config ()
4628 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4630 set_transport_controllable_state (*node);
4635 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4637 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4638 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4640 primary_clock->set (pos);
4643 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4644 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4646 secondary_clock->set (pos);
4649 if (big_clock_window) {
4650 big_clock->set (pos);
4652 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4656 ARDOUR_UI::step_edit_status_change (bool yn)
4658 // XXX should really store pre-step edit status of things
4659 // we make insensitive
4662 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4663 rec_button.set_sensitive (false);
4665 rec_button.unset_active_state ();;
4666 rec_button.set_sensitive (true);
4671 ARDOUR_UI::record_state_changed ()
4673 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4675 if (!_session || !big_clock_window) {
4676 /* why bother - the clock isn't visible */
4680 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4681 big_clock->set_active (true);
4683 big_clock->set_active (false);
4688 ARDOUR_UI::first_idle ()
4691 _session->allow_auto_play (true);
4695 editor->first_idle();
4698 Keyboard::set_can_save_keybindings (true);
4703 ARDOUR_UI::store_clock_modes ()
4705 XMLNode* node = new XMLNode(X_("ClockModes"));
4707 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4708 XMLNode* child = new XMLNode (X_("Clock"));
4710 child->add_property (X_("name"), (*x)->name());
4711 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4712 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4714 node->add_child_nocopy (*child);
4717 _session->add_extra_xml (*node);
4718 _session->set_dirty ();
4721 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4722 : Controllable (name), ui (u), type(tp)
4728 ARDOUR_UI::TransportControllable::set_value (double val)
4731 /* do nothing: these are radio-style actions */
4735 const char *action = 0;
4739 action = X_("Roll");
4742 action = X_("Stop");
4745 action = X_("GotoStart");
4748 action = X_("GotoEnd");
4751 action = X_("Loop");
4754 action = X_("PlaySelection");
4757 action = X_("Record");
4767 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4775 ARDOUR_UI::TransportControllable::get_value (void) const
4802 ARDOUR_UI::setup_profile ()
4804 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4805 Profile->set_small_screen ();
4808 if (g_getenv ("ARDOUR_SAE")) {
4809 Profile->set_sae ();
4810 Profile->set_single_package ();
4813 if (g_getenv ("TRX")) {
4814 Profile->set_trx ();
4817 if (g_getenv ("MIXBUS")) {
4818 Profile->set_mixbus ();
4823 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4825 MissingFileDialog dialog (s, str, type);
4830 int result = dialog.run ();
4837 return 1; // quit entire session load
4840 result = dialog.get_action ();
4846 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4848 AmbiguousFileDialog dialog (file, hits);
4855 return dialog.get_which ();
4858 /** Allocate our thread-local buffers */
4860 ARDOUR_UI::get_process_buffers ()
4862 _process_thread->get_buffers ();
4865 /** Drop our thread-local buffers */
4867 ARDOUR_UI::drop_process_buffers ()
4869 _process_thread->drop_buffers ();
4873 ARDOUR_UI::feedback_detected ()
4875 _feedback_exists = true;
4879 ARDOUR_UI::successful_graph_sort ()
4881 _feedback_exists = false;
4885 ARDOUR_UI::midi_panic ()
4888 _session->midi_panic();
4893 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4895 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4896 const char* end_big = "</span>";
4897 const char* start_mono = "<tt>";
4898 const char* end_mono = "</tt>";
4900 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4901 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4902 "From now on, use the -2000 version with older versions of %3"),
4903 xml_path, backup_path, PROGRAM_NAME,
4905 start_mono, end_mono), true);
4912 ARDOUR_UI::reset_peak_display ()
4914 if (!_session || !_session->master_out() || !editor_meter) return;
4915 editor_meter->clear_meters();
4916 editor_meter_max_peak = -INFINITY;
4917 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4921 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4923 if (!_session || !_session->master_out()) return;
4924 if (group == _session->master_out()->route_group()) {
4925 reset_peak_display ();
4930 ARDOUR_UI::reset_route_peak_display (Route* route)
4932 if (!_session || !_session->master_out()) return;
4933 if (_session->master_out().get() == route) {
4934 reset_peak_display ();
4939 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4941 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4942 audio_midi_setup->set_position (WIN_POS_CENTER);
4947 response = audio_midi_setup->run();
4949 case Gtk::RESPONSE_OK:
4950 if (!AudioEngine::instance()->running()) {
4964 ARDOUR_UI::transport_numpad_timeout ()
4966 _numpad_locate_happening = false;
4967 if (_numpad_timeout_connection.connected() )
4968 _numpad_timeout_connection.disconnect();
4973 ARDOUR_UI::transport_numpad_decimal ()
4975 _numpad_timeout_connection.disconnect();
4977 if (_numpad_locate_happening) {
4978 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4979 _numpad_locate_happening = false;
4981 _pending_locate_num = 0;
4982 _numpad_locate_happening = true;
4983 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
4988 ARDOUR_UI::transport_numpad_event (int num)
4990 if ( _numpad_locate_happening ) {
4991 _pending_locate_num = _pending_locate_num*10 + num;
4994 case 0: toggle_roll(false, false); break;
4995 case 1: transport_rewind(1); break;
4996 case 2: transport_forward(1); break;
4997 case 3: transport_record(true); break;
4998 case 4: toggle_session_auto_loop(); break;
4999 case 5: transport_record(false); toggle_session_auto_loop(); break;
5000 case 6: toggle_punch(); break;
5001 case 7: toggle_click(); break;
5002 case 8: toggle_auto_return(); break;
5003 case 9: toggle_follow_edits(); break;
5009 ARDOUR_UI::set_flat_buttons ()
5011 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5015 ARDOUR_UI::audioengine_became_silent ()
5017 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5019 Gtk::MESSAGE_WARNING,
5023 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5025 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5026 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5027 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5028 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5029 Gtk::HBox pay_button_box;
5030 Gtk::HBox subscribe_button_box;
5032 pay_button_box.pack_start (pay_button, true, false);
5033 subscribe_button_box.pack_start (subscribe_button, true, false);
5035 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 */
5037 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5038 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5040 msg.get_vbox()->pack_start (pay_label);
5041 msg.get_vbox()->pack_start (pay_button_box);
5042 msg.get_vbox()->pack_start (subscribe_label);
5043 msg.get_vbox()->pack_start (subscribe_button_box);
5045 msg.get_vbox()->show_all ();
5047 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5048 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5049 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5054 case Gtk::RESPONSE_YES:
5055 AudioEngine::instance()->reset_silence_countdown ();
5058 case Gtk::RESPONSE_NO:
5060 save_state_canfail ("");
5064 case Gtk::RESPONSE_CANCEL:
5066 /* don't reset, save session and exit */
5072 ARDOUR_UI::hide_application ()
5074 Application::instance ()-> hide ();
5078 ARDOUR_UI::cancel_solo ()
5081 if (_session->soloing()) {
5082 _session->set_solo (_session->get_routes(), false);
5083 } else if (_session->listening()) {
5084 _session->set_listen (_session->get_routes(), false);
5087 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window