2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #ifdef WINDOWS_VST_SUPPORT
97 #ifdef AUDIOUNIT_SUPPORT
98 #include "ardour/audio_unit.h"
101 #include "timecode/time.h"
103 typedef uint64_t microseconds_t;
108 #include "add_route_dialog.h"
109 #include "ambiguous_file_dialog.h"
110 #include "ardour_ui.h"
111 #include "audio_clock.h"
112 #include "audio_region_view.h"
113 #include "big_clock_window.h"
114 #include "bundle_manager.h"
115 #include "duplicate_routes_dialog.h"
117 #include "engine_dialog.h"
118 #include "export_video_dialog.h"
119 #include "export_video_infobox.h"
120 #include "gain_meter.h"
121 #include "global_port_matrix.h"
122 #include "gui_object.h"
123 #include "gui_thread.h"
124 #include "keyboard.h"
125 #include "keyeditor.h"
126 #include "location_ui.h"
127 #include "main_clock.h"
128 #include "missing_file_dialog.h"
129 #include "missing_plugin_dialog.h"
130 #include "mixer_ui.h"
131 #include "meterbridge.h"
132 #include "mouse_cursors.h"
135 #include "pingback.h"
136 #include "processor_box.h"
137 #include "prompter.h"
138 #include "public_editor.h"
139 #include "rc_option_editor.h"
140 #include "route_time_axis.h"
141 #include "route_params_ui.h"
142 #include "save_as_dialog.h"
143 #include "session_dialog.h"
144 #include "session_metadata_dialog.h"
145 #include "session_option_editor.h"
146 #include "shuttle_control.h"
147 #include "speaker_dialog.h"
150 #include "theme_manager.h"
151 #include "time_axis_view_item.h"
154 #include "video_server_dialog.h"
155 #include "add_video_dialog.h"
156 #include "transcode_video_dialog.h"
160 using namespace ARDOUR;
161 using namespace ARDOUR_UI_UTILS;
163 using namespace Gtkmm2ext;
166 using namespace Editing;
168 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
170 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
171 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
174 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
176 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
177 "Would you like these files to be copied and used for %1 %2.x?\n\n"
178 "(This will require you to restart %1.)"),
179 PROGRAM_NAME, PROGRAM_VERSION, version),
180 false, /* no markup */
183 true /* modal, though it hardly matters since it is the only window */
186 msg.set_default_response (Gtk::RESPONSE_YES);
189 return (msg.run() == Gtk::RESPONSE_YES);
193 libxml_generic_error_func (void* /* parsing_context*/,
201 vsnprintf (buf, sizeof (buf), msg, ap);
202 error << buf << endmsg;
207 libxml_structured_error_func (void* /* parsing_context*/,
215 replace_all (msg, "\n", "");
217 if (err->file && err->line) {
218 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
221 error << ':' << err->int2;
228 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
231 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
233 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
234 >>>>>>> first compilable version of tabbable design.
235 , session_loaded (false)
236 , gui_object_state (new GUIObjectState)
237 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
238 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
239 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
241 , global_actions (X_("global"))
242 , ignore_dual_punch (false)
247 , _mixer_on_top (false)
248 , _initial_verbose_plugin_scan (false)
249 , first_time_engine_run (true)
250 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
251 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
252 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
253 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
254 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
255 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
256 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
257 , auto_return_button (ArdourButton::led_default_elements)
258 , follow_edits_button (ArdourButton::led_default_elements)
259 , auto_input_button (ArdourButton::led_default_elements)
260 , auditioning_alert_button (_("Audition"))
261 , solo_alert_button (_("Solo"))
262 , feedback_alert_button (_("Feedback"))
263 , error_alert_button ( ArdourButton::just_led_default_elements )
265 , editor_meter_peak_display()
266 , _numpad_locate_happening (false)
267 , _session_is_new (false)
268 , last_key_press_time (0)
271 , rc_option_editor (0)
272 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
273 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
274 , about (X_("about"), _("About"))
275 , location_ui (X_("locations"), _("Locations"))
276 , route_params (X_("inspector"), _("Tracks and Busses"))
277 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
278 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
279 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
280 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
281 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
282 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
283 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
284 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
285 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
286 , video_server_process (0)
288 , have_configure_timeout (false)
289 , last_configure_time (0)
291 , have_disk_speed_dialog_displayed (false)
292 , _status_bar_visibility (X_("status-bar"))
293 , _feedback_exists (false)
294 , _log_not_acknowledged (LogLevelNone)
295 , duplicate_routes_dialog (0)
297 Gtkmm2ext::init (localedir);
299 UIConfiguration::instance().post_gui_init ();
301 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
302 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
304 /* configuration was modified, exit immediately */
308 if (theArdourUI == 0) {
312 /* stop libxml from spewing to stdout/stderr */
314 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
315 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
317 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
318 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
319 UIConfiguration::instance().map_parameters (pc);
321 roll_button.set_controllable (roll_controllable);
322 stop_button.set_controllable (stop_controllable);
323 goto_start_button.set_controllable (goto_start_controllable);
324 goto_end_button.set_controllable (goto_end_controllable);
325 auto_loop_button.set_controllable (auto_loop_controllable);
326 play_selection_button.set_controllable (play_selection_controllable);
327 rec_button.set_controllable (rec_controllable);
329 roll_button.set_name ("transport button");
330 stop_button.set_name ("transport button");
331 goto_start_button.set_name ("transport button");
332 goto_end_button.set_name ("transport button");
333 auto_loop_button.set_name ("transport button");
334 play_selection_button.set_name ("transport button");
335 rec_button.set_name ("transport recenable button");
336 midi_panic_button.set_name ("transport button");
338 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
339 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
341 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
343 /* handle dialog requests */
345 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
347 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
349 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
351 /* handle Audio/MIDI setup when session requires it */
353 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
355 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
357 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
359 /* handle requests to quit (coming from JACK session) */
361 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
363 /* tell the user about feedback */
365 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
366 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
368 /* handle requests to deal with missing files */
370 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
372 /* and ambiguous files */
374 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
376 /* also plugin scan messages */
377 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
378 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
380 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
382 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
385 /* lets get this party started */
387 setup_gtk_ardour_enums ();
390 SessionEvent::create_per_thread_pool ("GUI", 4096);
392 /* we like keyboards */
394 keyboard = new ArdourKeyboard(*this);
396 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
398 keyboard->set_state (*node, Stateful::loading_state_version);
401 /* we don't like certain modifiers */
402 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
404 UIConfiguration::instance().reset_dpi ();
406 TimeAxisViewItem::set_constant_heights ();
408 /* Set this up so that our window proxies can register actions */
410 ActionManager::init ();
412 /* The following must happen after ARDOUR::init() so that Config is set up */
414 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
417 key_editor.set_state (*ui_xml, 0);
418 session_option_editor.set_state (*ui_xml, 0);
419 speaker_config_window.set_state (*ui_xml, 0);
420 about.set_state (*ui_xml, 0);
421 add_route_dialog.set_state (*ui_xml, 0);
422 add_video_dialog.set_state (*ui_xml, 0);
423 route_params.set_state (*ui_xml, 0);
424 bundle_manager.set_state (*ui_xml, 0);
425 location_ui.set_state (*ui_xml, 0);
426 big_clock_window.set_state (*ui_xml, 0);
427 audio_port_matrix.set_state (*ui_xml, 0);
428 midi_port_matrix.set_state (*ui_xml, 0);
429 export_video_dialog.set_state (*ui_xml, 0);
432 /* Separate windows */
434 WM::Manager::instance().register_window (&key_editor);
435 WM::Manager::instance().register_window (&session_option_editor);
436 WM::Manager::instance().register_window (&speaker_config_window);
437 WM::Manager::instance().register_window (&about);
438 WM::Manager::instance().register_window (&add_route_dialog);
439 WM::Manager::instance().register_window (&add_video_dialog);
440 WM::Manager::instance().register_window (&route_params);
441 WM::Manager::instance().register_window (&audio_midi_setup);
442 WM::Manager::instance().register_window (&export_video_dialog);
443 WM::Manager::instance().register_window (&bundle_manager);
444 WM::Manager::instance().register_window (&location_ui);
445 WM::Manager::instance().register_window (&big_clock_window);
446 WM::Manager::instance().register_window (&audio_port_matrix);
447 WM::Manager::instance().register_window (&midi_port_matrix);
449 /* Trigger setting up the color scheme and loading the GTK RC file */
451 UIConfiguration::instance().load_rc_file (false);
453 _process_thread = new ProcessThread ();
454 _process_thread->init ();
456 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
461 GlobalPortMatrixWindow*
462 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
467 return new GlobalPortMatrixWindow (_session, type);
471 ARDOUR_UI::attach_to_engine ()
473 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
474 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
478 ARDOUR_UI::engine_stopped ()
480 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
481 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
482 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
483 update_sample_rate (0);
488 ARDOUR_UI::engine_running ()
490 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
491 if (first_time_engine_run) {
493 first_time_engine_run = false;
497 _session->reset_xrun_count ();
499 update_disk_space ();
501 update_xrun_count ();
502 update_sample_rate (AudioEngine::instance()->sample_rate());
503 update_timecode_format ();
504 update_peak_thread_work ();
505 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
506 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
510 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
512 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
513 /* we can't rely on the original string continuing to exist when we are called
514 again in the GUI thread, so make a copy and note that we need to
517 char *copy = strdup (reason);
518 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
522 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
523 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
525 update_sample_rate (0);
529 /* if the reason is a non-empty string, it means that the backend was shutdown
530 rather than just Ardour.
533 if (strlen (reason)) {
534 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
536 msgstr = string_compose (_("\
537 The audio backend has either been shutdown or it\n\
538 disconnected %1 because %1\n\
539 was not fast enough. Try to restart\n\
540 the audio backend and save the session."), PROGRAM_NAME);
543 MessageDialog msg (_main_window, msgstr);
544 pop_back_splash (msg);
548 free (const_cast<char*> (reason));
553 ARDOUR_UI::post_engine ()
555 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
557 #ifdef AUDIOUNIT_SUPPORT
559 if (AUPluginInfo::au_get_crashlog(au_msg)) {
560 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
561 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
562 info << au_msg << endmsg;
566 ARDOUR::init_post_engine ();
568 /* connect to important signals */
570 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
571 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
572 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
573 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
574 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
576 if (setup_windows ()) {
577 throw failed_constructor ();
580 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
581 XMLNode* n = Config->extra_xml (X_("UI"));
583 _status_bar_visibility.set_state (*n);
586 check_memory_locking();
588 /* this is the first point at which all the possible actions are
589 * available, because some of the available actions are dependent on
590 * aspects of the engine/backend.
593 if (ARDOUR_COMMAND_LINE::show_key_actions) {
595 for (list<Bindings*>::const_iterator mb = Bindings::bindings.begin(); mb != Bindings::bindings.end(); ++mb) {
597 vector<string> names;
598 vector<string> paths;
601 #warning Paul fix this before tabbed is merged
602 // mb->second->get_all_actions (names, paths, keys);
604 vector<string>::iterator n;
605 vector<string>::iterator k;
606 vector<string>::iterator p;
607 for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
608 cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
612 halt_connection.disconnect ();
613 AudioEngine::instance()->stop ();
617 /* this being a GUI and all, we want peakfiles */
619 AudioFileSource::set_build_peakfiles (true);
620 AudioFileSource::set_build_missing_peakfiles (true);
622 /* set default clock modes */
624 if (Profile->get_sae()) {
625 primary_clock->set_mode (AudioClock::BBT);
626 secondary_clock->set_mode (AudioClock::MinSec);
628 primary_clock->set_mode (AudioClock::Timecode);
629 secondary_clock->set_mode (AudioClock::BBT);
632 /* start the time-of-day-clock */
635 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
636 update_wall_clock ();
637 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
642 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
643 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
644 Config->map_parameters (pc);
646 UIConfiguration::instance().map_parameters (pc);
650 ARDOUR_UI::~ARDOUR_UI ()
652 UIConfiguration::instance().save_state();
656 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
657 // don't bother at 'real' exit. the OS cleans up for us.
659 delete primary_clock;
660 delete secondary_clock;
661 delete _process_thread;
666 delete gui_object_state;
667 FastMeter::flush_pattern_cache ();
668 PixFader::flush_pattern_cache ();
672 /* Small trick to flush main-thread event pool.
673 * Other thread-pools are destroyed at pthread_exit(),
674 * but tmain thread termination is too late to trigger Pool::~Pool()
676 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.
677 delete ev->event_pool();
682 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
684 if (Splash::instance()) {
685 Splash::instance()->pop_back_for (win);
690 ARDOUR_UI::configure_timeout ()
692 if (last_configure_time == 0) {
693 /* no configure events yet */
697 /* force a gap of 0.5 seconds since the last configure event
700 if (get_microseconds() - last_configure_time < 500000) {
703 have_configure_timeout = false;
704 save_ardour_state ();
710 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
712 if (have_configure_timeout) {
713 last_configure_time = get_microseconds();
715 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
716 have_configure_timeout = true;
723 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
725 const XMLProperty* prop;
727 if ((prop = node.property ("roll")) != 0) {
728 roll_controllable->set_id (prop->value());
730 if ((prop = node.property ("stop")) != 0) {
731 stop_controllable->set_id (prop->value());
733 if ((prop = node.property ("goto-start")) != 0) {
734 goto_start_controllable->set_id (prop->value());
736 if ((prop = node.property ("goto-end")) != 0) {
737 goto_end_controllable->set_id (prop->value());
739 if ((prop = node.property ("auto-loop")) != 0) {
740 auto_loop_controllable->set_id (prop->value());
742 if ((prop = node.property ("play-selection")) != 0) {
743 play_selection_controllable->set_id (prop->value());
745 if ((prop = node.property ("rec")) != 0) {
746 rec_controllable->set_id (prop->value());
748 if ((prop = node.property ("shuttle")) != 0) {
749 shuttle_box->controllable()->set_id (prop->value());
754 ARDOUR_UI::get_transport_controllable_state ()
756 XMLNode* node = new XMLNode(X_("TransportControllables"));
759 roll_controllable->id().print (buf, sizeof (buf));
760 node->add_property (X_("roll"), buf);
761 stop_controllable->id().print (buf, sizeof (buf));
762 node->add_property (X_("stop"), buf);
763 goto_start_controllable->id().print (buf, sizeof (buf));
764 node->add_property (X_("goto_start"), buf);
765 goto_end_controllable->id().print (buf, sizeof (buf));
766 node->add_property (X_("goto_end"), buf);
767 auto_loop_controllable->id().print (buf, sizeof (buf));
768 node->add_property (X_("auto_loop"), buf);
769 play_selection_controllable->id().print (buf, sizeof (buf));
770 node->add_property (X_("play_selection"), buf);
771 rec_controllable->id().print (buf, sizeof (buf));
772 node->add_property (X_("rec"), buf);
773 shuttle_box->controllable()->id().print (buf, sizeof (buf));
774 node->add_property (X_("shuttle"), buf);
780 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
783 _session->save_state (snapshot_name);
788 ARDOUR_UI::autosave_session ()
790 if (g_main_depth() > 1) {
791 /* inside a recursive main loop,
792 give up because we may not be able to
798 if (!Config->get_periodic_safety_backups()) {
803 _session->maybe_write_autosave();
810 ARDOUR_UI::session_dirty_changed ()
817 ARDOUR_UI::update_autosave ()
819 if (_session && _session->dirty()) {
820 if (_autosave_connection.connected()) {
821 _autosave_connection.disconnect();
824 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
825 Config->get_periodic_safety_backup_interval() * 1000);
828 if (_autosave_connection.connected()) {
829 _autosave_connection.disconnect();
835 ARDOUR_UI::check_announcements ()
838 string _annc_filename;
841 _annc_filename = PROGRAM_NAME "_announcements_osx_";
842 #elif defined PLATFORM_WINDOWS
843 _annc_filename = PROGRAM_NAME "_announcements_windows_";
845 _annc_filename = PROGRAM_NAME "_announcements_linux_";
847 _annc_filename.append (VERSIONSTRING);
849 _announce_string = "";
851 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
852 FILE* fin = g_fopen (path.c_str(), "rb");
854 while (!feof (fin)) {
857 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
860 _announce_string.append (tmp, len);
865 pingback (VERSIONSTRING, path);
870 _hide_splash (gpointer arg)
872 ((ARDOUR_UI*)arg)->hide_splash();
877 ARDOUR_UI::starting ()
879 Application* app = Application::instance ();
881 bool brand_new_user = ArdourStartup::required ();
883 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
884 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
886 if (ARDOUR_COMMAND_LINE::check_announcements) {
887 check_announcements ();
892 /* we need to create this early because it may need to set the
893 * audio backend end up.
897 audio_midi_setup.get (true);
899 std::cerr << "audio-midi engine setup failed."<< std::endl;
903 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
904 nsm = new NSM_Client;
905 if (!nsm->init (nsm_url)) {
906 /* the ardour executable may have different names:
908 * waf's obj.target for distro versions: eg ardour4, ardourvst4
909 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
910 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
912 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
914 const char *process_name = g_getenv ("ARDOUR_SELF");
915 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
918 // wait for announce reply from nsm server
919 for ( i = 0; i < 5000; ++i) {
923 if (nsm->is_active()) {
928 error << _("NSM server did not announce itself") << endmsg;
931 // wait for open command from nsm server
932 for ( i = 0; i < 5000; ++i) {
935 if (nsm->client_id ()) {
941 error << _("NSM: no client ID provided") << endmsg;
945 if (_session && nsm) {
946 _session->set_nsm_state( nsm->is_active() );
948 error << _("NSM: no session created") << endmsg;
952 // nsm requires these actions disabled
953 vector<string> action_names;
954 action_names.push_back("SaveAs");
955 action_names.push_back("Rename");
956 action_names.push_back("New");
957 action_names.push_back("Open");
958 action_names.push_back("Recent");
959 action_names.push_back("Close");
961 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
962 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
964 act->set_sensitive (false);
971 error << _("NSM: initialization failed") << endmsg;
977 if (brand_new_user) {
978 _initial_verbose_plugin_scan = true;
983 _initial_verbose_plugin_scan = false;
984 switch (s.response ()) {
985 case Gtk::RESPONSE_OK:
992 #ifdef NO_PLUGIN_STATE
994 ARDOUR::RecentSessions rs;
995 ARDOUR::read_recent_sessions (rs);
997 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
999 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1001 /* already used Ardour, have sessions ... warn about plugin state */
1003 ArdourDialog d (_("Free/Demo Version Warning"), true);
1005 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1006 CheckButton c (_("Don't warn me about this again"));
1008 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"),
1009 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1010 _("It will not restore OR save any plugin settings"),
1011 _("If you load an existing session with plugin settings\n"
1012 "they will not be used and will be lost."),
1013 _("To get full access to updates without this limitation\n"
1014 "consider becoming a subscriber for a low cost every month.")));
1015 l.set_justify (JUSTIFY_CENTER);
1017 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1019 d.get_vbox()->pack_start (l, true, true);
1020 d.get_vbox()->pack_start (b, false, false, 12);
1021 d.get_vbox()->pack_start (c, false, false, 12);
1023 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1024 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1028 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1030 if (d.run () != RESPONSE_OK) {
1036 /* go get a session */
1038 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1040 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1041 std::cerr << "Cannot get session parameters."<< std::endl;
1048 WM::Manager::instance().show_visible ();
1050 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1051 * editor window, and we may want stuff to be hidden.
1053 _status_bar_visibility.update ();
1055 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1057 if (splash && splash->is_visible()) {
1058 // in 1 second, hide the splash screen
1059 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1062 /* all other dialogs are created conditionally */
1068 ARDOUR_UI::check_memory_locking ()
1070 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1071 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1075 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1077 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1079 struct rlimit limits;
1081 long pages, page_size;
1083 size_t pages_len=sizeof(pages);
1084 if ((page_size = getpagesize()) < 0 ||
1085 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1087 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1092 ram = (int64_t) pages * (int64_t) page_size;
1095 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1099 if (limits.rlim_cur != RLIM_INFINITY) {
1101 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1105 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1106 "This might cause %1 to run out of memory before your system "
1107 "runs out of memory. \n\n"
1108 "You can view the memory limit with 'ulimit -l', "
1109 "and it is normally controlled by %2"),
1112 X_("/etc/login.conf")
1114 X_(" /etc/security/limits.conf")
1118 msg.set_default_response (RESPONSE_OK);
1120 VBox* vbox = msg.get_vbox();
1122 CheckButton cb (_("Do not show this window again"));
1123 hbox.pack_start (cb, true, false);
1124 vbox->pack_start (hbox);
1129 pop_back_splash (msg);
1133 if (cb.get_active()) {
1134 XMLNode node (X_("no-memory-warning"));
1135 Config->add_instant_xml (node);
1140 #endif // !__APPLE__
1145 ARDOUR_UI::queue_finish ()
1147 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1151 ARDOUR_UI::idle_finish ()
1154 return false; /* do not call again */
1161 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1163 if (_session->dirty()) {
1164 vector<string> actions;
1165 actions.push_back (_("Don't quit"));
1166 actions.push_back (_("Just quit"));
1167 actions.push_back (_("Save and quit"));
1168 switch (ask_about_saving_session(actions)) {
1173 /* use the default name */
1174 if (save_state_canfail ("")) {
1175 /* failed - don't quit */
1176 MessageDialog msg (_main_window,
1177 string_compose (_("\
1178 %1 was unable to save your session.\n\n\
1179 If you still wish to quit, please use the\n\n\
1180 \"Just quit\" option."), PROGRAM_NAME));
1181 pop_back_splash(msg);
1191 second_connection.disconnect ();
1192 point_one_second_connection.disconnect ();
1193 point_zero_something_second_connection.disconnect();
1194 fps_connection.disconnect();
1197 delete ARDOUR_UI::instance()->video_timeline;
1198 ARDOUR_UI::instance()->video_timeline = NULL;
1199 stop_video_server();
1201 /* Save state before deleting the session, as that causes some
1202 windows to be destroyed before their visible state can be
1205 save_ardour_state ();
1207 close_all_dialogs ();
1210 _session->set_clean ();
1211 _session->remove_pending_capture_state ();
1216 halt_connection.disconnect ();
1217 AudioEngine::instance()->stop ();
1218 #ifdef WINDOWS_VST_SUPPORT
1219 fst_stop_threading();
1225 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1227 ArdourDialog window (_("Unsaved Session"));
1228 Gtk::HBox dhbox; // the hbox for the image and text
1229 Gtk::Label prompt_label;
1230 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1234 assert (actions.size() >= 3);
1236 window.add_button (actions[0], RESPONSE_REJECT);
1237 window.add_button (actions[1], RESPONSE_APPLY);
1238 window.add_button (actions[2], RESPONSE_ACCEPT);
1240 window.set_default_response (RESPONSE_ACCEPT);
1242 Gtk::Button noquit_button (msg);
1243 noquit_button.set_name ("EditorGTKButton");
1247 if (_session->snap_name() == _session->name()) {
1248 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?"),
1249 _session->snap_name());
1251 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?"),
1252 _session->snap_name());
1255 prompt_label.set_text (prompt);
1256 prompt_label.set_name (X_("PrompterLabel"));
1257 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1259 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1260 dhbox.set_homogeneous (false);
1261 dhbox.pack_start (*dimage, false, false, 5);
1262 dhbox.pack_start (prompt_label, true, false, 5);
1263 window.get_vbox()->pack_start (dhbox);
1265 window.set_name (_("Prompter"));
1266 window.set_modal (true);
1267 window.set_resizable (false);
1270 prompt_label.show();
1275 ResponseType r = (ResponseType) window.run();
1280 case RESPONSE_ACCEPT: // save and get out of here
1282 case RESPONSE_APPLY: // get out of here
1293 ARDOUR_UI::every_second ()
1296 update_xrun_count ();
1297 update_buffer_load ();
1298 update_disk_space ();
1299 update_timecode_format ();
1300 update_peak_thread_work ();
1302 if (nsm && nsm->is_active ()) {
1305 if (!_was_dirty && _session->dirty ()) {
1309 else if (_was_dirty && !_session->dirty ()){
1317 ARDOUR_UI::every_point_one_seconds ()
1319 // TODO get rid of this..
1320 // ShuttleControl is updated directly via TransportStateChange signal
1324 ARDOUR_UI::every_point_zero_something_seconds ()
1326 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1328 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1329 float mpeak = editor_meter->update_meters();
1330 if (mpeak > editor_meter_max_peak) {
1331 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1332 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1339 ARDOUR_UI::set_fps_timeout_connection ()
1341 unsigned int interval = 40;
1342 if (!_session) return;
1343 if (_session->timecode_frames_per_second() != 0) {
1344 /* ideally we'll use a select() to sleep and not accumulate
1345 * idle time to provide a regular periodic signal.
1346 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1347 * However, that'll require a dedicated thread and cross-thread
1348 * signals to the GUI Thread..
1350 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1351 * _session->frame_rate() / _session->nominal_frame_rate()
1352 / _session->timecode_frames_per_second()
1354 #ifdef PLATFORM_WINDOWS
1355 // the smallest windows scheduler time-slice is ~15ms.
1356 // periodic GUI timeouts shorter than that will cause
1357 // WaitForSingleObject to spinlock (100% of one CPU Core)
1358 // and gtk never enters idle mode.
1359 // also changing timeBeginPeriod(1) does not affect that in
1360 // any beneficial way, so we just limit the max rate for now.
1361 interval = std::max(30u, interval); // at most ~33Hz.
1363 interval = std::max(8u, interval); // at most 120Hz.
1366 fps_connection.disconnect();
1367 Timers::set_fps_interval (interval);
1371 ARDOUR_UI::update_sample_rate (framecnt_t)
1375 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1377 if (!AudioEngine::instance()->connected()) {
1379 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1383 framecnt_t rate = AudioEngine::instance()->sample_rate();
1386 /* no sample rate available */
1387 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1390 if (fmod (rate, 1000.0) != 0.0) {
1391 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1392 (float) rate / 1000.0f,
1393 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1395 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1397 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1401 sample_rate_label.set_markup (buf);
1405 ARDOUR_UI::update_format ()
1408 format_label.set_text ("");
1413 s << _("File:") << X_(" <span foreground=\"green\">");
1415 switch (_session->config.get_native_file_header_format ()) {
1447 switch (_session->config.get_native_file_data_format ()) {
1461 format_label.set_markup (s.str ());
1465 ARDOUR_UI::update_xrun_count ()
1469 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1470 should also be changed.
1474 const unsigned int x = _session->get_xrun_count ();
1476 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1478 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1481 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1483 xrun_label.set_markup (buf);
1484 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1488 ARDOUR_UI::update_cpu_load ()
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.
1496 double const c = AudioEngine::instance()->get_dsp_load ();
1497 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1498 cpu_load_label.set_markup (buf);
1502 ARDOUR_UI::update_peak_thread_work ()
1505 const int c = SourceFactory::peak_work_queue_length ();
1507 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1508 peak_thread_work_label.set_markup (buf);
1510 peak_thread_work_label.set_markup (X_(""));
1515 ARDOUR_UI::update_buffer_load ()
1519 uint32_t const playback = _session ? _session->playback_load () : 100;
1520 uint32_t const capture = _session ? _session->capture_load () : 100;
1522 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1523 should also be changed.
1529 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1530 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1531 playback <= 5 ? X_("red") : X_("green"),
1533 capture <= 5 ? X_("red") : X_("green"),
1537 buffer_load_label.set_markup (buf);
1539 buffer_load_label.set_text ("");
1544 ARDOUR_UI::count_recenabled_streams (Route& route)
1546 Track* track = dynamic_cast<Track*>(&route);
1547 if (track && track->record_enabled()) {
1548 rec_enabled_streams += track->n_inputs().n_total();
1553 ARDOUR_UI::update_disk_space()
1555 if (_session == 0) {
1559 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1561 framecnt_t fr = _session->frame_rate();
1564 /* skip update - no SR available */
1569 /* Available space is unknown */
1570 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1571 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1572 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1574 rec_enabled_streams = 0;
1575 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1577 framecnt_t frames = opt_frames.get_value_or (0);
1579 if (rec_enabled_streams) {
1580 frames /= rec_enabled_streams;
1587 hrs = frames / (fr * 3600);
1590 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1592 frames -= hrs * fr * 3600;
1593 mins = frames / (fr * 60);
1594 frames -= mins * fr * 60;
1597 bool const low = (hrs == 0 && mins <= 30);
1601 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1602 low ? X_("red") : X_("green"),
1608 disk_space_label.set_markup (buf);
1612 ARDOUR_UI::update_timecode_format ()
1618 TimecodeSlave* tcslave;
1619 SyncSource sync_src = Config->get_sync_source();
1621 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1622 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1627 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1628 matching ? X_("green") : X_("red"),
1629 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1631 snprintf (buf, sizeof (buf), "TC: n/a");
1634 timecode_format_label.set_markup (buf);
1638 ARDOUR_UI::update_wall_clock ()
1642 static int last_min = -1;
1645 tm_now = localtime (&now);
1646 if (last_min != tm_now->tm_min) {
1648 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1649 wall_clock_label.set_text (buf);
1650 last_min = tm_now->tm_min;
1657 ARDOUR_UI::open_recent_session ()
1659 bool can_return = (_session != 0);
1661 SessionDialog recent_session_dialog;
1665 ResponseType r = (ResponseType) recent_session_dialog.run ();
1668 case RESPONSE_ACCEPT:
1672 recent_session_dialog.hide();
1679 recent_session_dialog.hide();
1683 std::string path = recent_session_dialog.session_folder();
1684 std::string state = recent_session_dialog.session_name (should_be_new);
1686 if (should_be_new == true) {
1690 _session_is_new = false;
1692 if (load_session (path, state) == 0) {
1701 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1703 if (!AudioEngine::instance()->connected()) {
1704 MessageDialog msg (parent, string_compose (
1705 _("%1 is not connected to any audio backend.\n"
1706 "You cannot open or close sessions in this condition"),
1708 pop_back_splash (msg);
1716 ARDOUR_UI::open_session ()
1718 if (!check_audioengine(*editor)) {
1722 /* ardour sessions are folders */
1723 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1724 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1725 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1726 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1729 string session_parent_dir = Glib::path_get_dirname(_session->path());
1730 open_session_selector.set_current_folder(session_parent_dir);
1732 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1735 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1737 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1738 string default_session_folder = Config->get_default_session_parent_dir();
1739 open_session_selector.add_shortcut_folder (default_session_folder);
1741 catch (Glib::Error & e) {
1742 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1745 FileFilter session_filter;
1746 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1747 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1748 open_session_selector.add_filter (session_filter);
1749 open_session_selector.set_filter (session_filter);
1751 int response = open_session_selector.run();
1752 open_session_selector.hide ();
1754 if (response == Gtk::RESPONSE_CANCEL) {
1758 string session_path = open_session_selector.get_filename();
1762 if (session_path.length() > 0) {
1763 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1764 _session_is_new = isnew;
1765 load_session (path, name);
1772 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1773 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1775 list<boost::shared_ptr<MidiTrack> > tracks;
1777 if (_session == 0) {
1778 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1783 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1785 if (tracks.size() != how_many) {
1786 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1791 MessageDialog msg (_main_window,
1792 string_compose (_("There are insufficient ports available\n\
1793 to create a new track or bus.\n\
1794 You should save %1, exit and\n\
1795 restart with more ports."), PROGRAM_NAME));
1802 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1804 ChanCount one_midi_channel;
1805 one_midi_channel.set (DataType::MIDI, 1);
1808 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1813 ARDOUR_UI::session_add_audio_route (
1815 int32_t input_channels,
1816 int32_t output_channels,
1817 ARDOUR::TrackMode mode,
1818 RouteGroup* route_group,
1820 string const & name_template
1823 list<boost::shared_ptr<AudioTrack> > tracks;
1826 if (_session == 0) {
1827 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1833 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1835 if (tracks.size() != how_many) {
1836 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1842 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1844 if (routes.size() != how_many) {
1845 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1852 MessageDialog msg (_main_window,
1853 string_compose (_("There are insufficient ports available\n\
1854 to create a new track or bus.\n\
1855 You should save %1, exit and\n\
1856 restart with more ports."), PROGRAM_NAME));
1857 pop_back_splash (msg);
1863 ARDOUR_UI::transport_goto_start ()
1866 _session->goto_start();
1868 /* force displayed area in editor to start no matter
1869 what "follow playhead" setting is.
1873 editor->center_screen (_session->current_start_frame ());
1879 ARDOUR_UI::transport_goto_zero ()
1882 _session->request_locate (0);
1884 /* force displayed area in editor to start no matter
1885 what "follow playhead" setting is.
1889 editor->reset_x_origin (0);
1895 ARDOUR_UI::transport_goto_wallclock ()
1897 if (_session && editor) {
1904 localtime_r (&now, &tmnow);
1906 framecnt_t frame_rate = _session->frame_rate();
1908 if (frame_rate == 0) {
1909 /* no frame rate available */
1913 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1914 frames += tmnow.tm_min * (60 * frame_rate);
1915 frames += tmnow.tm_sec * frame_rate;
1917 _session->request_locate (frames, _session->transport_rolling ());
1919 /* force displayed area in editor to start no matter
1920 what "follow playhead" setting is.
1924 editor->center_screen (frames);
1930 ARDOUR_UI::transport_goto_end ()
1933 framepos_t const frame = _session->current_end_frame();
1934 _session->request_locate (frame);
1936 /* force displayed area in editor to start no matter
1937 what "follow playhead" setting is.
1941 editor->center_screen (frame);
1947 ARDOUR_UI::transport_stop ()
1953 if (_session->is_auditioning()) {
1954 _session->cancel_audition ();
1958 _session->request_stop (false, true);
1961 /** Check if any tracks are record enabled. If none are, record enable all of them.
1962 * @return true if track record-enabled status was changed, false otherwise.
1965 ARDOUR_UI::trx_record_enable_all_tracks ()
1971 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1972 bool none_record_enabled = true;
1974 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1975 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1978 if (t->record_enabled()) {
1979 none_record_enabled = false;
1984 if (none_record_enabled) {
1985 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1988 return none_record_enabled;
1992 ARDOUR_UI::transport_record (bool roll)
1995 switch (_session->record_status()) {
1996 case Session::Disabled:
1997 if (_session->ntracks() == 0) {
1998 MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
2002 if (Profile->get_trx()) {
2003 roll = trx_record_enable_all_tracks ();
2005 _session->maybe_enable_record ();
2010 case Session::Recording:
2012 _session->request_stop();
2014 _session->disable_record (false, true);
2018 case Session::Enabled:
2019 _session->disable_record (false, true);
2025 ARDOUR_UI::transport_roll ()
2031 if (_session->is_auditioning()) {
2036 if (_session->config.get_external_sync()) {
2037 switch (Config->get_sync_source()) {
2041 /* transport controlled by the master */
2047 bool rolling = _session->transport_rolling();
2049 if (_session->get_play_loop()) {
2051 /* If loop playback is not a mode, then we should cancel
2052 it when this action is requested. If it is a mode
2053 we just leave it in place.
2056 if (!Config->get_loop_is_mode()) {
2057 /* XXX it is not possible to just leave seamless loop and keep
2058 playing at present (nov 4th 2009)
2060 if (!Config->get_seamless_loop()) {
2061 /* stop loop playback and stop rolling */
2062 _session->request_play_loop (false, true);
2063 } else if (rolling) {
2064 /* stop loop playback but keep rolling */
2065 _session->request_play_loop (false, false);
2069 } else if (_session->get_play_range () ) {
2070 /* stop playing a range if we currently are */
2071 _session->request_play_range (0, true);
2075 _session->request_transport_speed (1.0f);
2080 ARDOUR_UI::get_smart_mode() const
2082 return ( editor->get_smart_mode() );
2087 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2093 if (_session->is_auditioning()) {
2094 _session->cancel_audition ();
2098 if (_session->config.get_external_sync()) {
2099 switch (Config->get_sync_source()) {
2103 /* transport controlled by the master */
2108 bool rolling = _session->transport_rolling();
2109 bool affect_transport = true;
2111 if (rolling && roll_out_of_bounded_mode) {
2112 /* drop out of loop/range playback but leave transport rolling */
2113 if (_session->get_play_loop()) {
2114 if (_session->actively_recording()) {
2116 /* just stop using the loop, then actually stop
2119 _session->request_play_loop (false, affect_transport);
2122 if (Config->get_seamless_loop()) {
2123 /* the disk buffers contain copies of the loop - we can't
2124 just keep playing, so stop the transport. the user
2125 can restart as they wish.
2127 affect_transport = true;
2129 /* disk buffers are normal, so we can keep playing */
2130 affect_transport = false;
2132 _session->request_play_loop (false, affect_transport);
2134 } else if (_session->get_play_range ()) {
2135 affect_transport = false;
2136 _session->request_play_range (0, true);
2140 if (affect_transport) {
2142 _session->request_stop (with_abort, true);
2144 /* the only external sync condition we can be in here
2145 * would be Engine (JACK) sync, in which case we still
2149 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
2150 _session->request_play_range (&editor->get_selection().time, true);
2151 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2153 _session->request_transport_speed (1.0f);
2159 ARDOUR_UI::toggle_session_auto_loop ()
2165 Location * looploc = _session->locations()->auto_loop_location();
2171 if (_session->get_play_loop()) {
2173 /* looping enabled, our job is to disable it */
2175 _session->request_play_loop (false);
2179 /* looping not enabled, our job is to enable it.
2181 loop-is-NOT-mode: this action always starts the transport rolling.
2182 loop-IS-mode: this action simply sets the loop play mechanism, but
2183 does not start transport.
2185 if (Config->get_loop_is_mode()) {
2186 _session->request_play_loop (true, false);
2188 _session->request_play_loop (true, true);
2192 //show the loop markers
2193 looploc->set_hidden (false, this);
2197 ARDOUR_UI::transport_play_selection ()
2203 editor->play_selection ();
2207 ARDOUR_UI::transport_play_preroll ()
2212 editor->play_with_preroll ();
2216 ARDOUR_UI::transport_rewind (int option)
2218 float current_transport_speed;
2221 current_transport_speed = _session->transport_speed();
2223 if (current_transport_speed >= 0.0f) {
2226 _session->request_transport_speed (-1.0f);
2229 _session->request_transport_speed (-4.0f);
2232 _session->request_transport_speed (-0.5f);
2237 _session->request_transport_speed (current_transport_speed * 1.5f);
2243 ARDOUR_UI::transport_forward (int option)
2249 float current_transport_speed = _session->transport_speed();
2251 if (current_transport_speed <= 0.0f) {
2254 _session->request_transport_speed (1.0f);
2257 _session->request_transport_speed (4.0f);
2260 _session->request_transport_speed (0.5f);
2265 _session->request_transport_speed (current_transport_speed * 1.5f);
2270 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2276 boost::shared_ptr<Route> r;
2278 if ((r = _session->route_by_remote_id (rid)) != 0) {
2280 boost::shared_ptr<Track> t;
2282 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2283 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2289 ARDOUR_UI::map_transport_state ()
2292 auto_loop_button.unset_active_state ();
2293 play_selection_button.unset_active_state ();
2294 roll_button.unset_active_state ();
2295 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2299 shuttle_box->map_transport_state ();
2301 float sp = _session->transport_speed();
2307 if (_session->get_play_range()) {
2309 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2310 roll_button.unset_active_state ();
2311 auto_loop_button.unset_active_state ();
2313 } else if (_session->get_play_loop ()) {
2315 auto_loop_button.set_active (true);
2316 play_selection_button.set_active (false);
2317 if (Config->get_loop_is_mode()) {
2318 roll_button.set_active (true);
2320 roll_button.set_active (false);
2325 roll_button.set_active (true);
2326 play_selection_button.set_active (false);
2327 auto_loop_button.set_active (false);
2330 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2331 /* light up both roll and play-selection if they are joined */
2332 roll_button.set_active (true);
2333 play_selection_button.set_active (true);
2336 stop_button.set_active (false);
2340 stop_button.set_active (true);
2341 roll_button.set_active (false);
2342 play_selection_button.set_active (false);
2343 if (Config->get_loop_is_mode ()) {
2344 auto_loop_button.set_active (_session->get_play_loop());
2346 auto_loop_button.set_active (false);
2348 update_disk_space ();
2353 ARDOUR_UI::blink_handler (bool blink_on)
2355 transport_rec_enable_blink (blink_on);
2356 solo_blink (blink_on);
2357 sync_blink (blink_on);
2358 audition_blink (blink_on);
2359 feedback_blink (blink_on);
2360 error_blink (blink_on);
2364 ARDOUR_UI::update_clocks ()
2366 if (!_session) return;
2368 if (editor && !editor->dragging_playhead()) {
2369 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2374 ARDOUR_UI::start_clocking ()
2376 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2377 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2379 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2384 ARDOUR_UI::stop_clocking ()
2386 clock_signal_connection.disconnect ();
2390 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2394 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2396 label->set_text (buf);
2397 bar->set_fraction (fraction);
2399 /* process events, redraws, etc. */
2401 while (gtk_events_pending()) {
2402 gtk_main_iteration ();
2405 return true; /* continue with save-as */
2409 ARDOUR_UI::save_session_as ()
2415 if (!save_as_dialog) {
2416 save_as_dialog = new SaveAsDialog;
2419 save_as_dialog->set_name (_session->name());
2421 int response = save_as_dialog->run ();
2423 save_as_dialog->hide ();
2426 case Gtk::RESPONSE_OK:
2435 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2436 sa.new_name = save_as_dialog->new_name ();
2437 sa.switch_to = save_as_dialog->switch_to();
2438 sa.copy_media = save_as_dialog->copy_media();
2439 sa.copy_external = save_as_dialog->copy_external();
2440 sa.include_media = save_as_dialog->include_media ();
2442 /* Only bother with a progress dialog if we're going to copy
2443 media into the save-as target. Without that choice, this
2444 will be very fast because we're only talking about a few kB's to
2445 perhaps a couple of MB's of data.
2448 ArdourDialog progress_dialog (_("Save As"), true);
2450 if (sa.include_media && sa.copy_media) {
2453 Gtk::ProgressBar progress_bar;
2455 progress_dialog.get_vbox()->pack_start (label);
2456 progress_dialog.get_vbox()->pack_start (progress_bar);
2458 progress_bar.show ();
2460 /* this signal will be emitted from within this, the calling thread,
2461 * after every file is copied. It provides information on percentage
2462 * complete (in terms of total data to copy), the number of files
2463 * copied so far, and the total number to copy.
2468 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2470 progress_dialog.show_all ();
2471 progress_dialog.present ();
2474 if (_session->save_as (sa)) {
2476 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2480 if (!sa.include_media) {
2481 unload_session (false);
2482 load_session (sa.final_session_folder_name, sa.new_name);
2487 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2491 struct tm local_time;
2494 localtime_r (&n, &local_time);
2495 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2497 save_state (timebuf, switch_to_it);
2502 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2506 prompter.get_result (snapname);
2508 bool do_save = (snapname.length() != 0);
2511 char illegal = Session::session_name_is_legal(snapname);
2513 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2514 "snapshot names may not contain a '%1' character"), illegal));
2520 vector<std::string> p;
2521 get_state_files_in_directory (_session->session_directory().root_path(), p);
2522 vector<string> n = get_file_names_no_extension (p);
2524 if (find (n.begin(), n.end(), snapname) != n.end()) {
2526 do_save = overwrite_file_dialog (prompter,
2527 _("Confirm Snapshot Overwrite"),
2528 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2532 save_state (snapname, switch_to_it);
2542 /** Ask the user for the name of a new snapshot and then take it.
2546 ARDOUR_UI::snapshot_session (bool switch_to_it)
2548 ArdourPrompter prompter (true);
2550 prompter.set_name ("Prompter");
2551 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2553 prompter.set_title (_("Save as..."));
2554 prompter.set_prompt (_("New session name"));
2556 prompter.set_title (_("Take Snapshot"));
2557 prompter.set_prompt (_("Name of new snapshot"));
2561 prompter.set_initial_text (_session->snap_name());
2565 struct tm local_time;
2568 localtime_r (&n, &local_time);
2569 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2570 prompter.set_initial_text (timebuf);
2573 bool finished = false;
2575 switch (prompter.run()) {
2576 case RESPONSE_ACCEPT:
2578 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2589 /** Ask the user for a new session name and then rename the session to it.
2593 ARDOUR_UI::rename_session ()
2599 ArdourPrompter prompter (true);
2602 prompter.set_name ("Prompter");
2603 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2604 prompter.set_title (_("Rename Session"));
2605 prompter.set_prompt (_("New session name"));
2608 switch (prompter.run()) {
2609 case RESPONSE_ACCEPT:
2611 prompter.get_result (name);
2613 bool do_rename = (name.length() != 0);
2616 char illegal = Session::session_name_is_legal (name);
2619 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2620 "session names may not contain a '%1' character"), illegal));
2625 switch (_session->rename (name)) {
2627 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2628 msg.set_position (WIN_POS_MOUSE);
2636 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2637 msg.set_position (WIN_POS_MOUSE);
2653 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2655 if (!_session || _session->deletion_in_progress()) {
2659 XMLNode* node = new XMLNode (X_("UI"));
2661 WM::Manager::instance().add_state (*node);
2663 node->add_child_nocopy (gui_object_state->get_state());
2665 _session->add_extra_xml (*node);
2667 if (export_video_dialog) {
2668 _session->add_extra_xml (export_video_dialog->get_state());
2671 save_state_canfail (name, switch_to_it);
2675 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2680 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2685 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2690 ARDOUR_UI::primary_clock_value_changed ()
2693 _session->request_locate (primary_clock->current_time ());
2698 ARDOUR_UI::big_clock_value_changed ()
2701 _session->request_locate (big_clock->current_time ());
2706 ARDOUR_UI::secondary_clock_value_changed ()
2709 _session->request_locate (secondary_clock->current_time ());
2714 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2716 if (_session == 0) {
2720 if (_session->step_editing()) {
2724 Session::RecordState const r = _session->record_status ();
2725 bool const h = _session->have_rec_enabled_track ();
2727 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2729 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2731 rec_button.set_active_state (Gtkmm2ext::Off);
2733 } else if (r == Session::Recording && h) {
2734 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2736 rec_button.unset_active_state ();
2741 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2745 prompter.get_result (name);
2747 if (name.length()) {
2748 int failed = _session->save_template (name);
2750 if (failed == -2) { /* file already exists. */
2751 bool overwrite = overwrite_file_dialog (prompter,
2752 _("Confirm Template Overwrite"),
2753 _("A template already exists with that name. Do you want to overwrite it?"));
2756 _session->save_template (name, true);
2768 ARDOUR_UI::save_template ()
2770 ArdourPrompter prompter (true);
2772 if (!check_audioengine(*editor)) {
2776 prompter.set_name (X_("Prompter"));
2777 prompter.set_title (_("Save Template"));
2778 prompter.set_prompt (_("Name for template:"));
2779 prompter.set_initial_text(_session->name() + _("-template"));
2780 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2782 bool finished = false;
2784 switch (prompter.run()) {
2785 case RESPONSE_ACCEPT:
2786 finished = process_save_template_prompter (prompter);
2797 ARDOUR_UI::edit_metadata ()
2799 SessionMetadataEditor dialog;
2800 dialog.set_session (_session);
2801 dialog.grab_focus ();
2806 ARDOUR_UI::import_metadata ()
2808 SessionMetadataImporter dialog;
2809 dialog.set_session (_session);
2814 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2816 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2818 MessageDialog msg (str,
2820 Gtk::MESSAGE_WARNING,
2821 Gtk::BUTTONS_YES_NO,
2825 msg.set_name (X_("OpenExistingDialog"));
2826 msg.set_title (_("Open Existing Session"));
2827 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2828 msg.set_position (Gtk::WIN_POS_CENTER);
2829 pop_back_splash (msg);
2831 switch (msg.run()) {
2840 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2842 BusProfile bus_profile;
2844 if (nsm || Profile->get_sae()) {
2846 bus_profile.master_out_channels = 2;
2847 bus_profile.input_ac = AutoConnectPhysical;
2848 bus_profile.output_ac = AutoConnectMaster;
2849 bus_profile.requested_physical_in = 0; // use all available
2850 bus_profile.requested_physical_out = 0; // use all available
2854 /* get settings from advanced section of NSD */
2856 if (sd.create_master_bus()) {
2857 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2859 bus_profile.master_out_channels = 0;
2862 if (sd.connect_inputs()) {
2863 bus_profile.input_ac = AutoConnectPhysical;
2865 bus_profile.input_ac = AutoConnectOption (0);
2868 bus_profile.output_ac = AutoConnectOption (0);
2870 if (sd.connect_outputs ()) {
2871 if (sd.connect_outs_to_master()) {
2872 bus_profile.output_ac = AutoConnectMaster;
2873 } else if (sd.connect_outs_to_physical()) {
2874 bus_profile.output_ac = AutoConnectPhysical;
2878 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2879 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2882 if (build_session (session_path, session_name, bus_profile)) {
2890 ARDOUR_UI::load_from_application_api (const std::string& path)
2892 ARDOUR_COMMAND_LINE::session_name = path;
2893 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2895 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2897 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2898 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2899 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2900 * -> SessionDialog is not displayed
2903 if (_session_dialog) {
2904 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2905 std::string session_path = path;
2906 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2907 session_path = Glib::path_get_dirname (session_path);
2909 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2910 _session_dialog->set_provided_session (session_name, session_path);
2911 _session_dialog->response (RESPONSE_NONE);
2912 _session_dialog->hide();
2917 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2918 /* /path/to/foo => /path/to/foo, foo */
2919 rv = load_session (path, basename_nosuffix (path));
2921 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2922 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2925 // if load_session fails -> pop up SessionDialog.
2927 ARDOUR_COMMAND_LINE::session_name = "";
2929 if (get_session_parameters (true, false)) {
2933 goto_editor_window ();
2937 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2939 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2941 string session_name;
2942 string session_path;
2943 string template_name;
2945 bool likely_new = false;
2946 bool cancel_not_quit;
2948 /* deal with any existing DIRTY session now, rather than later. don't
2949 * treat a non-dirty session this way, so that it stays visible
2950 * as we bring up the new session dialog.
2953 if (_session && ARDOUR_UI::instance()->video_timeline) {
2954 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2957 /* if there is already a session, relabel the button
2958 on the SessionDialog so that we don't Quit directly
2960 cancel_not_quit = (_session != 0);
2962 if (_session && _session->dirty()) {
2963 if (unload_session (false)) {
2964 /* unload cancelled by user */
2967 ARDOUR_COMMAND_LINE::session_name = "";
2970 if (!load_template.empty()) {
2971 should_be_new = true;
2972 template_name = load_template;
2975 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2976 session_path = ARDOUR_COMMAND_LINE::session_name;
2978 if (!session_path.empty()) {
2979 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2980 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2981 /* session/snapshot file, change path to be dir */
2982 session_path = Glib::path_get_dirname (session_path);
2987 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2989 _session_dialog = &session_dialog;
2992 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2994 /* if they named a specific statefile, use it, otherwise they are
2995 just giving a session folder, and we want to use it as is
2996 to find the session.
2999 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3001 if (suffix != string::npos) {
3002 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3003 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3004 session_name = Glib::path_get_basename (session_name);
3006 session_path = ARDOUR_COMMAND_LINE::session_name;
3007 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3012 session_dialog.clear_given ();
3015 if (should_be_new || session_name.empty()) {
3016 /* need the dialog to get info from user */
3018 cerr << "run dialog\n";
3020 switch (session_dialog.run()) {
3021 case RESPONSE_ACCEPT:
3024 /* this is used for async * app->ShouldLoad(). */
3025 continue; // while loop
3028 if (quit_on_cancel) {
3029 // JE - Currently (July 2014) this section can only get reached if the
3030 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3031 // point does NOT indicate an abnormal termination). Therefore, let's
3032 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3034 pthread_cancel_all ();
3042 session_dialog.hide ();
3045 /* if we run the startup dialog again, offer more than just "new session" */
3047 should_be_new = false;
3049 session_name = session_dialog.session_name (likely_new);
3050 session_path = session_dialog.session_folder ();
3056 string::size_type suffix = session_name.find (statefile_suffix);
3058 if (suffix != string::npos) {
3059 session_name = session_name.substr (0, suffix);
3062 /* this shouldn't happen, but we catch it just in case it does */
3064 if (session_name.empty()) {
3068 if (session_dialog.use_session_template()) {
3069 template_name = session_dialog.session_template_name();
3070 _session_is_new = true;
3073 if (session_name[0] == G_DIR_SEPARATOR ||
3074 #ifdef PLATFORM_WINDOWS
3075 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3077 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3078 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3083 /* absolute path or cwd-relative path specified for session name: infer session folder
3084 from what was given.
3087 session_path = Glib::path_get_dirname (session_name);
3088 session_name = Glib::path_get_basename (session_name);
3092 session_path = session_dialog.session_folder();
3094 char illegal = Session::session_name_is_legal (session_name);
3097 MessageDialog msg (session_dialog,
3098 string_compose (_("To ensure compatibility with various systems\n"
3099 "session names may not contain a '%1' character"),
3102 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3107 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3110 if (likely_new && !nsm) {
3112 std::string existing = Glib::build_filename (session_path, session_name);
3114 if (!ask_about_loading_existing_session (existing)) {
3115 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3120 _session_is_new = false;
3125 pop_back_splash (session_dialog);
3126 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3128 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3132 char illegal = Session::session_name_is_legal(session_name);
3135 pop_back_splash (session_dialog);
3136 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3137 "session names may not contain a '%1' character"), illegal));
3139 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3143 _session_is_new = true;
3146 if (likely_new && template_name.empty()) {
3148 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3152 ret = load_session (session_path, session_name, template_name);
3155 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3159 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3160 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3164 /* clear this to avoid endless attempts to load the
3168 ARDOUR_COMMAND_LINE::session_name = "";
3172 _session_dialog = NULL;
3178 ARDOUR_UI::close_session()
3180 if (!check_audioengine(*editor)) {
3184 if (unload_session (true)) {
3188 ARDOUR_COMMAND_LINE::session_name = "";
3190 if (get_session_parameters (true, false)) {
3195 /** @param snap_name Snapshot name (without .ardour suffix).
3196 * @return -2 if the load failed because we are not connected to the AudioEngine.
3199 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3201 Session *new_session;
3206 unload_status = unload_session ();
3208 if (unload_status < 0) {
3210 } else if (unload_status > 0) {
3216 session_loaded = false;
3218 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3221 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3224 /* this one is special */
3226 catch (AudioEngine::PortRegistrationFailure& err) {
3228 MessageDialog msg (err.what(),
3231 Gtk::BUTTONS_CLOSE);
3233 msg.set_title (_("Port Registration Error"));
3234 msg.set_secondary_text (_("Click the Close button to try again."));
3235 msg.set_position (Gtk::WIN_POS_CENTER);
3236 pop_back_splash (msg);
3239 int response = msg.run ();
3244 case RESPONSE_CANCEL:
3251 catch (SessionException e) {
3252 MessageDialog msg (string_compose(
3253 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3254 path, snap_name, e.what()),
3259 msg.set_title (_("Loading Error"));
3260 msg.set_position (Gtk::WIN_POS_CENTER);
3261 pop_back_splash (msg);
3273 MessageDialog msg (string_compose(
3274 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3280 msg.set_title (_("Loading Error"));
3281 msg.set_position (Gtk::WIN_POS_CENTER);
3282 pop_back_splash (msg);
3294 list<string> const u = new_session->unknown_processors ();
3296 MissingPluginDialog d (_session, u);
3301 if (!new_session->writable()) {
3302 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3307 msg.set_title (_("Read-only Session"));
3308 msg.set_position (Gtk::WIN_POS_CENTER);
3309 pop_back_splash (msg);
3316 /* Now the session been created, add the transport controls */
3317 new_session->add_controllable(roll_controllable);
3318 new_session->add_controllable(stop_controllable);
3319 new_session->add_controllable(goto_start_controllable);
3320 new_session->add_controllable(goto_end_controllable);
3321 new_session->add_controllable(auto_loop_controllable);
3322 new_session->add_controllable(play_selection_controllable);
3323 new_session->add_controllable(rec_controllable);
3325 set_session (new_session);
3327 session_loaded = true;
3330 _session->set_clean ();
3333 #ifdef WINDOWS_VST_SUPPORT
3334 fst_stop_threading();
3338 Timers::TimerSuspender t;
3342 #ifdef WINDOWS_VST_SUPPORT
3343 fst_start_threading();
3352 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3354 Session *new_session;
3357 session_loaded = false;
3358 x = unload_session ();
3366 _session_is_new = true;
3369 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3372 catch (SessionException e) {
3374 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3375 msg.set_title (_("Loading Error"));
3376 msg.set_position (Gtk::WIN_POS_CENTER);
3377 pop_back_splash (msg);
3383 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3384 msg.set_title (_("Loading Error"));
3385 msg.set_position (Gtk::WIN_POS_CENTER);
3386 pop_back_splash (msg);
3391 /* Give the new session the default GUI state, if such things exist */
3394 n = Config->instant_xml (X_("Editor"));
3396 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3397 new_session->add_instant_xml (*n, false);
3399 n = Config->instant_xml (X_("Mixer"));
3401 new_session->add_instant_xml (*n, false);
3404 /* Put the playhead at 0 and scroll fully left */
3405 n = new_session->instant_xml (X_("Editor"));
3407 n->add_property (X_("playhead"), X_("0"));
3408 n->add_property (X_("left-frame"), X_("0"));
3411 set_session (new_session);
3413 session_loaded = true;
3415 new_session->save_state(new_session->name());
3421 ARDOUR_UI::launch_chat ()
3423 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3425 dialog.set_title (_("About the Chat"));
3426 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."));
3428 switch (dialog.run()) {
3431 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3432 #elif defined PLATFORM_WINDOWS
3433 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3435 open_uri("http://webchat.freenode.net/?channels=ardour");
3444 ARDOUR_UI::launch_manual ()
3446 PBD::open_uri (Config->get_tutorial_manual_url());
3450 ARDOUR_UI::launch_reference ()
3452 PBD::open_uri (Config->get_reference_manual_url());
3456 ARDOUR_UI::launch_tracker ()
3458 PBD::open_uri ("http://tracker.ardour.org");
3462 ARDOUR_UI::launch_subscribe ()
3464 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3468 ARDOUR_UI::launch_cheat_sheet ()
3471 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3473 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3478 ARDOUR_UI::launch_website ()
3480 PBD::open_uri ("http://ardour.org");
3484 ARDOUR_UI::launch_website_dev ()
3486 PBD::open_uri ("http://ardour.org/development.html");
3490 ARDOUR_UI::launch_forums ()
3492 PBD::open_uri ("https://community.ardour.org/forums");
3496 ARDOUR_UI::launch_howto_report ()
3498 PBD::open_uri ("http://ardour.org/reporting_bugs");
3502 ARDOUR_UI::loading_message (const std::string& msg)
3504 if (ARDOUR_COMMAND_LINE::no_splash) {
3512 splash->message (msg);
3516 ARDOUR_UI::show_splash ()
3520 splash = new Splash;
3530 ARDOUR_UI::hide_splash ()
3537 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3541 removed = rep.paths.size();
3544 MessageDialog msgd (_main_window,
3545 _("No files were ready for clean-up"),
3549 msgd.set_title (_("Clean-up"));
3550 msgd.set_secondary_text (_("If this seems suprising, \n\
3551 check for any existing snapshots.\n\
3552 These may still include regions that\n\
3553 require some unused files to continue to exist."));
3559 ArdourDialog results (_("Clean-up"), true, false);
3561 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3562 CleanupResultsModelColumns() {
3566 Gtk::TreeModelColumn<std::string> visible_name;
3567 Gtk::TreeModelColumn<std::string> fullpath;
3571 CleanupResultsModelColumns results_columns;
3572 Glib::RefPtr<Gtk::ListStore> results_model;
3573 Gtk::TreeView results_display;
3575 results_model = ListStore::create (results_columns);
3576 results_display.set_model (results_model);
3577 results_display.append_column (list_title, results_columns.visible_name);
3579 results_display.set_name ("CleanupResultsList");
3580 results_display.set_headers_visible (true);
3581 results_display.set_headers_clickable (false);
3582 results_display.set_reorderable (false);
3584 Gtk::ScrolledWindow list_scroller;
3587 Gtk::HBox dhbox; // the hbox for the image and text
3588 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3589 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3591 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3593 const string dead_directory = _session->session_directory().dead_path();
3596 %1 - number of files removed
3597 %2 - location of "dead"
3598 %3 - size of files affected
3599 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3602 const char* bprefix;
3603 double space_adjusted = 0;
3605 if (rep.space < 1000) {
3607 space_adjusted = rep.space;
3608 } else if (rep.space < 1000000) {
3609 bprefix = _("kilo");
3610 space_adjusted = floorf((float)rep.space / 1000.0);
3611 } else if (rep.space < 1000000 * 1000) {
3612 bprefix = _("mega");
3613 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3615 bprefix = _("giga");
3616 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3620 txt.set_markup (string_compose (P_("\
3621 The following file was deleted from %2,\n\
3622 releasing %3 %4bytes of disk space", "\
3623 The following %1 files were deleted from %2,\n\
3624 releasing %3 %4bytes of disk space", removed),
3625 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3627 txt.set_markup (string_compose (P_("\
3628 The following file was not in use and \n\
3629 has been moved to: %2\n\n\
3630 After a restart of %5\n\n\
3631 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3632 will release an additional %3 %4bytes of disk space.\n", "\
3633 The following %1 files were not in use and \n\
3634 have been moved to: %2\n\n\
3635 After a restart of %5\n\n\
3636 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3637 will release an additional %3 %4bytes of disk space.\n", removed),
3638 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3641 dhbox.pack_start (*dimage, true, false, 5);
3642 dhbox.pack_start (txt, true, false, 5);
3644 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3645 TreeModel::Row row = *(results_model->append());
3646 row[results_columns.visible_name] = *i;
3647 row[results_columns.fullpath] = *i;
3650 list_scroller.add (results_display);
3651 list_scroller.set_size_request (-1, 150);
3652 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3654 dvbox.pack_start (dhbox, true, false, 5);
3655 dvbox.pack_start (list_scroller, true, false, 5);
3656 ddhbox.pack_start (dvbox, true, false, 5);
3658 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3659 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3660 results.set_default_response (RESPONSE_CLOSE);
3661 results.set_position (Gtk::WIN_POS_MOUSE);
3663 results_display.show();
3664 list_scroller.show();
3671 //results.get_vbox()->show();
3672 results.set_resizable (false);
3679 ARDOUR_UI::cleanup ()
3681 if (_session == 0) {
3682 /* shouldn't happen: menu item is insensitive */
3687 MessageDialog checker (_("Are you sure you want to clean-up?"),
3689 Gtk::MESSAGE_QUESTION,
3692 checker.set_title (_("Clean-up"));
3694 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3695 ALL undo/redo information will be lost if you clean-up.\n\
3696 Clean-up will move all unused files to a \"dead\" location."));
3698 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3699 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3700 checker.set_default_response (RESPONSE_CANCEL);
3702 checker.set_name (_("CleanupDialog"));
3703 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3704 checker.set_position (Gtk::WIN_POS_MOUSE);
3706 switch (checker.run()) {
3707 case RESPONSE_ACCEPT:
3713 ARDOUR::CleanupReport rep;
3715 editor->prepare_for_cleanup ();
3717 /* do not allow flush until a session is reloaded */
3719 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3721 act->set_sensitive (false);
3724 if (_session->cleanup_sources (rep)) {
3725 editor->finish_cleanup ();
3729 editor->finish_cleanup ();
3732 display_cleanup_results (rep, _("Cleaned Files"), false);
3736 ARDOUR_UI::flush_trash ()
3738 if (_session == 0) {
3739 /* shouldn't happen: menu item is insensitive */
3743 ARDOUR::CleanupReport rep;
3745 if (_session->cleanup_trash_sources (rep)) {
3749 display_cleanup_results (rep, _("deleted file"), true);
3753 ARDOUR_UI::cleanup_peakfiles ()
3755 if (_session == 0) {
3756 /* shouldn't happen: menu item is insensitive */
3760 if (! _session->can_cleanup_peakfiles ()) {
3764 // get all region-views in this session
3766 TrackViewList empty;
3768 editor->get_regions_after(rs, (framepos_t) 0, empty);
3769 std::list<RegionView*> views = rs.by_layer();
3771 // remove displayed audio-region-views waveforms
3772 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3773 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3774 if (!arv) { continue ; }
3775 arv->delete_waves();
3778 // cleanup peak files:
3779 // - stop pending peakfile threads
3780 // - close peakfiles if any
3781 // - remove peak dir in session
3782 // - setup peakfiles (background thread)
3783 _session->cleanup_peakfiles ();
3785 // re-add waves to ARV
3786 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3787 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3788 if (!arv) { continue ; }
3789 arv->create_waves();
3794 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3796 uint32_t order_hint = UINT32_MAX;
3798 if (editor->get_selection().tracks.empty()) {
3803 we want the new routes to have their order keys set starting from
3804 the highest order key in the selection + 1 (if available).
3807 if (place == AddRouteDialog::AfterSelection) {
3808 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3810 order_hint = rtav->route()->order_key();
3813 } else if (place == AddRouteDialog::BeforeSelection) {
3814 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3816 order_hint = rtav->route()->order_key();
3818 } else if (place == AddRouteDialog::First) {
3821 /* leave order_hint at UINT32_MAX */
3824 if (order_hint == UINT32_MAX) {
3825 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3826 * not setting an order hint will place new routes last.
3831 _session->set_order_hint (order_hint);
3833 /* create a gap in the existing route order keys to accomodate new routes.*/
3834 boost::shared_ptr <RouteList> rd = _session->get_routes();
3835 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3836 boost::shared_ptr<Route> rt (*ri);
3838 if (rt->is_monitor()) {
3842 if (rt->order_key () >= order_hint) {
3843 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3849 ARDOUR_UI::start_duplicate_routes ()
3851 if (!duplicate_routes_dialog) {
3852 duplicate_routes_dialog = new DuplicateRouteDialog;
3855 if (duplicate_routes_dialog->restart (_session)) {
3859 duplicate_routes_dialog->present ();
3863 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3871 if (add_route_dialog->is_visible()) {
3872 /* we're already doing this */
3876 ResponseType r = (ResponseType) add_route_dialog->run ();
3878 add_route_dialog->hide();
3881 case RESPONSE_ACCEPT:
3888 if ((count = add_route_dialog->count()) <= 0) {
3892 setup_order_hint(add_route_dialog->insert_at());
3894 string template_path = add_route_dialog->track_template();
3895 DisplaySuspender ds;
3897 if (!template_path.empty()) {
3898 if (add_route_dialog->name_template_is_default()) {
3899 _session->new_route_from_template (count, template_path, string());
3901 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3906 ChanCount input_chan= add_route_dialog->channels ();
3907 ChanCount output_chan;
3908 string name_template = add_route_dialog->name_template ();
3909 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3910 RouteGroup* route_group = add_route_dialog->route_group ();
3911 AutoConnectOption oac = Config->get_output_auto_connect();
3913 if (oac & AutoConnectMaster) {
3914 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3915 output_chan.set (DataType::MIDI, 0);
3917 output_chan = input_chan;
3920 /* XXX do something with name template */
3922 switch (add_route_dialog->type_wanted()) {
3923 case AddRouteDialog::AudioTrack:
3924 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3926 case AddRouteDialog::MidiTrack:
3927 session_add_midi_track (route_group, count, name_template, instrument);
3929 case AddRouteDialog::MixedTrack:
3930 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3932 case AddRouteDialog::AudioBus:
3933 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3939 ARDOUR_UI::stop_video_server (bool ask_confirm)
3941 if (!video_server_process && ask_confirm) {
3942 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3944 if (video_server_process) {
3946 ArdourDialog confirm (_("Stop Video-Server"), true);
3947 Label m (_("Do you really want to stop the Video Server?"));
3948 confirm.get_vbox()->pack_start (m, true, true);
3949 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3950 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3951 confirm.show_all ();
3952 if (confirm.run() == RESPONSE_CANCEL) {
3956 delete video_server_process;
3957 video_server_process =0;
3962 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3964 ARDOUR_UI::start_video_server( float_window, true);
3968 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3974 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3975 if (video_server_process) {
3976 popup_error(_("The Video Server is already started."));
3978 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3984 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3986 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3988 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3990 video_server_dialog->set_transient_for (*float_window);
3993 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3994 video_server_dialog->hide();
3996 ResponseType r = (ResponseType) video_server_dialog->run ();
3997 video_server_dialog->hide();
3998 if (r != RESPONSE_ACCEPT) { return false; }
3999 if (video_server_dialog->show_again()) {
4000 Config->set_show_video_server_dialog(false);
4004 std::string icsd_exec = video_server_dialog->get_exec_path();
4005 std::string icsd_docroot = video_server_dialog->get_docroot();
4006 if (icsd_docroot.empty()) {
4007 #ifndef PLATFORM_WINDOWS
4008 icsd_docroot = X_("/");
4010 icsd_docroot = X_("C:\\");
4015 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4016 warning << _("Specified docroot is not an existing directory.") << endmsg;
4019 #ifndef PLATFORM_WINDOWS
4020 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4021 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4022 warning << _("Given Video Server is not an executable file.") << endmsg;
4026 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4027 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4028 warning << _("Given Video Server is not an executable file.") << endmsg;
4034 argp=(char**) calloc(9,sizeof(char*));
4035 argp[0] = strdup(icsd_exec.c_str());
4036 argp[1] = strdup("-P");
4037 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4038 argp[3] = strdup("-p");
4039 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4040 argp[5] = strdup("-C");
4041 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4042 argp[7] = strdup(icsd_docroot.c_str());
4044 stop_video_server();
4046 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4047 Config->set_video_advanced_setup(false);
4049 std::ostringstream osstream;
4050 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4051 Config->set_video_server_url(osstream.str());
4052 Config->set_video_server_docroot(icsd_docroot);
4053 Config->set_video_advanced_setup(true);
4056 if (video_server_process) {
4057 delete video_server_process;
4060 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4061 if (video_server_process->start()) {
4062 warning << _("Cannot launch the video-server") << endmsg;
4065 int timeout = 120; // 6 sec
4066 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4067 Glib::usleep (50000);
4069 if (--timeout <= 0 || !video_server_process->is_running()) break;
4072 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4074 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4075 delete video_server_process;
4076 video_server_process = 0;
4084 ARDOUR_UI::add_video (Gtk::Window* float_window)
4090 if (!start_video_server(float_window, false)) {
4091 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4096 add_video_dialog->set_transient_for (*float_window);
4099 if (add_video_dialog->is_visible()) {
4100 /* we're already doing this */
4104 ResponseType r = (ResponseType) add_video_dialog->run ();
4105 add_video_dialog->hide();
4106 if (r != RESPONSE_ACCEPT) { return; }
4108 bool local_file, orig_local_file;
4109 std::string path = add_video_dialog->file_name(local_file);
4111 std::string orig_path = path;
4112 orig_local_file = local_file;
4114 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4116 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4117 warning << string_compose(_("could not open %1"), path) << endmsg;
4120 if (!local_file && path.length() == 0) {
4121 warning << _("no video-file selected") << endmsg;
4125 std::string audio_from_video;
4126 bool detect_ltc = false;
4128 switch (add_video_dialog->import_option()) {
4129 case VTL_IMPORT_TRANSCODE:
4131 TranscodeVideoDialog *transcode_video_dialog;
4132 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4133 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4134 transcode_video_dialog->hide();
4135 if (r != RESPONSE_ACCEPT) {
4136 delete transcode_video_dialog;
4140 audio_from_video = transcode_video_dialog->get_audiofile();
4142 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4145 else if (!audio_from_video.empty()) {
4146 editor->embed_audio_from_video(
4148 video_timeline->get_offset(),
4149 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4152 switch (transcode_video_dialog->import_option()) {
4153 case VTL_IMPORT_TRANSCODED:
4154 path = transcode_video_dialog->get_filename();
4157 case VTL_IMPORT_REFERENCE:
4160 delete transcode_video_dialog;
4163 delete transcode_video_dialog;
4167 case VTL_IMPORT_NONE:
4171 /* strip _session->session_directory().video_path() from video file if possible */
4172 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4173 path=path.substr(_session->session_directory().video_path().size());
4174 if (path.at(0) == G_DIR_SEPARATOR) {
4175 path=path.substr(1);
4179 video_timeline->set_update_session_fps(auto_set_session_fps);
4181 if (video_timeline->video_file_info(path, local_file)) {
4182 XMLNode* node = new XMLNode(X_("Videotimeline"));
4183 node->add_property (X_("Filename"), path);
4184 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4185 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4186 if (orig_local_file) {
4187 node->add_property (X_("OriginalVideoFile"), orig_path);
4189 node->remove_property (X_("OriginalVideoFile"));
4191 _session->add_extra_xml (*node);
4192 _session->set_dirty ();
4194 if (!audio_from_video.empty() && detect_ltc) {
4195 std::vector<LTCFileReader::LTCMap> ltc_seq;
4198 /* TODO ask user about TV standard (LTC alignment if any) */
4199 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4200 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4202 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4204 /* TODO seek near end of file, and read LTC until end.
4205 * if it fails to find any LTC frames, scan complete file
4207 * calculate drift of LTC compared to video-duration,
4208 * ask user for reference (timecode from start/mid/end)
4211 // LTCFileReader will have written error messages
4214 ::g_unlink(audio_from_video.c_str());
4216 if (ltc_seq.size() == 0) {
4217 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4219 /* the very first TC in the file is somteimes not aligned properly */
4220 int i = ltc_seq.size() -1;
4221 ARDOUR::frameoffset_t video_start_offset =
4222 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4223 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4224 video_timeline->set_offset(video_start_offset);
4228 _session->maybe_update_session_range(
4229 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4230 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4233 if (add_video_dialog->launch_xjadeo() && local_file) {
4234 editor->set_xjadeo_sensitive(true);
4235 editor->toggle_xjadeo_proc(1);
4237 editor->toggle_xjadeo_proc(0);
4239 editor->toggle_ruler_video(true);
4244 ARDOUR_UI::remove_video ()
4246 video_timeline->close_session();
4247 editor->toggle_ruler_video(false);
4250 video_timeline->set_offset_locked(false);
4251 video_timeline->set_offset(0);
4253 /* delete session state */
4254 XMLNode* node = new XMLNode(X_("Videotimeline"));
4255 _session->add_extra_xml(*node);
4256 node = new XMLNode(X_("Videomonitor"));
4257 _session->add_extra_xml(*node);
4258 node = new XMLNode(X_("Videoexport"));
4259 _session->add_extra_xml(*node);
4260 stop_video_server();
4264 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4266 if (localcacheonly) {
4267 video_timeline->vmon_update();
4269 video_timeline->flush_cache();
4271 editor->queue_visual_videotimeline_update();
4275 ARDOUR_UI::export_video (bool range)
4277 if (ARDOUR::Config->get_show_video_export_info()) {
4278 ExportVideoInfobox infobox (_session);
4279 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4280 if (infobox.show_again()) {
4281 ARDOUR::Config->set_show_video_export_info(false);
4284 case GTK_RESPONSE_YES:
4285 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4291 export_video_dialog->set_session (_session);
4292 export_video_dialog->apply_state(editor->get_selection().time, range);
4293 export_video_dialog->run ();
4294 export_video_dialog->hide ();
4298 ARDOUR_UI::mixer_settings () const
4303 node = _session->instant_xml(X_("Mixer"));
4305 node = Config->instant_xml(X_("Mixer"));
4309 node = new XMLNode (X_("Mixer"));
4316 ARDOUR_UI::main_window_settings () const
4321 node = _session->instant_xml(X_("Main"));
4323 node = Config->instant_xml(X_("Main"));
4327 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4328 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4333 node = new XMLNode (X_("Main"));
4340 ARDOUR_UI::editor_settings () const
4345 node = _session->instant_xml(X_("Editor"));
4347 node = Config->instant_xml(X_("Editor"));
4351 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4352 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4357 node = new XMLNode (X_("Editor"));
4364 ARDOUR_UI::keyboard_settings () const
4368 node = Config->extra_xml(X_("Keyboard"));
4371 node = new XMLNode (X_("Keyboard"));
4378 ARDOUR_UI::create_xrun_marker (framepos_t where)
4381 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4382 _session->locations()->add (location);
4387 ARDOUR_UI::halt_on_xrun_message ()
4389 cerr << "HALT on xrun\n";
4390 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4395 ARDOUR_UI::xrun_handler (framepos_t where)
4401 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4403 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4404 create_xrun_marker(where);
4407 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4408 halt_on_xrun_message ();
4413 ARDOUR_UI::disk_overrun_handler ()
4415 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4417 if (!have_disk_speed_dialog_displayed) {
4418 have_disk_speed_dialog_displayed = true;
4419 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4420 The disk system on your computer\n\
4421 was not able to keep up with %1.\n\
4423 Specifically, it failed to write data to disk\n\
4424 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4425 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4431 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4432 static MessageDialog *scan_dlg = NULL;
4433 static ProgressBar *scan_pbar = NULL;
4434 static HBox *scan_tbox = NULL;
4435 static Gtk::Button *scan_timeout_button;
4438 ARDOUR_UI::cancel_plugin_scan ()
4440 PluginManager::instance().cancel_plugin_scan();
4444 ARDOUR_UI::cancel_plugin_timeout ()
4446 PluginManager::instance().cancel_plugin_timeout();
4447 scan_timeout_button->set_sensitive (false);
4451 ARDOUR_UI::plugin_scan_timeout (int timeout)
4453 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4457 scan_pbar->set_sensitive (false);
4458 scan_timeout_button->set_sensitive (true);
4459 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4462 scan_pbar->set_sensitive (false);
4463 scan_timeout_button->set_sensitive (false);
4469 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4471 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4475 const bool cancelled = PluginManager::instance().cancelled();
4476 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4477 if (cancelled && scan_dlg->is_mapped()) {
4482 if (cancelled || !can_cancel) {
4487 static Gtk::Button *cancel_button;
4489 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4490 VBox* vbox = scan_dlg->get_vbox();
4491 vbox->set_size_request(400,-1);
4492 scan_dlg->set_title (_("Scanning for plugins"));
4494 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4495 cancel_button->set_name ("EditorGTKButton");
4496 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4497 cancel_button->show();
4499 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4501 scan_tbox = manage( new HBox() );
4503 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4504 scan_timeout_button->set_name ("EditorGTKButton");
4505 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4506 scan_timeout_button->show();
4508 scan_pbar = manage(new ProgressBar());
4509 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4510 scan_pbar->set_text(_("Scan Timeout"));
4513 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4514 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4516 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4519 assert(scan_dlg && scan_tbox && cancel_button);
4521 if (type == X_("closeme")) {
4525 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4528 if (!can_cancel || !cancelled) {
4529 scan_timeout_button->set_sensitive(false);
4531 cancel_button->set_sensitive(can_cancel && !cancelled);
4537 ARDOUR_UI::gui_idle_handler ()
4540 /* due to idle calls, gtk_events_pending() may always return true */
4541 while (gtk_events_pending() && --timeout) {
4542 gtk_main_iteration ();
4547 ARDOUR_UI::disk_underrun_handler ()
4549 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4551 if (!have_disk_speed_dialog_displayed) {
4552 have_disk_speed_dialog_displayed = true;
4553 MessageDialog* msg = new MessageDialog (
4554 _main_window, string_compose (_("The disk system on your computer\n\
4555 was not able to keep up with %1.\n\
4557 Specifically, it failed to read data from disk\n\
4558 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4559 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4565 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4567 have_disk_speed_dialog_displayed = false;
4572 ARDOUR_UI::session_dialog (std::string msg)
4574 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4578 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4585 ARDOUR_UI::pending_state_dialog ()
4587 HBox* hbox = manage (new HBox());
4588 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4589 ArdourDialog dialog (_("Crash Recovery"), true);
4590 Label message (string_compose (_("\
4591 This session appears to have been in the\n\
4592 middle of recording when %1 or\n\
4593 the computer was shutdown.\n\
4595 %1 can recover any captured audio for\n\
4596 you, or it can ignore it. Please decide\n\
4597 what you would like to do.\n"), PROGRAM_NAME));
4598 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4599 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4600 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4601 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4602 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4603 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4604 dialog.set_default_response (RESPONSE_ACCEPT);
4605 dialog.set_position (WIN_POS_CENTER);
4610 switch (dialog.run ()) {
4611 case RESPONSE_ACCEPT:
4619 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4621 HBox* hbox = new HBox();
4622 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4623 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4624 Label message (string_compose (_("\
4625 This session was created with a sample rate of %1 Hz, but\n\
4626 %2 is currently running at %3 Hz. If you load this session,\n\
4627 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4629 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4630 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4631 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4632 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4633 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4634 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4635 dialog.set_default_response (RESPONSE_ACCEPT);
4636 dialog.set_position (WIN_POS_CENTER);
4641 switch (dialog.run()) {
4642 case RESPONSE_ACCEPT:
4652 ARDOUR_UI::use_config ()
4654 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4656 set_transport_controllable_state (*node);
4661 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4663 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4664 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4666 primary_clock->set (pos);
4669 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4670 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4672 secondary_clock->set (pos);
4675 if (big_clock_window) {
4676 big_clock->set (pos);
4678 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4682 ARDOUR_UI::step_edit_status_change (bool yn)
4684 // XXX should really store pre-step edit status of things
4685 // we make insensitive
4688 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4689 rec_button.set_sensitive (false);
4691 rec_button.unset_active_state ();;
4692 rec_button.set_sensitive (true);
4697 ARDOUR_UI::record_state_changed ()
4699 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4701 if (!_session || !big_clock_window) {
4702 /* why bother - the clock isn't visible */
4706 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4707 big_clock->set_active (true);
4709 big_clock->set_active (false);
4714 ARDOUR_UI::first_idle ()
4717 _session->allow_auto_play (true);
4721 editor->first_idle();
4724 Keyboard::set_can_save_keybindings (true);
4729 ARDOUR_UI::store_clock_modes ()
4731 XMLNode* node = new XMLNode(X_("ClockModes"));
4733 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4734 XMLNode* child = new XMLNode (X_("Clock"));
4736 child->add_property (X_("name"), (*x)->name());
4737 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4738 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4740 node->add_child_nocopy (*child);
4743 _session->add_extra_xml (*node);
4744 _session->set_dirty ();
4747 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4748 : Controllable (name), ui (u), type(tp)
4754 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4757 /* do nothing: these are radio-style actions */
4761 const char *action = 0;
4765 action = X_("Roll");
4768 action = X_("Stop");
4771 action = X_("GotoStart");
4774 action = X_("GotoEnd");
4777 action = X_("Loop");
4780 action = X_("PlaySelection");
4783 action = X_("Record");
4793 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4801 ARDOUR_UI::TransportControllable::get_value (void) const
4828 ARDOUR_UI::setup_profile ()
4830 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4831 Profile->set_small_screen ();
4834 if (g_getenv ("ARDOUR_SAE")) {
4835 Profile->set_sae ();
4836 Profile->set_single_package ();
4839 if (g_getenv ("TRX")) {
4840 Profile->set_trx ();
4843 if (g_getenv ("MIXBUS")) {
4844 Profile->set_mixbus ();
4849 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4851 MissingFileDialog dialog (s, str, type);
4856 int result = dialog.run ();
4863 return 1; // quit entire session load
4866 result = dialog.get_action ();
4872 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4874 AmbiguousFileDialog dialog (file, hits);
4881 return dialog.get_which ();
4884 /** Allocate our thread-local buffers */
4886 ARDOUR_UI::get_process_buffers ()
4888 _process_thread->get_buffers ();
4891 /** Drop our thread-local buffers */
4893 ARDOUR_UI::drop_process_buffers ()
4895 _process_thread->drop_buffers ();
4899 ARDOUR_UI::feedback_detected ()
4901 _feedback_exists = true;
4905 ARDOUR_UI::successful_graph_sort ()
4907 _feedback_exists = false;
4911 ARDOUR_UI::midi_panic ()
4914 _session->midi_panic();
4919 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4921 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4922 const char* end_big = "</span>";
4923 const char* start_mono = "<tt>";
4924 const char* end_mono = "</tt>";
4926 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4927 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4928 "From now on, use the -2000 version with older versions of %3"),
4929 xml_path, backup_path, PROGRAM_NAME,
4931 start_mono, end_mono), true);
4938 ARDOUR_UI::reset_peak_display ()
4940 if (!_session || !_session->master_out() || !editor_meter) return;
4941 editor_meter->clear_meters();
4942 editor_meter_max_peak = -INFINITY;
4943 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4947 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4949 if (!_session || !_session->master_out()) return;
4950 if (group == _session->master_out()->route_group()) {
4951 reset_peak_display ();
4956 ARDOUR_UI::reset_route_peak_display (Route* route)
4958 if (!_session || !_session->master_out()) return;
4959 if (_session->master_out().get() == route) {
4960 reset_peak_display ();
4965 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4967 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4968 audio_midi_setup->set_position (WIN_POS_CENTER);
4973 response = audio_midi_setup->run();
4975 case Gtk::RESPONSE_OK:
4976 if (!AudioEngine::instance()->running()) {
4990 ARDOUR_UI::transport_numpad_timeout ()
4992 _numpad_locate_happening = false;
4993 if (_numpad_timeout_connection.connected() )
4994 _numpad_timeout_connection.disconnect();
4999 ARDOUR_UI::transport_numpad_decimal ()
5001 _numpad_timeout_connection.disconnect();
5003 if (_numpad_locate_happening) {
5004 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5005 _numpad_locate_happening = false;
5007 _pending_locate_num = 0;
5008 _numpad_locate_happening = true;
5009 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5014 ARDOUR_UI::transport_numpad_event (int num)
5016 if ( _numpad_locate_happening ) {
5017 _pending_locate_num = _pending_locate_num*10 + num;
5020 case 0: toggle_roll(false, false); break;
5021 case 1: transport_rewind(1); break;
5022 case 2: transport_forward(1); break;
5023 case 3: transport_record(true); break;
5024 case 4: toggle_session_auto_loop(); break;
5025 case 5: transport_record(false); toggle_session_auto_loop(); break;
5026 case 6: toggle_punch(); break;
5027 case 7: toggle_click(); break;
5028 case 8: toggle_auto_return(); break;
5029 case 9: toggle_follow_edits(); break;
5035 ARDOUR_UI::set_flat_buttons ()
5037 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5041 ARDOUR_UI::audioengine_became_silent ()
5043 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5045 Gtk::MESSAGE_WARNING,
5049 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5051 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5052 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5053 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5054 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5055 Gtk::HBox pay_button_box;
5056 Gtk::HBox subscribe_button_box;
5058 pay_button_box.pack_start (pay_button, true, false);
5059 subscribe_button_box.pack_start (subscribe_button, true, false);
5061 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 */
5063 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5064 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5066 msg.get_vbox()->pack_start (pay_label);
5067 msg.get_vbox()->pack_start (pay_button_box);
5068 msg.get_vbox()->pack_start (subscribe_label);
5069 msg.get_vbox()->pack_start (subscribe_button_box);
5071 msg.get_vbox()->show_all ();
5073 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5074 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5075 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5080 case Gtk::RESPONSE_YES:
5081 AudioEngine::instance()->reset_silence_countdown ();
5084 case Gtk::RESPONSE_NO:
5086 save_state_canfail ("");
5090 case Gtk::RESPONSE_CANCEL:
5092 /* don't reset, save session and exit */
5098 ARDOUR_UI::hide_application ()
5100 Application::instance ()-> hide ();
5104 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5106 /* icons, titles, WM stuff */
5108 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5110 if (window_icons.empty()) {
5111 Glib::RefPtr<Gdk::Pixbuf> icon;
5112 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5113 window_icons.push_back (icon);
5115 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5116 window_icons.push_back (icon);
5118 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5119 window_icons.push_back (icon);
5121 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5122 window_icons.push_back (icon);
5126 if (!window_icons.empty()) {
5127 window.set_default_icon_list (window_icons);
5130 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5132 if (!name.empty()) {
5136 window.set_title (title.get_string());
5137 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5139 window.set_flags (CAN_FOCUS);
5140 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5142 /* This is a hack to ensure that GTK-accelerators continue to
5143 * work. Once we switch over to entirely native bindings, this will be
5144 * unnecessary and should be removed
5146 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5148 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5149 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5150 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5151 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5155 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5157 Gtkmm2ext::Bindings* bindings = 0;
5158 Gtk::Window* window = 0;
5160 /* until we get ardour bindings working, we are not handling key
5164 if (ev->type != GDK_KEY_PRESS) {
5168 if (event_window == &_main_window) {
5170 window = event_window;
5172 /* find current tab contents */
5174 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5176 /* see if it uses the ardour binding system */
5179 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5182 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5184 } else if (event_window != 0) {
5186 window = event_window;
5188 /* see if window uses ardour binding system */
5190 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5193 /* An empty binding set is treated as if it doesn't exist */
5195 if (bindings && bindings->empty()) {
5199 return key_press_focus_accelerator_handler (*window, ev, bindings);
5203 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5205 GtkWindow* win = window.gobj();
5206 GtkWidget* focus = gtk_window_get_focus (win);
5207 bool special_handling_of_unmodified_accelerators = false;
5208 /* consider all relevant modifiers but not LOCK or SHIFT */
5209 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5211 GdkModifierType modifier = GdkModifierType (ev->state);
5212 modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
5213 Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
5217 /* some widget has keyboard focus */
5219 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5221 /* A particular kind of focusable widget currently has keyboard
5222 * focus. All unmodified key events should go to that widget
5223 * first and not be used as an accelerator by default
5226 special_handling_of_unmodified_accelerators = true;
5230 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7\n",
5233 show_gdk_event_state (ev->state),
5234 special_handling_of_unmodified_accelerators,
5235 Keyboard::some_magic_widget_has_focus(),
5237 (focus ? gtk_widget_get_name (focus) : "no focus widget")));
5239 /* This exists to allow us to override the way GTK handles
5240 key events. The normal sequence is:
5242 a) event is delivered to a GtkWindow
5243 b) accelerators/mnemonics are activated
5244 c) if (b) didn't handle the event, propagate to
5245 the focus widget and/or focus chain
5247 The problem with this is that if the accelerators include
5248 keys without modifiers, such as the space bar or the
5249 letter "e", then pressing the key while typing into
5250 a text entry widget results in the accelerator being
5251 activated, instead of the desired letter appearing
5254 There is no good way of fixing this, but this
5255 represents a compromise. The idea is that
5256 key events involving modifiers (not Shift)
5257 get routed into the activation pathway first, then
5258 get propagated to the focus widget if necessary.
5260 If the key event doesn't involve modifiers,
5261 we deliver to the focus widget first, thus allowing
5262 it to get "normal text" without interference
5265 Of course, this can also be problematic: if there
5266 is a widget with focus, then it will swallow
5267 all "normal text" accelerators.
5271 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5273 /* no special handling or there are modifiers in effect: accelerate first */
5275 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5276 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5277 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5279 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5280 KeyboardKey k (ev->state, ev->keyval);
5284 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5286 if (bindings->activate (k, Bindings::Press)) {
5287 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5292 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5294 if (global_bindings->activate (k, Bindings::Press)) {
5295 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5299 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5301 if (gtk_window_propagate_key_event (win, ev)) {
5302 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5308 /* no modifiers, propagate first */
5310 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5312 if (gtk_window_propagate_key_event (win, ev)) {
5313 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5317 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5318 KeyboardKey k (ev->state, ev->keyval);
5322 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5325 if (bindings->activate (k, Bindings::Press)) {
5326 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5332 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5334 if (global_bindings->activate (k, Bindings::Press)) {
5335 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5340 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5345 ARDOUR_UI::load_bindings ()
5347 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5348 error << _("Global keybindings are missing") << endmsg;