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 "binding_owners.h"
115 #include "bundle_manager.h"
116 #include "duplicate_routes_dialog.h"
118 #include "engine_dialog.h"
119 #include "export_video_dialog.h"
120 #include "export_video_infobox.h"
121 #include "gain_meter.h"
122 #include "global_port_matrix.h"
123 #include "gui_object.h"
124 #include "gui_thread.h"
125 #include "keyboard.h"
126 #include "keyeditor.h"
127 #include "location_ui.h"
128 #include "main_clock.h"
129 #include "missing_file_dialog.h"
130 #include "missing_plugin_dialog.h"
131 #include "mixer_ui.h"
132 #include "meterbridge.h"
133 #include "mouse_cursors.h"
136 #include "pingback.h"
137 #include "processor_box.h"
138 #include "prompter.h"
139 #include "public_editor.h"
140 #include "rc_option_editor.h"
141 #include "route_time_axis.h"
142 #include "route_params_ui.h"
143 #include "save_as_dialog.h"
144 #include "session_dialog.h"
145 #include "session_metadata_dialog.h"
146 #include "session_option_editor.h"
147 #include "shuttle_control.h"
148 #include "speaker_dialog.h"
151 #include "theme_manager.h"
152 #include "time_axis_view_item.h"
155 #include "video_server_dialog.h"
156 #include "add_video_dialog.h"
157 #include "transcode_video_dialog.h"
161 using namespace ARDOUR;
162 using namespace ARDOUR_UI_UTILS;
164 using namespace Gtkmm2ext;
167 using namespace Editing;
169 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
171 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
172 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
175 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
177 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
178 "Would you like these files to be copied and used for %1 %2.x?\n\n"
179 "(This will require you to restart %1.)"),
180 PROGRAM_NAME, PROGRAM_VERSION, version),
181 false, /* no markup */
184 true /* modal, though it hardly matters since it is the only window */
187 msg.set_default_response (Gtk::RESPONSE_YES);
190 return (msg.run() == Gtk::RESPONSE_YES);
194 libxml_generic_error_func (void* /* parsing_context*/,
202 vsnprintf (buf, sizeof (buf), msg, ap);
203 error << buf << endmsg;
208 libxml_structured_error_func (void* /* parsing_context*/,
216 replace_all (msg, "\n", "");
218 if (err->file && err->line) {
219 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
222 error << ':' << err->int2;
229 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
232 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
234 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
235 >>>>>>> first compilable version of tabbable design.
236 , session_loaded (false)
237 , gui_object_state (new GUIObjectState)
238 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
239 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
240 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
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 , key_editor (X_("key-editor"), _("Key Bindings"))
274 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
275 , about (X_("about"), _("About"))
276 , location_ui (X_("locations"), _("Locations"))
277 , route_params (X_("inspector"), _("Tracks and Busses"))
278 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
279 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
280 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
281 , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
282 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
283 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
284 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
285 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
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 keybindings are available */
590 if (ARDOUR_COMMAND_LINE::show_key_actions) {
591 vector<string> names;
592 vector<string> paths;
593 vector<string> tooltips;
595 vector<AccelKey> bindings;
597 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
599 vector<string>::iterator n;
600 vector<string>::iterator k;
601 vector<string>::iterator p;
602 for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
603 cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
606 halt_connection.disconnect ();
607 AudioEngine::instance()->stop ();
611 /* this being a GUI and all, we want peakfiles */
613 AudioFileSource::set_build_peakfiles (true);
614 AudioFileSource::set_build_missing_peakfiles (true);
616 /* set default clock modes */
618 if (Profile->get_sae()) {
619 primary_clock->set_mode (AudioClock::BBT);
620 secondary_clock->set_mode (AudioClock::MinSec);
622 primary_clock->set_mode (AudioClock::Timecode);
623 secondary_clock->set_mode (AudioClock::BBT);
626 /* start the time-of-day-clock */
629 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
630 update_wall_clock ();
631 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
636 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
637 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
638 Config->map_parameters (pc);
640 UIConfiguration::instance().map_parameters (pc);
644 ARDOUR_UI::~ARDOUR_UI ()
646 UIConfiguration::instance().save_state();
650 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
651 // don't bother at 'real' exit. the OS cleans up for us.
653 delete primary_clock;
654 delete secondary_clock;
655 delete _process_thread;
660 delete gui_object_state;
661 FastMeter::flush_pattern_cache ();
662 PixFader::flush_pattern_cache ();
666 /* Small trick to flush main-thread event pool.
667 * Other thread-pools are destroyed at pthread_exit(),
668 * but tmain thread termination is too late to trigger Pool::~Pool()
670 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.
671 delete ev->event_pool();
676 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
678 if (Splash::instance()) {
679 Splash::instance()->pop_back_for (win);
684 ARDOUR_UI::configure_timeout ()
686 if (last_configure_time == 0) {
687 /* no configure events yet */
691 /* force a gap of 0.5 seconds since the last configure event
694 if (get_microseconds() - last_configure_time < 500000) {
697 have_configure_timeout = false;
698 save_ardour_state ();
704 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
706 if (have_configure_timeout) {
707 last_configure_time = get_microseconds();
709 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
710 have_configure_timeout = true;
717 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
719 const XMLProperty* prop;
721 if ((prop = node.property ("roll")) != 0) {
722 roll_controllable->set_id (prop->value());
724 if ((prop = node.property ("stop")) != 0) {
725 stop_controllable->set_id (prop->value());
727 if ((prop = node.property ("goto-start")) != 0) {
728 goto_start_controllable->set_id (prop->value());
730 if ((prop = node.property ("goto-end")) != 0) {
731 goto_end_controllable->set_id (prop->value());
733 if ((prop = node.property ("auto-loop")) != 0) {
734 auto_loop_controllable->set_id (prop->value());
736 if ((prop = node.property ("play-selection")) != 0) {
737 play_selection_controllable->set_id (prop->value());
739 if ((prop = node.property ("rec")) != 0) {
740 rec_controllable->set_id (prop->value());
742 if ((prop = node.property ("shuttle")) != 0) {
743 shuttle_box->controllable()->set_id (prop->value());
748 ARDOUR_UI::get_transport_controllable_state ()
750 XMLNode* node = new XMLNode(X_("TransportControllables"));
753 roll_controllable->id().print (buf, sizeof (buf));
754 node->add_property (X_("roll"), buf);
755 stop_controllable->id().print (buf, sizeof (buf));
756 node->add_property (X_("stop"), buf);
757 goto_start_controllable->id().print (buf, sizeof (buf));
758 node->add_property (X_("goto_start"), buf);
759 goto_end_controllable->id().print (buf, sizeof (buf));
760 node->add_property (X_("goto_end"), buf);
761 auto_loop_controllable->id().print (buf, sizeof (buf));
762 node->add_property (X_("auto_loop"), buf);
763 play_selection_controllable->id().print (buf, sizeof (buf));
764 node->add_property (X_("play_selection"), buf);
765 rec_controllable->id().print (buf, sizeof (buf));
766 node->add_property (X_("rec"), buf);
767 shuttle_box->controllable()->id().print (buf, sizeof (buf));
768 node->add_property (X_("shuttle"), buf);
774 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
777 _session->save_state (snapshot_name);
782 ARDOUR_UI::autosave_session ()
784 if (g_main_depth() > 1) {
785 /* inside a recursive main loop,
786 give up because we may not be able to
792 if (!Config->get_periodic_safety_backups()) {
797 _session->maybe_write_autosave();
804 ARDOUR_UI::update_autosave ()
806 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
808 if (_session && _session->dirty()) {
809 if (_autosave_connection.connected()) {
810 _autosave_connection.disconnect();
813 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
814 Config->get_periodic_safety_backup_interval() * 1000);
817 if (_autosave_connection.connected()) {
818 _autosave_connection.disconnect();
824 ARDOUR_UI::check_announcements ()
827 string _annc_filename;
830 _annc_filename = PROGRAM_NAME "_announcements_osx_";
831 #elif defined PLATFORM_WINDOWS
832 _annc_filename = PROGRAM_NAME "_announcements_windows_";
834 _annc_filename = PROGRAM_NAME "_announcements_linux_";
836 _annc_filename.append (VERSIONSTRING);
838 _announce_string = "";
840 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
841 FILE* fin = g_fopen (path.c_str(), "rb");
843 while (!feof (fin)) {
846 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
849 _announce_string.append (tmp, len);
854 pingback (VERSIONSTRING, path);
859 ARDOUR_UI::starting ()
861 Application* app = Application::instance ();
863 bool brand_new_user = ArdourStartup::required ();
865 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
866 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
868 if (ARDOUR_COMMAND_LINE::check_announcements) {
869 check_announcements ();
874 /* we need to create this early because it may need to set the
875 * audio backend end up.
879 audio_midi_setup.get (true);
881 std::cerr << "audio-midi engine setup failed."<< std::endl;
885 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
886 nsm = new NSM_Client;
887 if (!nsm->init (nsm_url)) {
888 /* the ardour executable may have different names:
890 * waf's obj.target for distro versions: eg ardour4, ardourvst4
891 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
892 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
894 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
896 const char *process_name = g_getenv ("ARDOUR_SELF");
897 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
900 // wait for announce reply from nsm server
901 for ( i = 0; i < 5000; ++i) {
905 if (nsm->is_active()) {
910 error << _("NSM server did not announce itself") << endmsg;
913 // wait for open command from nsm server
914 for ( i = 0; i < 5000; ++i) {
917 if (nsm->client_id ()) {
923 error << _("NSM: no client ID provided") << endmsg;
927 if (_session && nsm) {
928 _session->set_nsm_state( nsm->is_active() );
930 error << _("NSM: no session created") << endmsg;
934 // nsm requires these actions disabled
935 vector<string> action_names;
936 action_names.push_back("SaveAs");
937 action_names.push_back("Rename");
938 action_names.push_back("New");
939 action_names.push_back("Open");
940 action_names.push_back("Recent");
941 action_names.push_back("Close");
943 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
944 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
946 act->set_sensitive (false);
953 error << _("NSM: initialization failed") << endmsg;
959 if (brand_new_user) {
960 _initial_verbose_plugin_scan = true;
965 _initial_verbose_plugin_scan = false;
966 switch (s.response ()) {
967 case Gtk::RESPONSE_OK:
974 #ifdef NO_PLUGIN_STATE
976 ARDOUR::RecentSessions rs;
977 ARDOUR::read_recent_sessions (rs);
979 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
981 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
983 /* already used Ardour, have sessions ... warn about plugin state */
985 ArdourDialog d (_("Free/Demo Version Warning"), true);
987 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
988 CheckButton c (_("Don't warn me about this again"));
990 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"),
991 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
992 _("It will not restore OR save any plugin settings"),
993 _("If you load an existing session with plugin settings\n"
994 "they will not be used and will be lost."),
995 _("To get full access to updates without this limitation\n"
996 "consider becoming a subscriber for a low cost every month.")));
997 l.set_justify (JUSTIFY_CENTER);
999 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1001 d.get_vbox()->pack_start (l, true, true);
1002 d.get_vbox()->pack_start (b, false, false, 12);
1003 d.get_vbox()->pack_start (c, false, false, 12);
1005 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1006 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1010 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1012 if (d.run () != RESPONSE_OK) {
1018 /* go get a session */
1020 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1022 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1023 std::cerr << "Cannot get session parameters."<< std::endl;
1030 goto_editor_window ();
1032 WM::Manager::instance().show_visible ();
1034 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1035 * editor window, and we may want stuff to be hidden.
1037 _status_bar_visibility.update ();
1039 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1044 ARDOUR_UI::check_memory_locking ()
1046 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1047 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1051 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1053 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1055 struct rlimit limits;
1057 long pages, page_size;
1059 size_t pages_len=sizeof(pages);
1060 if ((page_size = getpagesize()) < 0 ||
1061 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1063 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1068 ram = (int64_t) pages * (int64_t) page_size;
1071 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1075 if (limits.rlim_cur != RLIM_INFINITY) {
1077 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1081 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1082 "This might cause %1 to run out of memory before your system "
1083 "runs out of memory. \n\n"
1084 "You can view the memory limit with 'ulimit -l', "
1085 "and it is normally controlled by %2"),
1088 X_("/etc/login.conf")
1090 X_(" /etc/security/limits.conf")
1094 msg.set_default_response (RESPONSE_OK);
1096 VBox* vbox = msg.get_vbox();
1098 CheckButton cb (_("Do not show this window again"));
1099 hbox.pack_start (cb, true, false);
1100 vbox->pack_start (hbox);
1105 pop_back_splash (msg);
1109 if (cb.get_active()) {
1110 XMLNode node (X_("no-memory-warning"));
1111 Config->add_instant_xml (node);
1116 #endif // !__APPLE__
1121 ARDOUR_UI::queue_finish ()
1123 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1127 ARDOUR_UI::idle_finish ()
1130 return false; /* do not call again */
1137 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1139 if (_session->dirty()) {
1140 vector<string> actions;
1141 actions.push_back (_("Don't quit"));
1142 actions.push_back (_("Just quit"));
1143 actions.push_back (_("Save and quit"));
1144 switch (ask_about_saving_session(actions)) {
1149 /* use the default name */
1150 if (save_state_canfail ("")) {
1151 /* failed - don't quit */
1152 MessageDialog msg (_main_window,
1153 string_compose (_("\
1154 %1 was unable to save your session.\n\n\
1155 If you still wish to quit, please use the\n\n\
1156 \"Just quit\" option."), PROGRAM_NAME));
1157 pop_back_splash(msg);
1167 second_connection.disconnect ();
1168 point_one_second_connection.disconnect ();
1169 point_zero_something_second_connection.disconnect();
1170 fps_connection.disconnect();
1173 delete ARDOUR_UI::instance()->video_timeline;
1174 ARDOUR_UI::instance()->video_timeline = NULL;
1175 stop_video_server();
1177 /* Save state before deleting the session, as that causes some
1178 windows to be destroyed before their visible state can be
1181 save_ardour_state ();
1183 close_all_dialogs ();
1186 _session->set_clean ();
1187 _session->remove_pending_capture_state ();
1192 halt_connection.disconnect ();
1193 AudioEngine::instance()->stop ();
1194 #ifdef WINDOWS_VST_SUPPORT
1195 fst_stop_threading();
1201 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1203 ArdourDialog window (_("Unsaved Session"));
1204 Gtk::HBox dhbox; // the hbox for the image and text
1205 Gtk::Label prompt_label;
1206 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1210 assert (actions.size() >= 3);
1212 window.add_button (actions[0], RESPONSE_REJECT);
1213 window.add_button (actions[1], RESPONSE_APPLY);
1214 window.add_button (actions[2], RESPONSE_ACCEPT);
1216 window.set_default_response (RESPONSE_ACCEPT);
1218 Gtk::Button noquit_button (msg);
1219 noquit_button.set_name ("EditorGTKButton");
1223 if (_session->snap_name() == _session->name()) {
1224 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?"),
1225 _session->snap_name());
1227 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?"),
1228 _session->snap_name());
1231 prompt_label.set_text (prompt);
1232 prompt_label.set_name (X_("PrompterLabel"));
1233 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1235 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1236 dhbox.set_homogeneous (false);
1237 dhbox.pack_start (*dimage, false, false, 5);
1238 dhbox.pack_start (prompt_label, true, false, 5);
1239 window.get_vbox()->pack_start (dhbox);
1241 window.set_name (_("Prompter"));
1242 window.set_modal (true);
1243 window.set_resizable (false);
1246 prompt_label.show();
1251 ResponseType r = (ResponseType) window.run();
1256 case RESPONSE_ACCEPT: // save and get out of here
1258 case RESPONSE_APPLY: // get out of here
1269 ARDOUR_UI::every_second ()
1272 update_xrun_count ();
1273 update_buffer_load ();
1274 update_disk_space ();
1275 update_timecode_format ();
1276 update_peak_thread_work ();
1278 if (nsm && nsm->is_active ()) {
1281 if (!_was_dirty && _session->dirty ()) {
1285 else if (_was_dirty && !_session->dirty ()){
1293 ARDOUR_UI::every_point_one_seconds ()
1295 // TODO get rid of this..
1296 // ShuttleControl is updated directly via TransportStateChange signal
1300 ARDOUR_UI::every_point_zero_something_seconds ()
1302 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1304 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1305 float mpeak = editor_meter->update_meters();
1306 if (mpeak > editor_meter_max_peak) {
1307 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1308 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1315 ARDOUR_UI::set_fps_timeout_connection ()
1317 unsigned int interval = 40;
1318 if (!_session) return;
1319 if (_session->timecode_frames_per_second() != 0) {
1320 /* ideally we'll use a select() to sleep and not accumulate
1321 * idle time to provide a regular periodic signal.
1322 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1323 * However, that'll require a dedicated thread and cross-thread
1324 * signals to the GUI Thread..
1326 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1327 * _session->frame_rate() / _session->nominal_frame_rate()
1328 / _session->timecode_frames_per_second()
1330 #ifdef PLATFORM_WINDOWS
1331 // the smallest windows scheduler time-slice is ~15ms.
1332 // periodic GUI timeouts shorter than that will cause
1333 // WaitForSingleObject to spinlock (100% of one CPU Core)
1334 // and gtk never enters idle mode.
1335 // also changing timeBeginPeriod(1) does not affect that in
1336 // any beneficial way, so we just limit the max rate for now.
1337 interval = std::max(30u, interval); // at most ~33Hz.
1339 interval = std::max(8u, interval); // at most 120Hz.
1342 fps_connection.disconnect();
1343 Timers::set_fps_interval (interval);
1347 ARDOUR_UI::update_sample_rate (framecnt_t)
1351 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1353 if (!AudioEngine::instance()->connected()) {
1355 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1359 framecnt_t rate = AudioEngine::instance()->sample_rate();
1362 /* no sample rate available */
1363 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1366 if (fmod (rate, 1000.0) != 0.0) {
1367 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1368 (float) rate / 1000.0f,
1369 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1371 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1373 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1377 sample_rate_label.set_markup (buf);
1381 ARDOUR_UI::update_format ()
1384 format_label.set_text ("");
1389 s << _("File:") << X_(" <span foreground=\"green\">");
1391 switch (_session->config.get_native_file_header_format ()) {
1423 switch (_session->config.get_native_file_data_format ()) {
1437 format_label.set_markup (s.str ());
1441 ARDOUR_UI::update_xrun_count ()
1445 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1446 should also be changed.
1450 const unsigned int x = _session->get_xrun_count ();
1452 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1454 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1457 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1459 xrun_label.set_markup (buf);
1460 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1464 ARDOUR_UI::update_cpu_load ()
1468 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1469 should also be changed.
1472 double const c = AudioEngine::instance()->get_dsp_load ();
1473 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1474 cpu_load_label.set_markup (buf);
1478 ARDOUR_UI::update_peak_thread_work ()
1481 const int c = SourceFactory::peak_work_queue_length ();
1483 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1484 peak_thread_work_label.set_markup (buf);
1486 peak_thread_work_label.set_markup (X_(""));
1491 ARDOUR_UI::update_buffer_load ()
1495 uint32_t const playback = _session ? _session->playback_load () : 100;
1496 uint32_t const capture = _session ? _session->capture_load () : 100;
1498 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1499 should also be changed.
1505 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1506 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1507 playback <= 5 ? X_("red") : X_("green"),
1509 capture <= 5 ? X_("red") : X_("green"),
1513 buffer_load_label.set_markup (buf);
1515 buffer_load_label.set_text ("");
1520 ARDOUR_UI::count_recenabled_streams (Route& route)
1522 Track* track = dynamic_cast<Track*>(&route);
1523 if (track && track->record_enabled()) {
1524 rec_enabled_streams += track->n_inputs().n_total();
1529 ARDOUR_UI::update_disk_space()
1531 if (_session == 0) {
1535 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1537 framecnt_t fr = _session->frame_rate();
1540 /* skip update - no SR available */
1545 /* Available space is unknown */
1546 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1547 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1548 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1550 rec_enabled_streams = 0;
1551 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1553 framecnt_t frames = opt_frames.get_value_or (0);
1555 if (rec_enabled_streams) {
1556 frames /= rec_enabled_streams;
1563 hrs = frames / (fr * 3600);
1566 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1568 frames -= hrs * fr * 3600;
1569 mins = frames / (fr * 60);
1570 frames -= mins * fr * 60;
1573 bool const low = (hrs == 0 && mins <= 30);
1577 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1578 low ? X_("red") : X_("green"),
1584 disk_space_label.set_markup (buf);
1588 ARDOUR_UI::update_timecode_format ()
1594 TimecodeSlave* tcslave;
1595 SyncSource sync_src = Config->get_sync_source();
1597 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1598 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1603 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1604 matching ? X_("green") : X_("red"),
1605 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1607 snprintf (buf, sizeof (buf), "TC: n/a");
1610 timecode_format_label.set_markup (buf);
1614 ARDOUR_UI::update_wall_clock ()
1618 static int last_min = -1;
1621 tm_now = localtime (&now);
1622 if (last_min != tm_now->tm_min) {
1624 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1625 wall_clock_label.set_text (buf);
1626 last_min = tm_now->tm_min;
1633 ARDOUR_UI::open_recent_session ()
1635 bool can_return = (_session != 0);
1637 SessionDialog recent_session_dialog;
1641 ResponseType r = (ResponseType) recent_session_dialog.run ();
1644 case RESPONSE_ACCEPT:
1648 recent_session_dialog.hide();
1655 recent_session_dialog.hide();
1659 std::string path = recent_session_dialog.session_folder();
1660 std::string state = recent_session_dialog.session_name (should_be_new);
1662 if (should_be_new == true) {
1666 _session_is_new = false;
1668 if (load_session (path, state) == 0) {
1677 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1679 if (!AudioEngine::instance()->connected()) {
1680 MessageDialog msg (parent, string_compose (
1681 _("%1 is not connected to any audio backend.\n"
1682 "You cannot open or close sessions in this condition"),
1684 pop_back_splash (msg);
1692 ARDOUR_UI::open_session ()
1694 if (!check_audioengine(*editor)) {
1698 /* ardour sessions are folders */
1699 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1700 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1701 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1702 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1705 string session_parent_dir = Glib::path_get_dirname(_session->path());
1706 open_session_selector.set_current_folder(session_parent_dir);
1708 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1711 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1713 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1714 string default_session_folder = Config->get_default_session_parent_dir();
1715 open_session_selector.add_shortcut_folder (default_session_folder);
1717 catch (Glib::Error & e) {
1718 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1721 FileFilter session_filter;
1722 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1723 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1724 open_session_selector.add_filter (session_filter);
1725 open_session_selector.set_filter (session_filter);
1727 int response = open_session_selector.run();
1728 open_session_selector.hide ();
1730 if (response == Gtk::RESPONSE_CANCEL) {
1734 string session_path = open_session_selector.get_filename();
1738 if (session_path.length() > 0) {
1739 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1740 _session_is_new = isnew;
1741 load_session (path, name);
1748 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1749 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1751 list<boost::shared_ptr<MidiTrack> > tracks;
1753 if (_session == 0) {
1754 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1759 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1761 if (tracks.size() != how_many) {
1762 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1767 MessageDialog msg (_main_window,
1768 string_compose (_("There are insufficient ports available\n\
1769 to create a new track or bus.\n\
1770 You should save %1, exit and\n\
1771 restart with more ports."), PROGRAM_NAME));
1778 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1780 ChanCount one_midi_channel;
1781 one_midi_channel.set (DataType::MIDI, 1);
1784 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1789 ARDOUR_UI::session_add_audio_route (
1791 int32_t input_channels,
1792 int32_t output_channels,
1793 ARDOUR::TrackMode mode,
1794 RouteGroup* route_group,
1796 string const & name_template
1799 list<boost::shared_ptr<AudioTrack> > tracks;
1802 if (_session == 0) {
1803 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1809 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1811 if (tracks.size() != how_many) {
1812 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1818 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1820 if (routes.size() != how_many) {
1821 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1828 MessageDialog msg (_main_window,
1829 string_compose (_("There are insufficient ports available\n\
1830 to create a new track or bus.\n\
1831 You should save %1, exit and\n\
1832 restart with more ports."), PROGRAM_NAME));
1833 pop_back_splash (msg);
1839 ARDOUR_UI::transport_goto_start ()
1842 _session->goto_start();
1844 /* force displayed area in editor to start no matter
1845 what "follow playhead" setting is.
1849 editor->center_screen (_session->current_start_frame ());
1855 ARDOUR_UI::transport_goto_zero ()
1858 _session->request_locate (0);
1860 /* force displayed area in editor to start no matter
1861 what "follow playhead" setting is.
1865 editor->reset_x_origin (0);
1871 ARDOUR_UI::transport_goto_wallclock ()
1873 if (_session && editor) {
1880 localtime_r (&now, &tmnow);
1882 framecnt_t frame_rate = _session->frame_rate();
1884 if (frame_rate == 0) {
1885 /* no frame rate available */
1889 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1890 frames += tmnow.tm_min * (60 * frame_rate);
1891 frames += tmnow.tm_sec * frame_rate;
1893 _session->request_locate (frames, _session->transport_rolling ());
1895 /* force displayed area in editor to start no matter
1896 what "follow playhead" setting is.
1900 editor->center_screen (frames);
1906 ARDOUR_UI::transport_goto_end ()
1909 framepos_t const frame = _session->current_end_frame();
1910 _session->request_locate (frame);
1912 /* force displayed area in editor to start no matter
1913 what "follow playhead" setting is.
1917 editor->center_screen (frame);
1923 ARDOUR_UI::transport_stop ()
1929 if (_session->is_auditioning()) {
1930 _session->cancel_audition ();
1934 _session->request_stop (false, true);
1937 /** Check if any tracks are record enabled. If none are, record enable all of them.
1938 * @return true if track record-enabled status was changed, false otherwise.
1941 ARDOUR_UI::trx_record_enable_all_tracks ()
1947 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1948 bool none_record_enabled = true;
1950 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1951 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1954 if (t->record_enabled()) {
1955 none_record_enabled = false;
1960 if (none_record_enabled) {
1961 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1964 return none_record_enabled;
1968 ARDOUR_UI::transport_record (bool roll)
1971 switch (_session->record_status()) {
1972 case Session::Disabled:
1973 if (_session->ntracks() == 0) {
1974 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."));
1978 if (Profile->get_trx()) {
1979 roll = trx_record_enable_all_tracks ();
1981 _session->maybe_enable_record ();
1986 case Session::Recording:
1988 _session->request_stop();
1990 _session->disable_record (false, true);
1994 case Session::Enabled:
1995 _session->disable_record (false, true);
2001 ARDOUR_UI::transport_roll ()
2007 if (_session->is_auditioning()) {
2012 if (_session->config.get_external_sync()) {
2013 switch (Config->get_sync_source()) {
2017 /* transport controlled by the master */
2023 bool rolling = _session->transport_rolling();
2025 if (_session->get_play_loop()) {
2027 /* If loop playback is not a mode, then we should cancel
2028 it when this action is requested. If it is a mode
2029 we just leave it in place.
2032 if (!Config->get_loop_is_mode()) {
2033 /* XXX it is not possible to just leave seamless loop and keep
2034 playing at present (nov 4th 2009)
2036 if (!Config->get_seamless_loop()) {
2037 /* stop loop playback and stop rolling */
2038 _session->request_play_loop (false, true);
2039 } else if (rolling) {
2040 /* stop loop playback but keep rolling */
2041 _session->request_play_loop (false, false);
2045 } else if (_session->get_play_range () ) {
2046 /* stop playing a range if we currently are */
2047 _session->request_play_range (0, true);
2051 _session->request_transport_speed (1.0f);
2056 ARDOUR_UI::get_smart_mode() const
2058 return ( editor->get_smart_mode() );
2063 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2069 if (_session->is_auditioning()) {
2070 _session->cancel_audition ();
2074 if (_session->config.get_external_sync()) {
2075 switch (Config->get_sync_source()) {
2079 /* transport controlled by the master */
2084 bool rolling = _session->transport_rolling();
2085 bool affect_transport = true;
2087 if (rolling && roll_out_of_bounded_mode) {
2088 /* drop out of loop/range playback but leave transport rolling */
2089 if (_session->get_play_loop()) {
2090 if (_session->actively_recording()) {
2092 /* just stop using the loop, then actually stop
2095 _session->request_play_loop (false, affect_transport);
2098 if (Config->get_seamless_loop()) {
2099 /* the disk buffers contain copies of the loop - we can't
2100 just keep playing, so stop the transport. the user
2101 can restart as they wish.
2103 affect_transport = true;
2105 /* disk buffers are normal, so we can keep playing */
2106 affect_transport = false;
2108 _session->request_play_loop (false, affect_transport);
2110 } else if (_session->get_play_range ()) {
2111 affect_transport = false;
2112 _session->request_play_range (0, true);
2116 if (affect_transport) {
2118 _session->request_stop (with_abort, true);
2120 /* the only external sync condition we can be in here
2121 * would be Engine (JACK) sync, in which case we still
2125 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
2126 _session->request_play_range (&editor->get_selection().time, true);
2127 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2129 _session->request_transport_speed (1.0f);
2135 ARDOUR_UI::toggle_session_auto_loop ()
2141 Location * looploc = _session->locations()->auto_loop_location();
2147 if (_session->get_play_loop()) {
2149 /* looping enabled, our job is to disable it */
2151 _session->request_play_loop (false);
2155 /* looping not enabled, our job is to enable it.
2157 loop-is-NOT-mode: this action always starts the transport rolling.
2158 loop-IS-mode: this action simply sets the loop play mechanism, but
2159 does not start transport.
2161 if (Config->get_loop_is_mode()) {
2162 _session->request_play_loop (true, false);
2164 _session->request_play_loop (true, true);
2168 //show the loop markers
2169 looploc->set_hidden (false, this);
2173 ARDOUR_UI::transport_play_selection ()
2179 editor->play_selection ();
2183 ARDOUR_UI::transport_play_preroll ()
2188 editor->play_with_preroll ();
2192 ARDOUR_UI::transport_rewind (int option)
2194 float current_transport_speed;
2197 current_transport_speed = _session->transport_speed();
2199 if (current_transport_speed >= 0.0f) {
2202 _session->request_transport_speed (-1.0f);
2205 _session->request_transport_speed (-4.0f);
2208 _session->request_transport_speed (-0.5f);
2213 _session->request_transport_speed (current_transport_speed * 1.5f);
2219 ARDOUR_UI::transport_forward (int option)
2225 float current_transport_speed = _session->transport_speed();
2227 if (current_transport_speed <= 0.0f) {
2230 _session->request_transport_speed (1.0f);
2233 _session->request_transport_speed (4.0f);
2236 _session->request_transport_speed (0.5f);
2241 _session->request_transport_speed (current_transport_speed * 1.5f);
2246 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2252 boost::shared_ptr<Route> r;
2254 if ((r = _session->route_by_remote_id (rid)) != 0) {
2256 boost::shared_ptr<Track> t;
2258 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2259 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2265 ARDOUR_UI::map_transport_state ()
2268 auto_loop_button.unset_active_state ();
2269 play_selection_button.unset_active_state ();
2270 roll_button.unset_active_state ();
2271 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2275 shuttle_box->map_transport_state ();
2277 float sp = _session->transport_speed();
2283 if (_session->get_play_range()) {
2285 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2286 roll_button.unset_active_state ();
2287 auto_loop_button.unset_active_state ();
2289 } else if (_session->get_play_loop ()) {
2291 auto_loop_button.set_active (true);
2292 play_selection_button.set_active (false);
2293 if (Config->get_loop_is_mode()) {
2294 roll_button.set_active (true);
2296 roll_button.set_active (false);
2301 roll_button.set_active (true);
2302 play_selection_button.set_active (false);
2303 auto_loop_button.set_active (false);
2306 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2307 /* light up both roll and play-selection if they are joined */
2308 roll_button.set_active (true);
2309 play_selection_button.set_active (true);
2312 stop_button.set_active (false);
2316 stop_button.set_active (true);
2317 roll_button.set_active (false);
2318 play_selection_button.set_active (false);
2319 if (Config->get_loop_is_mode ()) {
2320 auto_loop_button.set_active (_session->get_play_loop());
2322 auto_loop_button.set_active (false);
2324 update_disk_space ();
2329 ARDOUR_UI::blink_handler (bool blink_on)
2331 transport_rec_enable_blink (blink_on);
2332 solo_blink (blink_on);
2333 sync_blink (blink_on);
2334 audition_blink (blink_on);
2335 feedback_blink (blink_on);
2336 error_blink (blink_on);
2340 ARDOUR_UI::update_clocks ()
2342 if (!_session) return;
2344 if (editor && !editor->dragging_playhead()) {
2345 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2350 ARDOUR_UI::start_clocking ()
2352 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2353 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2355 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2360 ARDOUR_UI::stop_clocking ()
2362 clock_signal_connection.disconnect ();
2366 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2370 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2372 label->set_text (buf);
2373 bar->set_fraction (fraction);
2375 /* process events, redraws, etc. */
2377 while (gtk_events_pending()) {
2378 gtk_main_iteration ();
2381 return true; /* continue with save-as */
2385 ARDOUR_UI::save_session_as ()
2391 if (!save_as_dialog) {
2392 save_as_dialog = new SaveAsDialog;
2395 save_as_dialog->set_name (_session->name());
2397 int response = save_as_dialog->run ();
2399 save_as_dialog->hide ();
2402 case Gtk::RESPONSE_OK:
2411 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2412 sa.new_name = save_as_dialog->new_name ();
2413 sa.switch_to = save_as_dialog->switch_to();
2414 sa.copy_media = save_as_dialog->copy_media();
2415 sa.copy_external = save_as_dialog->copy_external();
2416 sa.include_media = save_as_dialog->include_media ();
2418 /* Only bother with a progress dialog if we're going to copy
2419 media into the save-as target. Without that choice, this
2420 will be very fast because we're only talking about a few kB's to
2421 perhaps a couple of MB's of data.
2424 ArdourDialog progress_dialog (_("Save As"), true);
2426 if (sa.include_media && sa.copy_media) {
2429 Gtk::ProgressBar progress_bar;
2431 progress_dialog.get_vbox()->pack_start (label);
2432 progress_dialog.get_vbox()->pack_start (progress_bar);
2434 progress_bar.show ();
2436 /* this signal will be emitted from within this, the calling thread,
2437 * after every file is copied. It provides information on percentage
2438 * complete (in terms of total data to copy), the number of files
2439 * copied so far, and the total number to copy.
2444 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2446 progress_dialog.show_all ();
2447 progress_dialog.present ();
2450 if (_session->save_as (sa)) {
2452 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2456 if (!sa.include_media) {
2457 unload_session (false);
2458 load_session (sa.final_session_folder_name, sa.new_name);
2463 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2467 struct tm local_time;
2470 localtime_r (&n, &local_time);
2471 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2473 save_state (timebuf, switch_to_it);
2478 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2482 prompter.get_result (snapname);
2484 bool do_save = (snapname.length() != 0);
2487 char illegal = Session::session_name_is_legal(snapname);
2489 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2490 "snapshot names may not contain a '%1' character"), illegal));
2496 vector<std::string> p;
2497 get_state_files_in_directory (_session->session_directory().root_path(), p);
2498 vector<string> n = get_file_names_no_extension (p);
2500 if (find (n.begin(), n.end(), snapname) != n.end()) {
2502 do_save = overwrite_file_dialog (prompter,
2503 _("Confirm Snapshot Overwrite"),
2504 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2508 save_state (snapname, switch_to_it);
2518 /** Ask the user for the name of a new snapshot and then take it.
2522 ARDOUR_UI::snapshot_session (bool switch_to_it)
2524 ArdourPrompter prompter (true);
2526 prompter.set_name ("Prompter");
2527 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2529 prompter.set_title (_("Save as..."));
2530 prompter.set_prompt (_("New session name"));
2532 prompter.set_title (_("Take Snapshot"));
2533 prompter.set_prompt (_("Name of new snapshot"));
2537 prompter.set_initial_text (_session->snap_name());
2541 struct tm local_time;
2544 localtime_r (&n, &local_time);
2545 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2546 prompter.set_initial_text (timebuf);
2549 bool finished = false;
2551 switch (prompter.run()) {
2552 case RESPONSE_ACCEPT:
2554 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2565 /** Ask the user for a new session name and then rename the session to it.
2569 ARDOUR_UI::rename_session ()
2575 ArdourPrompter prompter (true);
2578 prompter.set_name ("Prompter");
2579 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2580 prompter.set_title (_("Rename Session"));
2581 prompter.set_prompt (_("New session name"));
2584 switch (prompter.run()) {
2585 case RESPONSE_ACCEPT:
2587 prompter.get_result (name);
2589 bool do_rename = (name.length() != 0);
2592 char illegal = Session::session_name_is_legal (name);
2595 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2596 "session names may not contain a '%1' character"), illegal));
2601 switch (_session->rename (name)) {
2603 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2604 msg.set_position (WIN_POS_MOUSE);
2612 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2613 msg.set_position (WIN_POS_MOUSE);
2629 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2631 if (!_session || _session->deletion_in_progress()) {
2635 XMLNode* node = new XMLNode (X_("UI"));
2637 WM::Manager::instance().add_state (*node);
2639 node->add_child_nocopy (gui_object_state->get_state());
2641 _session->add_extra_xml (*node);
2643 if (export_video_dialog) {
2644 _session->add_extra_xml (export_video_dialog->get_state());
2647 save_state_canfail (name, switch_to_it);
2651 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2656 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2661 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2666 ARDOUR_UI::primary_clock_value_changed ()
2669 _session->request_locate (primary_clock->current_time ());
2674 ARDOUR_UI::big_clock_value_changed ()
2677 _session->request_locate (big_clock->current_time ());
2682 ARDOUR_UI::secondary_clock_value_changed ()
2685 _session->request_locate (secondary_clock->current_time ());
2690 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2692 if (_session == 0) {
2696 if (_session->step_editing()) {
2700 Session::RecordState const r = _session->record_status ();
2701 bool const h = _session->have_rec_enabled_track ();
2703 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2705 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2707 rec_button.set_active_state (Gtkmm2ext::Off);
2709 } else if (r == Session::Recording && h) {
2710 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2712 rec_button.unset_active_state ();
2717 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2721 prompter.get_result (name);
2723 if (name.length()) {
2724 int failed = _session->save_template (name);
2726 if (failed == -2) { /* file already exists. */
2727 bool overwrite = overwrite_file_dialog (prompter,
2728 _("Confirm Template Overwrite"),
2729 _("A template already exists with that name. Do you want to overwrite it?"));
2732 _session->save_template (name, true);
2744 ARDOUR_UI::save_template ()
2746 ArdourPrompter prompter (true);
2748 if (!check_audioengine(*editor)) {
2752 prompter.set_name (X_("Prompter"));
2753 prompter.set_title (_("Save Template"));
2754 prompter.set_prompt (_("Name for template:"));
2755 prompter.set_initial_text(_session->name() + _("-template"));
2756 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2758 bool finished = false;
2760 switch (prompter.run()) {
2761 case RESPONSE_ACCEPT:
2762 finished = process_save_template_prompter (prompter);
2773 ARDOUR_UI::edit_metadata ()
2775 SessionMetadataEditor dialog;
2776 dialog.set_session (_session);
2777 dialog.grab_focus ();
2782 ARDOUR_UI::import_metadata ()
2784 SessionMetadataImporter dialog;
2785 dialog.set_session (_session);
2790 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2792 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2794 MessageDialog msg (str,
2796 Gtk::MESSAGE_WARNING,
2797 Gtk::BUTTONS_YES_NO,
2801 msg.set_name (X_("OpenExistingDialog"));
2802 msg.set_title (_("Open Existing Session"));
2803 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2804 msg.set_position (Gtk::WIN_POS_CENTER);
2805 pop_back_splash (msg);
2807 switch (msg.run()) {
2816 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2818 BusProfile bus_profile;
2820 if (nsm || Profile->get_sae()) {
2822 bus_profile.master_out_channels = 2;
2823 bus_profile.input_ac = AutoConnectPhysical;
2824 bus_profile.output_ac = AutoConnectMaster;
2825 bus_profile.requested_physical_in = 0; // use all available
2826 bus_profile.requested_physical_out = 0; // use all available
2830 /* get settings from advanced section of NSD */
2832 if (sd.create_master_bus()) {
2833 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2835 bus_profile.master_out_channels = 0;
2838 if (sd.connect_inputs()) {
2839 bus_profile.input_ac = AutoConnectPhysical;
2841 bus_profile.input_ac = AutoConnectOption (0);
2844 bus_profile.output_ac = AutoConnectOption (0);
2846 if (sd.connect_outputs ()) {
2847 if (sd.connect_outs_to_master()) {
2848 bus_profile.output_ac = AutoConnectMaster;
2849 } else if (sd.connect_outs_to_physical()) {
2850 bus_profile.output_ac = AutoConnectPhysical;
2854 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2855 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2858 if (build_session (session_path, session_name, bus_profile)) {
2866 ARDOUR_UI::load_from_application_api (const std::string& path)
2868 ARDOUR_COMMAND_LINE::session_name = path;
2869 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2871 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2873 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2874 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2875 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2876 * -> SessionDialog is not displayed
2879 if (_session_dialog) {
2880 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2881 std::string session_path = path;
2882 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2883 session_path = Glib::path_get_dirname (session_path);
2885 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2886 _session_dialog->set_provided_session (session_name, session_path);
2887 _session_dialog->response (RESPONSE_NONE);
2888 _session_dialog->hide();
2893 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2894 /* /path/to/foo => /path/to/foo, foo */
2895 rv = load_session (path, basename_nosuffix (path));
2897 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2898 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2901 // if load_session fails -> pop up SessionDialog.
2903 ARDOUR_COMMAND_LINE::session_name = "";
2905 if (get_session_parameters (true, false)) {
2909 goto_editor_window ();
2913 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2915 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2917 string session_name;
2918 string session_path;
2919 string template_name;
2921 bool likely_new = false;
2922 bool cancel_not_quit;
2924 /* deal with any existing DIRTY session now, rather than later. don't
2925 * treat a non-dirty session this way, so that it stays visible
2926 * as we bring up the new session dialog.
2929 if (_session && ARDOUR_UI::instance()->video_timeline) {
2930 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2933 /* if there is already a session, relabel the button
2934 on the SessionDialog so that we don't Quit directly
2936 cancel_not_quit = (_session != 0);
2938 if (_session && _session->dirty()) {
2939 if (unload_session (false)) {
2940 /* unload cancelled by user */
2943 ARDOUR_COMMAND_LINE::session_name = "";
2946 if (!load_template.empty()) {
2947 should_be_new = true;
2948 template_name = load_template;
2951 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2952 session_path = ARDOUR_COMMAND_LINE::session_name;
2954 if (!session_path.empty()) {
2955 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2956 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2957 /* session/snapshot file, change path to be dir */
2958 session_path = Glib::path_get_dirname (session_path);
2963 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2965 _session_dialog = &session_dialog;
2968 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2970 /* if they named a specific statefile, use it, otherwise they are
2971 just giving a session folder, and we want to use it as is
2972 to find the session.
2975 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2977 if (suffix != string::npos) {
2978 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2979 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2980 session_name = Glib::path_get_basename (session_name);
2982 session_path = ARDOUR_COMMAND_LINE::session_name;
2983 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2988 session_dialog.clear_given ();
2991 if (should_be_new || session_name.empty()) {
2992 /* need the dialog to get info from user */
2994 cerr << "run dialog\n";
2996 switch (session_dialog.run()) {
2997 case RESPONSE_ACCEPT:
3000 /* this is used for async * app->ShouldLoad(). */
3001 continue; // while loop
3004 if (quit_on_cancel) {
3005 // JE - Currently (July 2014) this section can only get reached if the
3006 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3007 // point does NOT indicate an abnormal termination). Therefore, let's
3008 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3010 pthread_cancel_all ();
3018 session_dialog.hide ();
3021 /* if we run the startup dialog again, offer more than just "new session" */
3023 should_be_new = false;
3025 session_name = session_dialog.session_name (likely_new);
3026 session_path = session_dialog.session_folder ();
3032 string::size_type suffix = session_name.find (statefile_suffix);
3034 if (suffix != string::npos) {
3035 session_name = session_name.substr (0, suffix);
3038 /* this shouldn't happen, but we catch it just in case it does */
3040 if (session_name.empty()) {
3044 if (session_dialog.use_session_template()) {
3045 template_name = session_dialog.session_template_name();
3046 _session_is_new = true;
3049 if (session_name[0] == G_DIR_SEPARATOR ||
3050 #ifdef PLATFORM_WINDOWS
3051 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3053 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3054 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3059 /* absolute path or cwd-relative path specified for session name: infer session folder
3060 from what was given.
3063 session_path = Glib::path_get_dirname (session_name);
3064 session_name = Glib::path_get_basename (session_name);
3068 session_path = session_dialog.session_folder();
3070 char illegal = Session::session_name_is_legal (session_name);
3073 MessageDialog msg (session_dialog,
3074 string_compose (_("To ensure compatibility with various systems\n"
3075 "session names may not contain a '%1' character"),
3078 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3083 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3086 if (likely_new && !nsm) {
3088 std::string existing = Glib::build_filename (session_path, session_name);
3090 if (!ask_about_loading_existing_session (existing)) {
3091 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3096 _session_is_new = false;
3101 pop_back_splash (session_dialog);
3102 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3104 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3108 char illegal = Session::session_name_is_legal(session_name);
3111 pop_back_splash (session_dialog);
3112 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3113 "session names may not contain a '%1' character"), illegal));
3115 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3119 _session_is_new = true;
3122 if (likely_new && template_name.empty()) {
3124 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3128 ret = load_session (session_path, session_name, template_name);
3131 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3135 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3136 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3140 /* clear this to avoid endless attempts to load the
3144 ARDOUR_COMMAND_LINE::session_name = "";
3148 _session_dialog = NULL;
3154 ARDOUR_UI::close_session()
3156 if (!check_audioengine(*editor)) {
3160 if (unload_session (true)) {
3164 ARDOUR_COMMAND_LINE::session_name = "";
3166 if (get_session_parameters (true, false)) {
3170 goto_editor_window ();
3173 /** @param snap_name Snapshot name (without .ardour suffix).
3174 * @return -2 if the load failed because we are not connected to the AudioEngine.
3177 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3179 Session *new_session;
3184 unload_status = unload_session ();
3186 if (unload_status < 0) {
3188 } else if (unload_status > 0) {
3194 session_loaded = false;
3196 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3199 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3202 /* this one is special */
3204 catch (AudioEngine::PortRegistrationFailure& err) {
3206 MessageDialog msg (err.what(),
3209 Gtk::BUTTONS_CLOSE);
3211 msg.set_title (_("Port Registration Error"));
3212 msg.set_secondary_text (_("Click the Close button to try again."));
3213 msg.set_position (Gtk::WIN_POS_CENTER);
3214 pop_back_splash (msg);
3217 int response = msg.run ();
3222 case RESPONSE_CANCEL:
3229 catch (SessionException e) {
3230 MessageDialog msg (string_compose(
3231 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3232 path, snap_name, e.what()),
3237 msg.set_title (_("Loading Error"));
3238 msg.set_position (Gtk::WIN_POS_CENTER);
3239 pop_back_splash (msg);
3251 MessageDialog msg (string_compose(
3252 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3258 msg.set_title (_("Loading Error"));
3259 msg.set_position (Gtk::WIN_POS_CENTER);
3260 pop_back_splash (msg);
3272 list<string> const u = new_session->unknown_processors ();
3274 MissingPluginDialog d (_session, u);
3279 if (!new_session->writable()) {
3280 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3285 msg.set_title (_("Read-only Session"));
3286 msg.set_position (Gtk::WIN_POS_CENTER);
3287 pop_back_splash (msg);
3294 /* Now the session been created, add the transport controls */
3295 new_session->add_controllable(roll_controllable);
3296 new_session->add_controllable(stop_controllable);
3297 new_session->add_controllable(goto_start_controllable);
3298 new_session->add_controllable(goto_end_controllable);
3299 new_session->add_controllable(auto_loop_controllable);
3300 new_session->add_controllable(play_selection_controllable);
3301 new_session->add_controllable(rec_controllable);
3303 set_session (new_session);
3305 session_loaded = true;
3307 goto_editor_window ();
3310 _session->set_clean ();
3313 #ifdef WINDOWS_VST_SUPPORT
3314 fst_stop_threading();
3318 Timers::TimerSuspender t;
3322 #ifdef WINDOWS_VST_SUPPORT
3323 fst_start_threading();
3332 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3334 Session *new_session;
3337 session_loaded = false;
3338 x = unload_session ();
3346 _session_is_new = true;
3349 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3352 catch (SessionException e) {
3354 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3355 msg.set_title (_("Loading Error"));
3356 msg.set_position (Gtk::WIN_POS_CENTER);
3357 pop_back_splash (msg);
3363 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3364 msg.set_title (_("Loading Error"));
3365 msg.set_position (Gtk::WIN_POS_CENTER);
3366 pop_back_splash (msg);
3371 /* Give the new session the default GUI state, if such things exist */
3374 n = Config->instant_xml (X_("Editor"));
3376 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3377 new_session->add_instant_xml (*n, false);
3379 n = Config->instant_xml (X_("Mixer"));
3381 new_session->add_instant_xml (*n, false);
3384 /* Put the playhead at 0 and scroll fully left */
3385 n = new_session->instant_xml (X_("Editor"));
3387 n->add_property (X_("playhead"), X_("0"));
3388 n->add_property (X_("left-frame"), X_("0"));
3391 set_session (new_session);
3393 session_loaded = true;
3395 new_session->save_state(new_session->name());
3401 ARDOUR_UI::launch_chat ()
3403 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3405 dialog.set_title (_("About the Chat"));
3406 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."));
3408 switch (dialog.run()) {
3411 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3412 #elif defined PLATFORM_WINDOWS
3413 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3415 open_uri("http://webchat.freenode.net/?channels=ardour");
3424 ARDOUR_UI::launch_manual ()
3426 PBD::open_uri (Config->get_tutorial_manual_url());
3430 ARDOUR_UI::launch_reference ()
3432 PBD::open_uri (Config->get_reference_manual_url());
3436 ARDOUR_UI::launch_tracker ()
3438 PBD::open_uri ("http://tracker.ardour.org");
3442 ARDOUR_UI::launch_subscribe ()
3444 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3448 ARDOUR_UI::launch_cheat_sheet ()
3451 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3453 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3458 ARDOUR_UI::launch_website ()
3460 PBD::open_uri ("http://ardour.org");
3464 ARDOUR_UI::launch_website_dev ()
3466 PBD::open_uri ("http://ardour.org/development.html");
3470 ARDOUR_UI::launch_forums ()
3472 PBD::open_uri ("https://community.ardour.org/forums");
3476 ARDOUR_UI::launch_howto_report ()
3478 PBD::open_uri ("http://ardour.org/reporting_bugs");
3482 ARDOUR_UI::loading_message (const std::string& msg)
3484 if (ARDOUR_COMMAND_LINE::no_splash) {
3492 splash->message (msg);
3496 ARDOUR_UI::show_splash ()
3500 splash = new Splash;
3510 ARDOUR_UI::hide_splash ()
3517 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3521 removed = rep.paths.size();
3524 MessageDialog msgd (_main_window,
3525 _("No files were ready for clean-up"),
3529 msgd.set_title (_("Clean-up"));
3530 msgd.set_secondary_text (_("If this seems suprising, \n\
3531 check for any existing snapshots.\n\
3532 These may still include regions that\n\
3533 require some unused files to continue to exist."));
3539 ArdourDialog results (_("Clean-up"), true, false);
3541 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3542 CleanupResultsModelColumns() {
3546 Gtk::TreeModelColumn<std::string> visible_name;
3547 Gtk::TreeModelColumn<std::string> fullpath;
3551 CleanupResultsModelColumns results_columns;
3552 Glib::RefPtr<Gtk::ListStore> results_model;
3553 Gtk::TreeView results_display;
3555 results_model = ListStore::create (results_columns);
3556 results_display.set_model (results_model);
3557 results_display.append_column (list_title, results_columns.visible_name);
3559 results_display.set_name ("CleanupResultsList");
3560 results_display.set_headers_visible (true);
3561 results_display.set_headers_clickable (false);
3562 results_display.set_reorderable (false);
3564 Gtk::ScrolledWindow list_scroller;
3567 Gtk::HBox dhbox; // the hbox for the image and text
3568 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3569 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3571 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3573 const string dead_directory = _session->session_directory().dead_path();
3576 %1 - number of files removed
3577 %2 - location of "dead"
3578 %3 - size of files affected
3579 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3582 const char* bprefix;
3583 double space_adjusted = 0;
3585 if (rep.space < 1000) {
3587 space_adjusted = rep.space;
3588 } else if (rep.space < 1000000) {
3589 bprefix = _("kilo");
3590 space_adjusted = floorf((float)rep.space / 1000.0);
3591 } else if (rep.space < 1000000 * 1000) {
3592 bprefix = _("mega");
3593 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3595 bprefix = _("giga");
3596 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3600 txt.set_markup (string_compose (P_("\
3601 The following file was deleted from %2,\n\
3602 releasing %3 %4bytes of disk space", "\
3603 The following %1 files were deleted from %2,\n\
3604 releasing %3 %4bytes of disk space", removed),
3605 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3607 txt.set_markup (string_compose (P_("\
3608 The following file was not in use and \n\
3609 has been moved to: %2\n\n\
3610 After a restart of %5\n\n\
3611 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3612 will release an additional %3 %4bytes of disk space.\n", "\
3613 The following %1 files were not in use and \n\
3614 have been moved to: %2\n\n\
3615 After a restart of %5\n\n\
3616 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3617 will release an additional %3 %4bytes of disk space.\n", removed),
3618 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3621 dhbox.pack_start (*dimage, true, false, 5);
3622 dhbox.pack_start (txt, true, false, 5);
3624 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3625 TreeModel::Row row = *(results_model->append());
3626 row[results_columns.visible_name] = *i;
3627 row[results_columns.fullpath] = *i;
3630 list_scroller.add (results_display);
3631 list_scroller.set_size_request (-1, 150);
3632 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3634 dvbox.pack_start (dhbox, true, false, 5);
3635 dvbox.pack_start (list_scroller, true, false, 5);
3636 ddhbox.pack_start (dvbox, true, false, 5);
3638 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3639 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3640 results.set_default_response (RESPONSE_CLOSE);
3641 results.set_position (Gtk::WIN_POS_MOUSE);
3643 results_display.show();
3644 list_scroller.show();
3651 //results.get_vbox()->show();
3652 results.set_resizable (false);
3659 ARDOUR_UI::cleanup ()
3661 if (_session == 0) {
3662 /* shouldn't happen: menu item is insensitive */
3667 MessageDialog checker (_("Are you sure you want to clean-up?"),
3669 Gtk::MESSAGE_QUESTION,
3672 checker.set_title (_("Clean-up"));
3674 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3675 ALL undo/redo information will be lost if you clean-up.\n\
3676 Clean-up will move all unused files to a \"dead\" location."));
3678 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3679 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3680 checker.set_default_response (RESPONSE_CANCEL);
3682 checker.set_name (_("CleanupDialog"));
3683 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3684 checker.set_position (Gtk::WIN_POS_MOUSE);
3686 switch (checker.run()) {
3687 case RESPONSE_ACCEPT:
3693 ARDOUR::CleanupReport rep;
3695 editor->prepare_for_cleanup ();
3697 /* do not allow flush until a session is reloaded */
3699 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3701 act->set_sensitive (false);
3704 if (_session->cleanup_sources (rep)) {
3705 editor->finish_cleanup ();
3709 editor->finish_cleanup ();
3712 display_cleanup_results (rep, _("Cleaned Files"), false);
3716 ARDOUR_UI::flush_trash ()
3718 if (_session == 0) {
3719 /* shouldn't happen: menu item is insensitive */
3723 ARDOUR::CleanupReport rep;
3725 if (_session->cleanup_trash_sources (rep)) {
3729 display_cleanup_results (rep, _("deleted file"), true);
3733 ARDOUR_UI::cleanup_peakfiles ()
3735 if (_session == 0) {
3736 /* shouldn't happen: menu item is insensitive */
3740 if (! _session->can_cleanup_peakfiles ()) {
3744 // get all region-views in this session
3746 TrackViewList empty;
3748 editor->get_regions_after(rs, (framepos_t) 0, empty);
3749 std::list<RegionView*> views = rs.by_layer();
3751 // remove displayed audio-region-views waveforms
3752 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3753 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3754 if (!arv) { continue ; }
3755 arv->delete_waves();
3758 // cleanup peak files:
3759 // - stop pending peakfile threads
3760 // - close peakfiles if any
3761 // - remove peak dir in session
3762 // - setup peakfiles (background thread)
3763 _session->cleanup_peakfiles ();
3765 // re-add waves to ARV
3766 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3767 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3768 if (!arv) { continue ; }
3769 arv->create_waves();
3774 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3776 uint32_t order_hint = UINT32_MAX;
3778 if (editor->get_selection().tracks.empty()) {
3783 we want the new routes to have their order keys set starting from
3784 the highest order key in the selection + 1 (if available).
3787 if (place == AddRouteDialog::AfterSelection) {
3788 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3790 order_hint = rtav->route()->order_key();
3793 } else if (place == AddRouteDialog::BeforeSelection) {
3794 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3796 order_hint = rtav->route()->order_key();
3798 } else if (place == AddRouteDialog::First) {
3801 /* leave order_hint at UINT32_MAX */
3804 if (order_hint == UINT32_MAX) {
3805 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3806 * not setting an order hint will place new routes last.
3811 _session->set_order_hint (order_hint);
3813 /* create a gap in the existing route order keys to accomodate new routes.*/
3814 boost::shared_ptr <RouteList> rd = _session->get_routes();
3815 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3816 boost::shared_ptr<Route> rt (*ri);
3818 if (rt->is_monitor()) {
3822 if (rt->order_key () >= order_hint) {
3823 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3829 ARDOUR_UI::start_duplicate_routes ()
3831 if (!duplicate_routes_dialog) {
3832 duplicate_routes_dialog = new DuplicateRouteDialog;
3835 if (duplicate_routes_dialog->restart (_session)) {
3839 duplicate_routes_dialog->present ();
3843 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3851 if (add_route_dialog->is_visible()) {
3852 /* we're already doing this */
3856 ResponseType r = (ResponseType) add_route_dialog->run ();
3858 add_route_dialog->hide();
3861 case RESPONSE_ACCEPT:
3868 if ((count = add_route_dialog->count()) <= 0) {
3872 setup_order_hint(add_route_dialog->insert_at());
3874 string template_path = add_route_dialog->track_template();
3875 DisplaySuspender ds;
3877 if (!template_path.empty()) {
3878 if (add_route_dialog->name_template_is_default()) {
3879 _session->new_route_from_template (count, template_path, string());
3881 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3886 ChanCount input_chan= add_route_dialog->channels ();
3887 ChanCount output_chan;
3888 string name_template = add_route_dialog->name_template ();
3889 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3890 RouteGroup* route_group = add_route_dialog->route_group ();
3891 AutoConnectOption oac = Config->get_output_auto_connect();
3893 if (oac & AutoConnectMaster) {
3894 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3895 output_chan.set (DataType::MIDI, 0);
3897 output_chan = input_chan;
3900 /* XXX do something with name template */
3902 switch (add_route_dialog->type_wanted()) {
3903 case AddRouteDialog::AudioTrack:
3904 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3906 case AddRouteDialog::MidiTrack:
3907 session_add_midi_track (route_group, count, name_template, instrument);
3909 case AddRouteDialog::MixedTrack:
3910 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3912 case AddRouteDialog::AudioBus:
3913 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3919 ARDOUR_UI::stop_video_server (bool ask_confirm)
3921 if (!video_server_process && ask_confirm) {
3922 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3924 if (video_server_process) {
3926 ArdourDialog confirm (_("Stop Video-Server"), true);
3927 Label m (_("Do you really want to stop the Video Server?"));
3928 confirm.get_vbox()->pack_start (m, true, true);
3929 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3930 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3931 confirm.show_all ();
3932 if (confirm.run() == RESPONSE_CANCEL) {
3936 delete video_server_process;
3937 video_server_process =0;
3942 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3944 ARDOUR_UI::start_video_server( float_window, true);
3948 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3954 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3955 if (video_server_process) {
3956 popup_error(_("The Video Server is already started."));
3958 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3964 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3966 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3968 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3970 video_server_dialog->set_transient_for (*float_window);
3973 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3974 video_server_dialog->hide();
3976 ResponseType r = (ResponseType) video_server_dialog->run ();
3977 video_server_dialog->hide();
3978 if (r != RESPONSE_ACCEPT) { return false; }
3979 if (video_server_dialog->show_again()) {
3980 Config->set_show_video_server_dialog(false);
3984 std::string icsd_exec = video_server_dialog->get_exec_path();
3985 std::string icsd_docroot = video_server_dialog->get_docroot();
3986 if (icsd_docroot.empty()) {
3987 #ifndef PLATFORM_WINDOWS
3988 icsd_docroot = X_("/");
3990 icsd_docroot = X_("C:\\");
3995 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
3996 warning << _("Specified docroot is not an existing directory.") << endmsg;
3999 #ifndef PLATFORM_WINDOWS
4000 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4001 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4002 warning << _("Given Video Server is not an executable file.") << endmsg;
4006 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4007 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4008 warning << _("Given Video Server is not an executable file.") << endmsg;
4014 argp=(char**) calloc(9,sizeof(char*));
4015 argp[0] = strdup(icsd_exec.c_str());
4016 argp[1] = strdup("-P");
4017 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4018 argp[3] = strdup("-p");
4019 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4020 argp[5] = strdup("-C");
4021 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4022 argp[7] = strdup(icsd_docroot.c_str());
4024 stop_video_server();
4026 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4027 Config->set_video_advanced_setup(false);
4029 std::ostringstream osstream;
4030 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4031 Config->set_video_server_url(osstream.str());
4032 Config->set_video_server_docroot(icsd_docroot);
4033 Config->set_video_advanced_setup(true);
4036 if (video_server_process) {
4037 delete video_server_process;
4040 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4041 if (video_server_process->start()) {
4042 warning << _("Cannot launch the video-server") << endmsg;
4045 int timeout = 120; // 6 sec
4046 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4047 Glib::usleep (50000);
4049 if (--timeout <= 0 || !video_server_process->is_running()) break;
4052 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4054 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4055 delete video_server_process;
4056 video_server_process = 0;
4064 ARDOUR_UI::add_video (Gtk::Window* float_window)
4070 if (!start_video_server(float_window, false)) {
4071 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4076 add_video_dialog->set_transient_for (*float_window);
4079 if (add_video_dialog->is_visible()) {
4080 /* we're already doing this */
4084 ResponseType r = (ResponseType) add_video_dialog->run ();
4085 add_video_dialog->hide();
4086 if (r != RESPONSE_ACCEPT) { return; }
4088 bool local_file, orig_local_file;
4089 std::string path = add_video_dialog->file_name(local_file);
4091 std::string orig_path = path;
4092 orig_local_file = local_file;
4094 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4096 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4097 warning << string_compose(_("could not open %1"), path) << endmsg;
4100 if (!local_file && path.length() == 0) {
4101 warning << _("no video-file selected") << endmsg;
4105 std::string audio_from_video;
4106 bool detect_ltc = false;
4108 switch (add_video_dialog->import_option()) {
4109 case VTL_IMPORT_TRANSCODE:
4111 TranscodeVideoDialog *transcode_video_dialog;
4112 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4113 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4114 transcode_video_dialog->hide();
4115 if (r != RESPONSE_ACCEPT) {
4116 delete transcode_video_dialog;
4120 audio_from_video = transcode_video_dialog->get_audiofile();
4122 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4125 else if (!audio_from_video.empty()) {
4126 editor->embed_audio_from_video(
4128 video_timeline->get_offset(),
4129 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4132 switch (transcode_video_dialog->import_option()) {
4133 case VTL_IMPORT_TRANSCODED:
4134 path = transcode_video_dialog->get_filename();
4137 case VTL_IMPORT_REFERENCE:
4140 delete transcode_video_dialog;
4143 delete transcode_video_dialog;
4147 case VTL_IMPORT_NONE:
4151 /* strip _session->session_directory().video_path() from video file if possible */
4152 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4153 path=path.substr(_session->session_directory().video_path().size());
4154 if (path.at(0) == G_DIR_SEPARATOR) {
4155 path=path.substr(1);
4159 video_timeline->set_update_session_fps(auto_set_session_fps);
4161 if (video_timeline->video_file_info(path, local_file)) {
4162 XMLNode* node = new XMLNode(X_("Videotimeline"));
4163 node->add_property (X_("Filename"), path);
4164 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4165 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4166 if (orig_local_file) {
4167 node->add_property (X_("OriginalVideoFile"), orig_path);
4169 node->remove_property (X_("OriginalVideoFile"));
4171 _session->add_extra_xml (*node);
4172 _session->set_dirty ();
4174 if (!audio_from_video.empty() && detect_ltc) {
4175 std::vector<LTCFileReader::LTCMap> ltc_seq;
4178 /* TODO ask user about TV standard (LTC alignment if any) */
4179 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4180 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4182 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4184 /* TODO seek near end of file, and read LTC until end.
4185 * if it fails to find any LTC frames, scan complete file
4187 * calculate drift of LTC compared to video-duration,
4188 * ask user for reference (timecode from start/mid/end)
4191 // LTCFileReader will have written error messages
4194 ::g_unlink(audio_from_video.c_str());
4196 if (ltc_seq.size() == 0) {
4197 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4199 /* the very first TC in the file is somteimes not aligned properly */
4200 int i = ltc_seq.size() -1;
4201 ARDOUR::frameoffset_t video_start_offset =
4202 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4203 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4204 video_timeline->set_offset(video_start_offset);
4208 _session->maybe_update_session_range(
4209 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4210 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4213 if (add_video_dialog->launch_xjadeo() && local_file) {
4214 editor->set_xjadeo_sensitive(true);
4215 editor->toggle_xjadeo_proc(1);
4217 editor->toggle_xjadeo_proc(0);
4219 editor->toggle_ruler_video(true);
4224 ARDOUR_UI::remove_video ()
4226 video_timeline->close_session();
4227 editor->toggle_ruler_video(false);
4230 video_timeline->set_offset_locked(false);
4231 video_timeline->set_offset(0);
4233 /* delete session state */
4234 XMLNode* node = new XMLNode(X_("Videotimeline"));
4235 _session->add_extra_xml(*node);
4236 node = new XMLNode(X_("Videomonitor"));
4237 _session->add_extra_xml(*node);
4238 node = new XMLNode(X_("Videoexport"));
4239 _session->add_extra_xml(*node);
4240 stop_video_server();
4244 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4246 if (localcacheonly) {
4247 video_timeline->vmon_update();
4249 video_timeline->flush_cache();
4251 editor->queue_visual_videotimeline_update();
4255 ARDOUR_UI::export_video (bool range)
4257 if (ARDOUR::Config->get_show_video_export_info()) {
4258 ExportVideoInfobox infobox (_session);
4259 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4260 if (infobox.show_again()) {
4261 ARDOUR::Config->set_show_video_export_info(false);
4264 case GTK_RESPONSE_YES:
4265 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4271 export_video_dialog->set_session (_session);
4272 export_video_dialog->apply_state(editor->get_selection().time, range);
4273 export_video_dialog->run ();
4274 export_video_dialog->hide ();
4278 ARDOUR_UI::mixer_settings () const
4283 node = _session->instant_xml(X_("Mixer"));
4285 node = Config->instant_xml(X_("Mixer"));
4289 node = new XMLNode (X_("Mixer"));
4296 ARDOUR_UI::editor_settings () const
4301 node = _session->instant_xml(X_("Editor"));
4303 node = Config->instant_xml(X_("Editor"));
4307 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4308 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4313 node = new XMLNode (X_("Editor"));
4320 ARDOUR_UI::keyboard_settings () const
4324 node = Config->extra_xml(X_("Keyboard"));
4327 node = new XMLNode (X_("Keyboard"));
4334 ARDOUR_UI::create_xrun_marker (framepos_t where)
4337 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4338 _session->locations()->add (location);
4343 ARDOUR_UI::halt_on_xrun_message ()
4345 cerr << "HALT on xrun\n";
4346 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4351 ARDOUR_UI::xrun_handler (framepos_t where)
4357 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4359 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4360 create_xrun_marker(where);
4363 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4364 halt_on_xrun_message ();
4369 ARDOUR_UI::disk_overrun_handler ()
4371 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4373 if (!have_disk_speed_dialog_displayed) {
4374 have_disk_speed_dialog_displayed = true;
4375 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4376 The disk system on your computer\n\
4377 was not able to keep up with %1.\n\
4379 Specifically, it failed to write data to disk\n\
4380 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4381 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4387 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4388 static MessageDialog *scan_dlg = NULL;
4389 static ProgressBar *scan_pbar = NULL;
4390 static HBox *scan_tbox = NULL;
4391 static Gtk::Button *scan_timeout_button;
4394 ARDOUR_UI::cancel_plugin_scan ()
4396 PluginManager::instance().cancel_plugin_scan();
4400 ARDOUR_UI::cancel_plugin_timeout ()
4402 PluginManager::instance().cancel_plugin_timeout();
4403 scan_timeout_button->set_sensitive (false);
4407 ARDOUR_UI::plugin_scan_timeout (int timeout)
4409 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4413 scan_pbar->set_sensitive (false);
4414 scan_timeout_button->set_sensitive (true);
4415 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4418 scan_pbar->set_sensitive (false);
4419 scan_timeout_button->set_sensitive (false);
4425 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4427 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4431 const bool cancelled = PluginManager::instance().cancelled();
4432 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4433 if (cancelled && scan_dlg->is_mapped()) {
4438 if (cancelled || !can_cancel) {
4443 static Gtk::Button *cancel_button;
4445 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4446 VBox* vbox = scan_dlg->get_vbox();
4447 vbox->set_size_request(400,-1);
4448 scan_dlg->set_title (_("Scanning for plugins"));
4450 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4451 cancel_button->set_name ("EditorGTKButton");
4452 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4453 cancel_button->show();
4455 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4457 scan_tbox = manage( new HBox() );
4459 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4460 scan_timeout_button->set_name ("EditorGTKButton");
4461 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4462 scan_timeout_button->show();
4464 scan_pbar = manage(new ProgressBar());
4465 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4466 scan_pbar->set_text(_("Scan Timeout"));
4469 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4470 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4472 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4475 assert(scan_dlg && scan_tbox && cancel_button);
4477 if (type == X_("closeme")) {
4481 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4484 if (!can_cancel || !cancelled) {
4485 scan_timeout_button->set_sensitive(false);
4487 cancel_button->set_sensitive(can_cancel && !cancelled);
4493 ARDOUR_UI::gui_idle_handler ()
4496 /* due to idle calls, gtk_events_pending() may always return true */
4497 while (gtk_events_pending() && --timeout) {
4498 gtk_main_iteration ();
4503 ARDOUR_UI::disk_underrun_handler ()
4505 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4507 if (!have_disk_speed_dialog_displayed) {
4508 have_disk_speed_dialog_displayed = true;
4509 MessageDialog* msg = new MessageDialog (
4510 _main_window, string_compose (_("The disk system on your computer\n\
4511 was not able to keep up with %1.\n\
4513 Specifically, it failed to read data from disk\n\
4514 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4515 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4521 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4523 have_disk_speed_dialog_displayed = false;
4528 ARDOUR_UI::session_dialog (std::string msg)
4530 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4534 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4541 ARDOUR_UI::pending_state_dialog ()
4543 HBox* hbox = manage (new HBox());
4544 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4545 ArdourDialog dialog (_("Crash Recovery"), true);
4546 Label message (string_compose (_("\
4547 This session appears to have been in the\n\
4548 middle of recording when %1 or\n\
4549 the computer was shutdown.\n\
4551 %1 can recover any captured audio for\n\
4552 you, or it can ignore it. Please decide\n\
4553 what you would like to do.\n"), PROGRAM_NAME));
4554 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4555 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4556 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4557 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4558 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4559 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4560 dialog.set_default_response (RESPONSE_ACCEPT);
4561 dialog.set_position (WIN_POS_CENTER);
4566 switch (dialog.run ()) {
4567 case RESPONSE_ACCEPT:
4575 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4577 HBox* hbox = new HBox();
4578 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4579 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4580 Label message (string_compose (_("\
4581 This session was created with a sample rate of %1 Hz, but\n\
4582 %2 is currently running at %3 Hz. If you load this session,\n\
4583 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4585 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4586 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4587 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4588 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4589 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4590 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4591 dialog.set_default_response (RESPONSE_ACCEPT);
4592 dialog.set_position (WIN_POS_CENTER);
4597 switch (dialog.run()) {
4598 case RESPONSE_ACCEPT:
4608 ARDOUR_UI::use_config ()
4610 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4612 set_transport_controllable_state (*node);
4617 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4619 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4620 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4622 primary_clock->set (pos);
4625 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4626 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4628 secondary_clock->set (pos);
4631 if (big_clock_window) {
4632 big_clock->set (pos);
4634 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4638 ARDOUR_UI::step_edit_status_change (bool yn)
4640 // XXX should really store pre-step edit status of things
4641 // we make insensitive
4644 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4645 rec_button.set_sensitive (false);
4647 rec_button.unset_active_state ();;
4648 rec_button.set_sensitive (true);
4653 ARDOUR_UI::record_state_changed ()
4655 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4657 if (!_session || !big_clock_window) {
4658 /* why bother - the clock isn't visible */
4662 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4663 big_clock->set_active (true);
4665 big_clock->set_active (false);
4670 ARDOUR_UI::first_idle ()
4673 _session->allow_auto_play (true);
4677 editor->first_idle();
4680 Keyboard::set_can_save_keybindings (true);
4685 ARDOUR_UI::store_clock_modes ()
4687 XMLNode* node = new XMLNode(X_("ClockModes"));
4689 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4690 XMLNode* child = new XMLNode (X_("Clock"));
4692 child->add_property (X_("name"), (*x)->name());
4693 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4694 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4696 node->add_child_nocopy (*child);
4699 _session->add_extra_xml (*node);
4700 _session->set_dirty ();
4703 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4704 : Controllable (name), ui (u), type(tp)
4710 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4713 /* do nothing: these are radio-style actions */
4717 const char *action = 0;
4721 action = X_("Roll");
4724 action = X_("Stop");
4727 action = X_("GotoStart");
4730 action = X_("GotoEnd");
4733 action = X_("Loop");
4736 action = X_("PlaySelection");
4739 action = X_("Record");
4749 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4757 ARDOUR_UI::TransportControllable::get_value (void) const
4784 ARDOUR_UI::setup_profile ()
4786 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4787 Profile->set_small_screen ();
4790 if (g_getenv ("ARDOUR_SAE")) {
4791 Profile->set_sae ();
4792 Profile->set_single_package ();
4795 if (g_getenv ("TRX")) {
4796 Profile->set_trx ();
4799 if (g_getenv ("MIXBUS")) {
4800 Profile->set_mixbus ();
4805 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4807 MissingFileDialog dialog (s, str, type);
4812 int result = dialog.run ();
4819 return 1; // quit entire session load
4822 result = dialog.get_action ();
4828 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4830 AmbiguousFileDialog dialog (file, hits);
4837 return dialog.get_which ();
4840 /** Allocate our thread-local buffers */
4842 ARDOUR_UI::get_process_buffers ()
4844 _process_thread->get_buffers ();
4847 /** Drop our thread-local buffers */
4849 ARDOUR_UI::drop_process_buffers ()
4851 _process_thread->drop_buffers ();
4855 ARDOUR_UI::feedback_detected ()
4857 _feedback_exists = true;
4861 ARDOUR_UI::successful_graph_sort ()
4863 _feedback_exists = false;
4867 ARDOUR_UI::midi_panic ()
4870 _session->midi_panic();
4875 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4877 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4878 const char* end_big = "</span>";
4879 const char* start_mono = "<tt>";
4880 const char* end_mono = "</tt>";
4882 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4883 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4884 "From now on, use the -2000 version with older versions of %3"),
4885 xml_path, backup_path, PROGRAM_NAME,
4887 start_mono, end_mono), true);
4894 ARDOUR_UI::reset_peak_display ()
4896 if (!_session || !_session->master_out() || !editor_meter) return;
4897 editor_meter->clear_meters();
4898 editor_meter_max_peak = -INFINITY;
4899 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4903 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4905 if (!_session || !_session->master_out()) return;
4906 if (group == _session->master_out()->route_group()) {
4907 reset_peak_display ();
4912 ARDOUR_UI::reset_route_peak_display (Route* route)
4914 if (!_session || !_session->master_out()) return;
4915 if (_session->master_out().get() == route) {
4916 reset_peak_display ();
4921 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4923 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4924 audio_midi_setup->set_position (WIN_POS_CENTER);
4929 response = audio_midi_setup->run();
4931 case Gtk::RESPONSE_OK:
4932 if (!AudioEngine::instance()->running()) {
4946 ARDOUR_UI::transport_numpad_timeout ()
4948 _numpad_locate_happening = false;
4949 if (_numpad_timeout_connection.connected() )
4950 _numpad_timeout_connection.disconnect();
4955 ARDOUR_UI::transport_numpad_decimal ()
4957 _numpad_timeout_connection.disconnect();
4959 if (_numpad_locate_happening) {
4960 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4961 _numpad_locate_happening = false;
4963 _pending_locate_num = 0;
4964 _numpad_locate_happening = true;
4965 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
4970 ARDOUR_UI::transport_numpad_event (int num)
4972 if ( _numpad_locate_happening ) {
4973 _pending_locate_num = _pending_locate_num*10 + num;
4976 case 0: toggle_roll(false, false); break;
4977 case 1: transport_rewind(1); break;
4978 case 2: transport_forward(1); break;
4979 case 3: transport_record(true); break;
4980 case 4: toggle_session_auto_loop(); break;
4981 case 5: transport_record(false); toggle_session_auto_loop(); break;
4982 case 6: toggle_punch(); break;
4983 case 7: toggle_click(); break;
4984 case 8: toggle_auto_return(); break;
4985 case 9: toggle_follow_edits(); break;
4991 ARDOUR_UI::set_flat_buttons ()
4993 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
4997 ARDOUR_UI::audioengine_became_silent ()
4999 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5001 Gtk::MESSAGE_WARNING,
5005 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5007 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5008 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5009 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5010 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5011 Gtk::HBox pay_button_box;
5012 Gtk::HBox subscribe_button_box;
5014 pay_button_box.pack_start (pay_button, true, false);
5015 subscribe_button_box.pack_start (subscribe_button, true, false);
5017 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 */
5019 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5020 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5022 msg.get_vbox()->pack_start (pay_label);
5023 msg.get_vbox()->pack_start (pay_button_box);
5024 msg.get_vbox()->pack_start (subscribe_label);
5025 msg.get_vbox()->pack_start (subscribe_button_box);
5027 msg.get_vbox()->show_all ();
5029 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5030 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5031 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5036 case Gtk::RESPONSE_YES:
5037 AudioEngine::instance()->reset_silence_countdown ();
5040 case Gtk::RESPONSE_NO:
5042 save_state_canfail ("");
5046 case Gtk::RESPONSE_CANCEL:
5048 /* don't reset, save session and exit */
5054 ARDOUR_UI::hide_application ()
5056 Application::instance ()-> hide ();
5060 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5062 /* icons, titles, WM stuff */
5064 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5066 if (window_icons.empty()) {
5067 Glib::RefPtr<Gdk::Pixbuf> icon;
5068 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5069 window_icons.push_back (icon);
5071 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5072 window_icons.push_back (icon);
5074 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5075 window_icons.push_back (icon);
5077 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5078 window_icons.push_back (icon);
5082 if (!window_icons.empty()) {
5083 window.set_default_icon_list (window_icons);
5086 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5088 if (!name.empty()) {
5092 window.set_title (title.get_string());
5093 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5095 window.set_flags (CAN_FOCUS);
5096 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5098 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5100 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5101 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5102 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5103 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5107 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5109 Gtkmm2ext::Bindings* bindings = 0;
5110 Gtk::Window* window = 0;
5112 /* until we get ardour bindings working, we are not handling key
5116 if (ev->type != GDK_KEY_PRESS) {
5120 if (event_window == &_main_window) {
5122 window = event_window;
5124 /* find current tab contents */
5126 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5128 /* see if it uses the ardour binding system */
5130 HasBindings* bindable;
5132 if ((bindable = dynamic_cast<HasBindings*> (w)) != 0) {
5133 KeyboardKey k (ev->state, ev->keyval);
5134 bindings = &bindable->bindings();
5137 } else if (window != 0) {
5139 window = event_window;
5141 /* see if window uses ardour binding system */
5146 window = &_main_window;
5148 /* no window supplied, try our own bindings */
5150 bindings = &_global_bindings;
5153 return key_press_focus_accelerator_handler (*window, ev, bindings);
5157 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5159 GtkWindow* win = window.gobj();
5160 GtkWidget* focus = gtk_window_get_focus (win);
5161 bool special_handling_of_unmodified_accelerators = false;
5162 bool allow_activating = true;
5163 /* consider all relevant modifiers but not LOCK or SHIFT */
5164 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5165 GdkModifierType modifier = GdkModifierType (ev->state);
5166 modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
5167 Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
5170 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5171 special_handling_of_unmodified_accelerators = true;
5176 /* at one time this appeared to be necessary. As of July 2012, it does not
5177 appear to be. if it ever is necessar, figure out if it should apply
5181 if (Keyboard::some_magic_widget_has_focus ()) {
5182 allow_activating = false;
5188 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 allow_activation ? %6\n",
5191 show_gdk_event_state (ev->state),
5192 special_handling_of_unmodified_accelerators,
5193 Keyboard::some_magic_widget_has_focus(),
5196 (focus ? gtk_widget_get_name (focus) : "no focus widget")));
5198 /* This exists to allow us to override the way GTK handles
5199 key events. The normal sequence is:
5201 a) event is delivered to a GtkWindow
5202 b) accelerators/mnemonics are activated
5203 c) if (b) didn't handle the event, propagate to
5204 the focus widget and/or focus chain
5206 The problem with this is that if the accelerators include
5207 keys without modifiers, such as the space bar or the
5208 letter "e", then pressing the key while typing into
5209 a text entry widget results in the accelerator being
5210 activated, instead of the desired letter appearing
5213 There is no good way of fixing this, but this
5214 represents a compromise. The idea is that
5215 key events involving modifiers (not Shift)
5216 get routed into the activation pathway first, then
5217 get propagated to the focus widget if necessary.
5219 If the key event doesn't involve modifiers,
5220 we deliver to the focus widget first, thus allowing
5221 it to get "normal text" without interference
5224 Of course, this can also be problematic: if there
5225 is a widget with focus, then it will swallow
5226 all "normal text" accelerators.
5229 if (!special_handling_of_unmodified_accelerators) {
5232 /* XXX note that for a brief moment, the conditional above
5233 * included "|| (ev->state & mask)" so as to enforce the
5234 * implication of special_handling_of_UNMODIFIED_accelerators.
5235 * however, this forces any key that GTK doesn't allow and that
5236 * we have an alternative (see next comment) for to be
5237 * automatically sent through the accel groups activation
5238 * pathway, which prevents individual widgets & canvas items
5239 * from ever seeing it if is used by a key binding.
5241 * specifically, this hid Ctrl-down-arrow from MIDI region
5242 * views because it is also bound to an action.
5244 * until we have a robust, clean binding system, this
5245 * quirk will have to remain in place.
5248 /* pretend that certain key events that GTK does not allow
5249 to be used as accelerators are actually something that
5250 it does allow. but only where there are no modifiers.
5253 uint32_t fakekey = ev->keyval;
5255 if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) {
5256 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tactivate (was %1 now %2) without special hanlding of unmodified accels\n",
5257 ev->keyval, fakekey));
5259 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tmodified modifier was %1\n", show_gdk_event_state (modifier)));
5261 if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, modifier)) {
5262 DEBUG_TRACE (DEBUG::Accelerators, "\taccel group activated by fakekey\n");
5268 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5270 /* no special handling or there are modifiers in effect: accelerate first */
5272 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5273 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5274 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5276 if (allow_activating) {
5277 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5278 if (gtk_accel_groups_activate (G_OBJECT(win), ev->keyval, modifier)) {
5279 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5283 DEBUG_TRACE (DEBUG::Accelerators, "\tactivation skipped\n");
5286 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5288 return gtk_window_propagate_key_event (win, ev);
5291 /* no modifiers, propagate first */
5293 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5295 if (!gtk_window_propagate_key_event (win, ev)) {
5296 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5297 if (allow_activating) {
5298 return gtk_accel_groups_activate (G_OBJECT(win), ev->keyval, modifier);
5300 DEBUG_TRACE (DEBUG::Accelerators, "\tactivation skipped\n");
5304 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5308 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");