2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #ifdef WINDOWS_VST_SUPPORT
97 #ifdef AUDIOUNIT_SUPPORT
98 #include "ardour/audio_unit.h"
101 #include "timecode/time.h"
103 typedef uint64_t microseconds_t;
108 #include "add_route_dialog.h"
109 #include "ambiguous_file_dialog.h"
110 #include "ardour_ui.h"
111 #include "audio_clock.h"
112 #include "audio_region_view.h"
113 #include "big_clock_window.h"
114 #include "bundle_manager.h"
115 #include "duplicate_routes_dialog.h"
117 #include "engine_dialog.h"
118 #include "export_video_dialog.h"
119 #include "export_video_infobox.h"
120 #include "gain_meter.h"
121 #include "global_port_matrix.h"
122 #include "gui_object.h"
123 #include "gui_thread.h"
124 #include "keyboard.h"
125 #include "keyeditor.h"
126 #include "location_ui.h"
127 #include "main_clock.h"
128 #include "missing_file_dialog.h"
129 #include "missing_plugin_dialog.h"
130 #include "mixer_ui.h"
131 #include "meterbridge.h"
132 #include "mouse_cursors.h"
135 #include "pingback.h"
136 #include "processor_box.h"
137 #include "prompter.h"
138 #include "public_editor.h"
139 #include "rc_option_editor.h"
140 #include "route_time_axis.h"
141 #include "route_params_ui.h"
142 #include "save_as_dialog.h"
143 #include "session_dialog.h"
144 #include "session_metadata_dialog.h"
145 #include "session_option_editor.h"
146 #include "shuttle_control.h"
147 #include "speaker_dialog.h"
150 #include "theme_manager.h"
151 #include "time_axis_view_item.h"
154 #include "video_server_dialog.h"
155 #include "add_video_dialog.h"
156 #include "transcode_video_dialog.h"
160 using namespace ARDOUR;
161 using namespace ARDOUR_UI_UTILS;
163 using namespace Gtkmm2ext;
166 using namespace Editing;
168 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
170 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
171 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
174 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
176 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
177 "Would you like these files to be copied and used for %1 %2.x?\n\n"
178 "(This will require you to restart %1.)"),
179 PROGRAM_NAME, PROGRAM_VERSION, version),
180 false, /* no markup */
183 true /* modal, though it hardly matters since it is the only window */
186 msg.set_default_response (Gtk::RESPONSE_YES);
189 return (msg.run() == Gtk::RESPONSE_YES);
193 libxml_generic_error_func (void* /* parsing_context*/,
201 vsnprintf (buf, sizeof (buf), msg, ap);
202 error << buf << endmsg;
207 libxml_structured_error_func (void* /* parsing_context*/,
215 replace_all (msg, "\n", "");
217 if (err->file && err->line) {
218 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
221 error << ':' << err->int2;
228 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
231 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
233 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
234 >>>>>>> first compilable version of tabbable design.
235 , session_loaded (false)
236 , gui_object_state (new GUIObjectState)
237 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
238 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
239 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
241 , ignore_dual_punch (false)
246 , _mixer_on_top (false)
247 , _initial_verbose_plugin_scan (false)
248 , first_time_engine_run (true)
249 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
250 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
251 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
252 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
253 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
254 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
255 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
256 , auto_return_button (ArdourButton::led_default_elements)
257 , follow_edits_button (ArdourButton::led_default_elements)
258 , auto_input_button (ArdourButton::led_default_elements)
259 , auditioning_alert_button (_("Audition"))
260 , solo_alert_button (_("Solo"))
261 , feedback_alert_button (_("Feedback"))
262 , error_alert_button ( ArdourButton::just_led_default_elements )
264 , editor_meter_peak_display()
265 , _numpad_locate_happening (false)
266 , _session_is_new (false)
267 , last_key_press_time (0)
270 , rc_option_editor (0)
271 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
272 , key_editor (X_("key-editor"), _("Key Bindings"))
273 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
274 , about (X_("about"), _("About"))
275 , location_ui (X_("locations"), _("Locations"))
276 , route_params (X_("inspector"), _("Tracks and Busses"))
277 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
278 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
279 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
280 , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
281 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
282 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
283 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
284 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
285 , video_server_process (0)
287 , have_configure_timeout (false)
288 , last_configure_time (0)
290 , have_disk_speed_dialog_displayed (false)
291 , _status_bar_visibility (X_("status-bar"))
292 , _feedback_exists (false)
293 , _log_not_acknowledged (LogLevelNone)
294 , duplicate_routes_dialog (0)
296 Gtkmm2ext::init (localedir);
298 UIConfiguration::instance().post_gui_init ();
300 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
301 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
303 /* configuration was modified, exit immediately */
307 if (theArdourUI == 0) {
311 /* stop libxml from spewing to stdout/stderr */
313 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
314 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
316 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
317 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
318 UIConfiguration::instance().map_parameters (pc);
320 roll_button.set_controllable (roll_controllable);
321 stop_button.set_controllable (stop_controllable);
322 goto_start_button.set_controllable (goto_start_controllable);
323 goto_end_button.set_controllable (goto_end_controllable);
324 auto_loop_button.set_controllable (auto_loop_controllable);
325 play_selection_button.set_controllable (play_selection_controllable);
326 rec_button.set_controllable (rec_controllable);
328 roll_button.set_name ("transport button");
329 stop_button.set_name ("transport button");
330 goto_start_button.set_name ("transport button");
331 goto_end_button.set_name ("transport button");
332 auto_loop_button.set_name ("transport button");
333 play_selection_button.set_name ("transport button");
334 rec_button.set_name ("transport recenable button");
335 midi_panic_button.set_name ("transport button");
337 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
338 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
340 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
342 /* handle dialog requests */
344 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
346 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
348 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
350 /* handle Audio/MIDI setup when session requires it */
352 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
354 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
356 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
358 /* handle requests to quit (coming from JACK session) */
360 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
362 /* tell the user about feedback */
364 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
365 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
367 /* handle requests to deal with missing files */
369 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
371 /* and ambiguous files */
373 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
375 /* also plugin scan messages */
376 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
377 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
379 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
381 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
384 /* lets get this party started */
386 setup_gtk_ardour_enums ();
389 SessionEvent::create_per_thread_pool ("GUI", 4096);
391 /* we like keyboards */
393 keyboard = new ArdourKeyboard(*this);
395 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
397 keyboard->set_state (*node, Stateful::loading_state_version);
400 /* we don't like certain modifiers */
401 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
403 UIConfiguration::instance().reset_dpi ();
405 TimeAxisViewItem::set_constant_heights ();
407 /* Set this up so that our window proxies can register actions */
409 ActionManager::init ();
411 /* The following must happen after ARDOUR::init() so that Config is set up */
413 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
416 key_editor.set_state (*ui_xml, 0);
417 session_option_editor.set_state (*ui_xml, 0);
418 speaker_config_window.set_state (*ui_xml, 0);
419 about.set_state (*ui_xml, 0);
420 add_route_dialog.set_state (*ui_xml, 0);
421 add_video_dialog.set_state (*ui_xml, 0);
422 route_params.set_state (*ui_xml, 0);
423 bundle_manager.set_state (*ui_xml, 0);
424 location_ui.set_state (*ui_xml, 0);
425 big_clock_window.set_state (*ui_xml, 0);
426 audio_port_matrix.set_state (*ui_xml, 0);
427 midi_port_matrix.set_state (*ui_xml, 0);
428 export_video_dialog.set_state (*ui_xml, 0);
431 /* Separate windows */
433 WM::Manager::instance().register_window (&key_editor);
434 WM::Manager::instance().register_window (&session_option_editor);
435 WM::Manager::instance().register_window (&speaker_config_window);
436 WM::Manager::instance().register_window (&about);
437 WM::Manager::instance().register_window (&add_route_dialog);
438 WM::Manager::instance().register_window (&add_video_dialog);
439 WM::Manager::instance().register_window (&route_params);
440 WM::Manager::instance().register_window (&audio_midi_setup);
441 WM::Manager::instance().register_window (&export_video_dialog);
442 WM::Manager::instance().register_window (&bundle_manager);
443 WM::Manager::instance().register_window (&location_ui);
444 WM::Manager::instance().register_window (&big_clock_window);
445 WM::Manager::instance().register_window (&audio_port_matrix);
446 WM::Manager::instance().register_window (&midi_port_matrix);
448 /* Trigger setting up the color scheme and loading the GTK RC file */
450 UIConfiguration::instance().load_rc_file (false);
452 _process_thread = new ProcessThread ();
453 _process_thread->init ();
455 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
460 GlobalPortMatrixWindow*
461 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
466 return new GlobalPortMatrixWindow (_session, type);
470 ARDOUR_UI::attach_to_engine ()
472 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
473 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
477 ARDOUR_UI::engine_stopped ()
479 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
480 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
481 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
482 update_sample_rate (0);
487 ARDOUR_UI::engine_running ()
489 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
490 if (first_time_engine_run) {
492 first_time_engine_run = false;
496 _session->reset_xrun_count ();
498 update_disk_space ();
500 update_xrun_count ();
501 update_sample_rate (AudioEngine::instance()->sample_rate());
502 update_timecode_format ();
503 update_peak_thread_work ();
504 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
505 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
509 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
511 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
512 /* we can't rely on the original string continuing to exist when we are called
513 again in the GUI thread, so make a copy and note that we need to
516 char *copy = strdup (reason);
517 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
521 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
522 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
524 update_sample_rate (0);
528 /* if the reason is a non-empty string, it means that the backend was shutdown
529 rather than just Ardour.
532 if (strlen (reason)) {
533 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
535 msgstr = string_compose (_("\
536 The audio backend has either been shutdown or it\n\
537 disconnected %1 because %1\n\
538 was not fast enough. Try to restart\n\
539 the audio backend and save the session."), PROGRAM_NAME);
542 MessageDialog msg (_main_window, msgstr);
543 pop_back_splash (msg);
547 free (const_cast<char*> (reason));
552 ARDOUR_UI::post_engine ()
554 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
556 #ifdef AUDIOUNIT_SUPPORT
558 if (AUPluginInfo::au_get_crashlog(au_msg)) {
559 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
560 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
561 info << au_msg << endmsg;
565 ARDOUR::init_post_engine ();
567 /* connect to important signals */
569 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
570 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
571 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
572 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
573 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
575 if (setup_windows ()) {
576 throw failed_constructor ();
579 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
580 XMLNode* n = Config->extra_xml (X_("UI"));
582 _status_bar_visibility.set_state (*n);
585 check_memory_locking();
587 /* this is the first point at which all the keybindings are available */
589 if (ARDOUR_COMMAND_LINE::show_key_actions) {
590 vector<string> names;
591 vector<string> paths;
592 vector<string> tooltips;
594 vector<AccelKey> bindings;
596 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
598 vector<string>::iterator n;
599 vector<string>::iterator k;
600 vector<string>::iterator p;
601 for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
602 cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
605 halt_connection.disconnect ();
606 AudioEngine::instance()->stop ();
610 /* this being a GUI and all, we want peakfiles */
612 AudioFileSource::set_build_peakfiles (true);
613 AudioFileSource::set_build_missing_peakfiles (true);
615 /* set default clock modes */
617 if (Profile->get_sae()) {
618 primary_clock->set_mode (AudioClock::BBT);
619 secondary_clock->set_mode (AudioClock::MinSec);
621 primary_clock->set_mode (AudioClock::Timecode);
622 secondary_clock->set_mode (AudioClock::BBT);
625 /* start the time-of-day-clock */
628 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
629 update_wall_clock ();
630 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
635 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
636 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
637 Config->map_parameters (pc);
639 UIConfiguration::instance().map_parameters (pc);
643 ARDOUR_UI::~ARDOUR_UI ()
645 UIConfiguration::instance().save_state();
649 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
650 // don't bother at 'real' exit. the OS cleans up for us.
652 delete primary_clock;
653 delete secondary_clock;
654 delete _process_thread;
659 delete gui_object_state;
660 FastMeter::flush_pattern_cache ();
661 PixFader::flush_pattern_cache ();
665 /* Small trick to flush main-thread event pool.
666 * Other thread-pools are destroyed at pthread_exit(),
667 * but tmain thread termination is too late to trigger Pool::~Pool()
669 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
670 delete ev->event_pool();
675 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
677 if (Splash::instance()) {
678 Splash::instance()->pop_back_for (win);
683 ARDOUR_UI::configure_timeout ()
685 if (last_configure_time == 0) {
686 /* no configure events yet */
690 /* force a gap of 0.5 seconds since the last configure event
693 if (get_microseconds() - last_configure_time < 500000) {
696 have_configure_timeout = false;
697 save_ardour_state ();
703 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
705 if (have_configure_timeout) {
706 last_configure_time = get_microseconds();
708 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
709 have_configure_timeout = true;
716 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
718 const XMLProperty* prop;
720 if ((prop = node.property ("roll")) != 0) {
721 roll_controllable->set_id (prop->value());
723 if ((prop = node.property ("stop")) != 0) {
724 stop_controllable->set_id (prop->value());
726 if ((prop = node.property ("goto-start")) != 0) {
727 goto_start_controllable->set_id (prop->value());
729 if ((prop = node.property ("goto-end")) != 0) {
730 goto_end_controllable->set_id (prop->value());
732 if ((prop = node.property ("auto-loop")) != 0) {
733 auto_loop_controllable->set_id (prop->value());
735 if ((prop = node.property ("play-selection")) != 0) {
736 play_selection_controllable->set_id (prop->value());
738 if ((prop = node.property ("rec")) != 0) {
739 rec_controllable->set_id (prop->value());
741 if ((prop = node.property ("shuttle")) != 0) {
742 shuttle_box->controllable()->set_id (prop->value());
747 ARDOUR_UI::get_transport_controllable_state ()
749 XMLNode* node = new XMLNode(X_("TransportControllables"));
752 roll_controllable->id().print (buf, sizeof (buf));
753 node->add_property (X_("roll"), buf);
754 stop_controllable->id().print (buf, sizeof (buf));
755 node->add_property (X_("stop"), buf);
756 goto_start_controllable->id().print (buf, sizeof (buf));
757 node->add_property (X_("goto_start"), buf);
758 goto_end_controllable->id().print (buf, sizeof (buf));
759 node->add_property (X_("goto_end"), buf);
760 auto_loop_controllable->id().print (buf, sizeof (buf));
761 node->add_property (X_("auto_loop"), buf);
762 play_selection_controllable->id().print (buf, sizeof (buf));
763 node->add_property (X_("play_selection"), buf);
764 rec_controllable->id().print (buf, sizeof (buf));
765 node->add_property (X_("rec"), buf);
766 shuttle_box->controllable()->id().print (buf, sizeof (buf));
767 node->add_property (X_("shuttle"), buf);
773 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
776 _session->save_state (snapshot_name);
781 ARDOUR_UI::autosave_session ()
783 if (g_main_depth() > 1) {
784 /* inside a recursive main loop,
785 give up because we may not be able to
791 if (!Config->get_periodic_safety_backups()) {
796 _session->maybe_write_autosave();
803 ARDOUR_UI::session_dirty_changed ()
810 ARDOUR_UI::update_autosave ()
812 if (_session && _session->dirty()) {
813 if (_autosave_connection.connected()) {
814 _autosave_connection.disconnect();
817 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
818 Config->get_periodic_safety_backup_interval() * 1000);
821 if (_autosave_connection.connected()) {
822 _autosave_connection.disconnect();
828 ARDOUR_UI::check_announcements ()
831 string _annc_filename;
834 _annc_filename = PROGRAM_NAME "_announcements_osx_";
835 #elif defined PLATFORM_WINDOWS
836 _annc_filename = PROGRAM_NAME "_announcements_windows_";
838 _annc_filename = PROGRAM_NAME "_announcements_linux_";
840 _annc_filename.append (VERSIONSTRING);
842 _announce_string = "";
844 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
845 FILE* fin = g_fopen (path.c_str(), "rb");
847 while (!feof (fin)) {
850 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
853 _announce_string.append (tmp, len);
858 pingback (VERSIONSTRING, path);
863 ARDOUR_UI::starting ()
865 Application* app = Application::instance ();
867 bool brand_new_user = ArdourStartup::required ();
869 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
870 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
872 if (ARDOUR_COMMAND_LINE::check_announcements) {
873 check_announcements ();
878 /* we need to create this early because it may need to set the
879 * audio backend end up.
883 audio_midi_setup.get (true);
885 std::cerr << "audio-midi engine setup failed."<< std::endl;
889 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
890 nsm = new NSM_Client;
891 if (!nsm->init (nsm_url)) {
892 /* the ardour executable may have different names:
894 * waf's obj.target for distro versions: eg ardour4, ardourvst4
895 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
896 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
898 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
900 const char *process_name = g_getenv ("ARDOUR_SELF");
901 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
904 // wait for announce reply from nsm server
905 for ( i = 0; i < 5000; ++i) {
909 if (nsm->is_active()) {
914 error << _("NSM server did not announce itself") << endmsg;
917 // wait for open command from nsm server
918 for ( i = 0; i < 5000; ++i) {
921 if (nsm->client_id ()) {
927 error << _("NSM: no client ID provided") << endmsg;
931 if (_session && nsm) {
932 _session->set_nsm_state( nsm->is_active() );
934 error << _("NSM: no session created") << endmsg;
938 // nsm requires these actions disabled
939 vector<string> action_names;
940 action_names.push_back("SaveAs");
941 action_names.push_back("Rename");
942 action_names.push_back("New");
943 action_names.push_back("Open");
944 action_names.push_back("Recent");
945 action_names.push_back("Close");
947 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
948 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
950 act->set_sensitive (false);
957 error << _("NSM: initialization failed") << endmsg;
963 if (brand_new_user) {
964 _initial_verbose_plugin_scan = true;
969 _initial_verbose_plugin_scan = false;
970 switch (s.response ()) {
971 case Gtk::RESPONSE_OK:
978 #ifdef NO_PLUGIN_STATE
980 ARDOUR::RecentSessions rs;
981 ARDOUR::read_recent_sessions (rs);
983 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
985 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
987 /* already used Ardour, have sessions ... warn about plugin state */
989 ArdourDialog d (_("Free/Demo Version Warning"), true);
991 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
992 CheckButton c (_("Don't warn me about this again"));
994 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"),
995 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
996 _("It will not restore OR save any plugin settings"),
997 _("If you load an existing session with plugin settings\n"
998 "they will not be used and will be lost."),
999 _("To get full access to updates without this limitation\n"
1000 "consider becoming a subscriber for a low cost every month.")));
1001 l.set_justify (JUSTIFY_CENTER);
1003 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1005 d.get_vbox()->pack_start (l, true, true);
1006 d.get_vbox()->pack_start (b, false, false, 12);
1007 d.get_vbox()->pack_start (c, false, false, 12);
1009 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1010 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1014 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1016 if (d.run () != RESPONSE_OK) {
1022 /* go get a session */
1024 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1026 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1027 std::cerr << "Cannot get session parameters."<< std::endl;
1034 WM::Manager::instance().show_visible ();
1036 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1037 * editor window, and we may want stuff to be hidden.
1039 _status_bar_visibility.update ();
1041 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1046 ARDOUR_UI::check_memory_locking ()
1048 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1049 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1053 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1055 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1057 struct rlimit limits;
1059 long pages, page_size;
1061 size_t pages_len=sizeof(pages);
1062 if ((page_size = getpagesize()) < 0 ||
1063 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1065 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1070 ram = (int64_t) pages * (int64_t) page_size;
1073 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1077 if (limits.rlim_cur != RLIM_INFINITY) {
1079 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1083 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1084 "This might cause %1 to run out of memory before your system "
1085 "runs out of memory. \n\n"
1086 "You can view the memory limit with 'ulimit -l', "
1087 "and it is normally controlled by %2"),
1090 X_("/etc/login.conf")
1092 X_(" /etc/security/limits.conf")
1096 msg.set_default_response (RESPONSE_OK);
1098 VBox* vbox = msg.get_vbox();
1100 CheckButton cb (_("Do not show this window again"));
1101 hbox.pack_start (cb, true, false);
1102 vbox->pack_start (hbox);
1107 pop_back_splash (msg);
1111 if (cb.get_active()) {
1112 XMLNode node (X_("no-memory-warning"));
1113 Config->add_instant_xml (node);
1118 #endif // !__APPLE__
1123 ARDOUR_UI::queue_finish ()
1125 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1129 ARDOUR_UI::idle_finish ()
1132 return false; /* do not call again */
1139 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1141 if (_session->dirty()) {
1142 vector<string> actions;
1143 actions.push_back (_("Don't quit"));
1144 actions.push_back (_("Just quit"));
1145 actions.push_back (_("Save and quit"));
1146 switch (ask_about_saving_session(actions)) {
1151 /* use the default name */
1152 if (save_state_canfail ("")) {
1153 /* failed - don't quit */
1154 MessageDialog msg (_main_window,
1155 string_compose (_("\
1156 %1 was unable to save your session.\n\n\
1157 If you still wish to quit, please use the\n\n\
1158 \"Just quit\" option."), PROGRAM_NAME));
1159 pop_back_splash(msg);
1169 second_connection.disconnect ();
1170 point_one_second_connection.disconnect ();
1171 point_zero_something_second_connection.disconnect();
1172 fps_connection.disconnect();
1175 delete ARDOUR_UI::instance()->video_timeline;
1176 ARDOUR_UI::instance()->video_timeline = NULL;
1177 stop_video_server();
1179 /* Save state before deleting the session, as that causes some
1180 windows to be destroyed before their visible state can be
1183 save_ardour_state ();
1185 close_all_dialogs ();
1188 _session->set_clean ();
1189 _session->remove_pending_capture_state ();
1194 halt_connection.disconnect ();
1195 AudioEngine::instance()->stop ();
1196 #ifdef WINDOWS_VST_SUPPORT
1197 fst_stop_threading();
1203 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1205 ArdourDialog window (_("Unsaved Session"));
1206 Gtk::HBox dhbox; // the hbox for the image and text
1207 Gtk::Label prompt_label;
1208 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1212 assert (actions.size() >= 3);
1214 window.add_button (actions[0], RESPONSE_REJECT);
1215 window.add_button (actions[1], RESPONSE_APPLY);
1216 window.add_button (actions[2], RESPONSE_ACCEPT);
1218 window.set_default_response (RESPONSE_ACCEPT);
1220 Gtk::Button noquit_button (msg);
1221 noquit_button.set_name ("EditorGTKButton");
1225 if (_session->snap_name() == _session->name()) {
1226 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?"),
1227 _session->snap_name());
1229 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?"),
1230 _session->snap_name());
1233 prompt_label.set_text (prompt);
1234 prompt_label.set_name (X_("PrompterLabel"));
1235 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1237 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1238 dhbox.set_homogeneous (false);
1239 dhbox.pack_start (*dimage, false, false, 5);
1240 dhbox.pack_start (prompt_label, true, false, 5);
1241 window.get_vbox()->pack_start (dhbox);
1243 window.set_name (_("Prompter"));
1244 window.set_modal (true);
1245 window.set_resizable (false);
1248 prompt_label.show();
1253 ResponseType r = (ResponseType) window.run();
1258 case RESPONSE_ACCEPT: // save and get out of here
1260 case RESPONSE_APPLY: // get out of here
1271 ARDOUR_UI::every_second ()
1274 update_xrun_count ();
1275 update_buffer_load ();
1276 update_disk_space ();
1277 update_timecode_format ();
1278 update_peak_thread_work ();
1280 if (nsm && nsm->is_active ()) {
1283 if (!_was_dirty && _session->dirty ()) {
1287 else if (_was_dirty && !_session->dirty ()){
1295 ARDOUR_UI::every_point_one_seconds ()
1297 // TODO get rid of this..
1298 // ShuttleControl is updated directly via TransportStateChange signal
1302 ARDOUR_UI::every_point_zero_something_seconds ()
1304 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1306 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1307 float mpeak = editor_meter->update_meters();
1308 if (mpeak > editor_meter_max_peak) {
1309 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1310 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1317 ARDOUR_UI::set_fps_timeout_connection ()
1319 unsigned int interval = 40;
1320 if (!_session) return;
1321 if (_session->timecode_frames_per_second() != 0) {
1322 /* ideally we'll use a select() to sleep and not accumulate
1323 * idle time to provide a regular periodic signal.
1324 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1325 * However, that'll require a dedicated thread and cross-thread
1326 * signals to the GUI Thread..
1328 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1329 * _session->frame_rate() / _session->nominal_frame_rate()
1330 / _session->timecode_frames_per_second()
1332 #ifdef PLATFORM_WINDOWS
1333 // the smallest windows scheduler time-slice is ~15ms.
1334 // periodic GUI timeouts shorter than that will cause
1335 // WaitForSingleObject to spinlock (100% of one CPU Core)
1336 // and gtk never enters idle mode.
1337 // also changing timeBeginPeriod(1) does not affect that in
1338 // any beneficial way, so we just limit the max rate for now.
1339 interval = std::max(30u, interval); // at most ~33Hz.
1341 interval = std::max(8u, interval); // at most 120Hz.
1344 fps_connection.disconnect();
1345 Timers::set_fps_interval (interval);
1349 ARDOUR_UI::update_sample_rate (framecnt_t)
1353 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1355 if (!AudioEngine::instance()->connected()) {
1357 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1361 framecnt_t rate = AudioEngine::instance()->sample_rate();
1364 /* no sample rate available */
1365 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1368 if (fmod (rate, 1000.0) != 0.0) {
1369 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1370 (float) rate / 1000.0f,
1371 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1373 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1375 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1379 sample_rate_label.set_markup (buf);
1383 ARDOUR_UI::update_format ()
1386 format_label.set_text ("");
1391 s << _("File:") << X_(" <span foreground=\"green\">");
1393 switch (_session->config.get_native_file_header_format ()) {
1425 switch (_session->config.get_native_file_data_format ()) {
1439 format_label.set_markup (s.str ());
1443 ARDOUR_UI::update_xrun_count ()
1447 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1448 should also be changed.
1452 const unsigned int x = _session->get_xrun_count ();
1454 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1456 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1459 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1461 xrun_label.set_markup (buf);
1462 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1466 ARDOUR_UI::update_cpu_load ()
1470 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1471 should also be changed.
1474 double const c = AudioEngine::instance()->get_dsp_load ();
1475 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1476 cpu_load_label.set_markup (buf);
1480 ARDOUR_UI::update_peak_thread_work ()
1483 const int c = SourceFactory::peak_work_queue_length ();
1485 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1486 peak_thread_work_label.set_markup (buf);
1488 peak_thread_work_label.set_markup (X_(""));
1493 ARDOUR_UI::update_buffer_load ()
1497 uint32_t const playback = _session ? _session->playback_load () : 100;
1498 uint32_t const capture = _session ? _session->capture_load () : 100;
1500 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1501 should also be changed.
1507 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1508 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1509 playback <= 5 ? X_("red") : X_("green"),
1511 capture <= 5 ? X_("red") : X_("green"),
1515 buffer_load_label.set_markup (buf);
1517 buffer_load_label.set_text ("");
1522 ARDOUR_UI::count_recenabled_streams (Route& route)
1524 Track* track = dynamic_cast<Track*>(&route);
1525 if (track && track->record_enabled()) {
1526 rec_enabled_streams += track->n_inputs().n_total();
1531 ARDOUR_UI::update_disk_space()
1533 if (_session == 0) {
1537 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1539 framecnt_t fr = _session->frame_rate();
1542 /* skip update - no SR available */
1547 /* Available space is unknown */
1548 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1549 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1550 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1552 rec_enabled_streams = 0;
1553 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1555 framecnt_t frames = opt_frames.get_value_or (0);
1557 if (rec_enabled_streams) {
1558 frames /= rec_enabled_streams;
1565 hrs = frames / (fr * 3600);
1568 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1570 frames -= hrs * fr * 3600;
1571 mins = frames / (fr * 60);
1572 frames -= mins * fr * 60;
1575 bool const low = (hrs == 0 && mins <= 30);
1579 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1580 low ? X_("red") : X_("green"),
1586 disk_space_label.set_markup (buf);
1590 ARDOUR_UI::update_timecode_format ()
1596 TimecodeSlave* tcslave;
1597 SyncSource sync_src = Config->get_sync_source();
1599 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1600 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1605 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1606 matching ? X_("green") : X_("red"),
1607 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1609 snprintf (buf, sizeof (buf), "TC: n/a");
1612 timecode_format_label.set_markup (buf);
1616 ARDOUR_UI::update_wall_clock ()
1620 static int last_min = -1;
1623 tm_now = localtime (&now);
1624 if (last_min != tm_now->tm_min) {
1626 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1627 wall_clock_label.set_text (buf);
1628 last_min = tm_now->tm_min;
1635 ARDOUR_UI::open_recent_session ()
1637 bool can_return = (_session != 0);
1639 SessionDialog recent_session_dialog;
1643 ResponseType r = (ResponseType) recent_session_dialog.run ();
1646 case RESPONSE_ACCEPT:
1650 recent_session_dialog.hide();
1657 recent_session_dialog.hide();
1661 std::string path = recent_session_dialog.session_folder();
1662 std::string state = recent_session_dialog.session_name (should_be_new);
1664 if (should_be_new == true) {
1668 _session_is_new = false;
1670 if (load_session (path, state) == 0) {
1679 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1681 if (!AudioEngine::instance()->connected()) {
1682 MessageDialog msg (parent, string_compose (
1683 _("%1 is not connected to any audio backend.\n"
1684 "You cannot open or close sessions in this condition"),
1686 pop_back_splash (msg);
1694 ARDOUR_UI::open_session ()
1696 if (!check_audioengine(*editor)) {
1700 /* ardour sessions are folders */
1701 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1702 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1703 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1704 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1707 string session_parent_dir = Glib::path_get_dirname(_session->path());
1708 open_session_selector.set_current_folder(session_parent_dir);
1710 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1713 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1715 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1716 string default_session_folder = Config->get_default_session_parent_dir();
1717 open_session_selector.add_shortcut_folder (default_session_folder);
1719 catch (Glib::Error & e) {
1720 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1723 FileFilter session_filter;
1724 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1725 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1726 open_session_selector.add_filter (session_filter);
1727 open_session_selector.set_filter (session_filter);
1729 int response = open_session_selector.run();
1730 open_session_selector.hide ();
1732 if (response == Gtk::RESPONSE_CANCEL) {
1736 string session_path = open_session_selector.get_filename();
1740 if (session_path.length() > 0) {
1741 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1742 _session_is_new = isnew;
1743 load_session (path, name);
1750 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1751 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1753 list<boost::shared_ptr<MidiTrack> > tracks;
1755 if (_session == 0) {
1756 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1761 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1763 if (tracks.size() != how_many) {
1764 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1769 MessageDialog msg (_main_window,
1770 string_compose (_("There are insufficient ports available\n\
1771 to create a new track or bus.\n\
1772 You should save %1, exit and\n\
1773 restart with more ports."), PROGRAM_NAME));
1780 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1782 ChanCount one_midi_channel;
1783 one_midi_channel.set (DataType::MIDI, 1);
1786 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1791 ARDOUR_UI::session_add_audio_route (
1793 int32_t input_channels,
1794 int32_t output_channels,
1795 ARDOUR::TrackMode mode,
1796 RouteGroup* route_group,
1798 string const & name_template
1801 list<boost::shared_ptr<AudioTrack> > tracks;
1804 if (_session == 0) {
1805 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1811 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1813 if (tracks.size() != how_many) {
1814 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1820 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1822 if (routes.size() != how_many) {
1823 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1830 MessageDialog msg (_main_window,
1831 string_compose (_("There are insufficient ports available\n\
1832 to create a new track or bus.\n\
1833 You should save %1, exit and\n\
1834 restart with more ports."), PROGRAM_NAME));
1835 pop_back_splash (msg);
1841 ARDOUR_UI::transport_goto_start ()
1844 _session->goto_start();
1846 /* force displayed area in editor to start no matter
1847 what "follow playhead" setting is.
1851 editor->center_screen (_session->current_start_frame ());
1857 ARDOUR_UI::transport_goto_zero ()
1860 _session->request_locate (0);
1862 /* force displayed area in editor to start no matter
1863 what "follow playhead" setting is.
1867 editor->reset_x_origin (0);
1873 ARDOUR_UI::transport_goto_wallclock ()
1875 if (_session && editor) {
1882 localtime_r (&now, &tmnow);
1884 framecnt_t frame_rate = _session->frame_rate();
1886 if (frame_rate == 0) {
1887 /* no frame rate available */
1891 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1892 frames += tmnow.tm_min * (60 * frame_rate);
1893 frames += tmnow.tm_sec * frame_rate;
1895 _session->request_locate (frames, _session->transport_rolling ());
1897 /* force displayed area in editor to start no matter
1898 what "follow playhead" setting is.
1902 editor->center_screen (frames);
1908 ARDOUR_UI::transport_goto_end ()
1911 framepos_t const frame = _session->current_end_frame();
1912 _session->request_locate (frame);
1914 /* force displayed area in editor to start no matter
1915 what "follow playhead" setting is.
1919 editor->center_screen (frame);
1925 ARDOUR_UI::transport_stop ()
1931 if (_session->is_auditioning()) {
1932 _session->cancel_audition ();
1936 _session->request_stop (false, true);
1939 /** Check if any tracks are record enabled. If none are, record enable all of them.
1940 * @return true if track record-enabled status was changed, false otherwise.
1943 ARDOUR_UI::trx_record_enable_all_tracks ()
1949 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1950 bool none_record_enabled = true;
1952 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1953 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1956 if (t->record_enabled()) {
1957 none_record_enabled = false;
1962 if (none_record_enabled) {
1963 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1966 return none_record_enabled;
1970 ARDOUR_UI::transport_record (bool roll)
1973 switch (_session->record_status()) {
1974 case Session::Disabled:
1975 if (_session->ntracks() == 0) {
1976 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."));
1980 if (Profile->get_trx()) {
1981 roll = trx_record_enable_all_tracks ();
1983 _session->maybe_enable_record ();
1988 case Session::Recording:
1990 _session->request_stop();
1992 _session->disable_record (false, true);
1996 case Session::Enabled:
1997 _session->disable_record (false, true);
2003 ARDOUR_UI::transport_roll ()
2009 if (_session->is_auditioning()) {
2014 if (_session->config.get_external_sync()) {
2015 switch (Config->get_sync_source()) {
2019 /* transport controlled by the master */
2025 bool rolling = _session->transport_rolling();
2027 if (_session->get_play_loop()) {
2029 /* If loop playback is not a mode, then we should cancel
2030 it when this action is requested. If it is a mode
2031 we just leave it in place.
2034 if (!Config->get_loop_is_mode()) {
2035 /* XXX it is not possible to just leave seamless loop and keep
2036 playing at present (nov 4th 2009)
2038 if (!Config->get_seamless_loop()) {
2039 /* stop loop playback and stop rolling */
2040 _session->request_play_loop (false, true);
2041 } else if (rolling) {
2042 /* stop loop playback but keep rolling */
2043 _session->request_play_loop (false, false);
2047 } else if (_session->get_play_range () ) {
2048 /* stop playing a range if we currently are */
2049 _session->request_play_range (0, true);
2053 _session->request_transport_speed (1.0f);
2058 ARDOUR_UI::get_smart_mode() const
2060 return ( editor->get_smart_mode() );
2065 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2071 if (_session->is_auditioning()) {
2072 _session->cancel_audition ();
2076 if (_session->config.get_external_sync()) {
2077 switch (Config->get_sync_source()) {
2081 /* transport controlled by the master */
2086 bool rolling = _session->transport_rolling();
2087 bool affect_transport = true;
2089 if (rolling && roll_out_of_bounded_mode) {
2090 /* drop out of loop/range playback but leave transport rolling */
2091 if (_session->get_play_loop()) {
2092 if (_session->actively_recording()) {
2094 /* just stop using the loop, then actually stop
2097 _session->request_play_loop (false, affect_transport);
2100 if (Config->get_seamless_loop()) {
2101 /* the disk buffers contain copies of the loop - we can't
2102 just keep playing, so stop the transport. the user
2103 can restart as they wish.
2105 affect_transport = true;
2107 /* disk buffers are normal, so we can keep playing */
2108 affect_transport = false;
2110 _session->request_play_loop (false, affect_transport);
2112 } else if (_session->get_play_range ()) {
2113 affect_transport = false;
2114 _session->request_play_range (0, true);
2118 if (affect_transport) {
2120 _session->request_stop (with_abort, true);
2122 /* the only external sync condition we can be in here
2123 * would be Engine (JACK) sync, in which case we still
2127 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
2128 _session->request_play_range (&editor->get_selection().time, true);
2129 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2131 _session->request_transport_speed (1.0f);
2137 ARDOUR_UI::toggle_session_auto_loop ()
2143 Location * looploc = _session->locations()->auto_loop_location();
2149 if (_session->get_play_loop()) {
2151 /* looping enabled, our job is to disable it */
2153 _session->request_play_loop (false);
2157 /* looping not enabled, our job is to enable it.
2159 loop-is-NOT-mode: this action always starts the transport rolling.
2160 loop-IS-mode: this action simply sets the loop play mechanism, but
2161 does not start transport.
2163 if (Config->get_loop_is_mode()) {
2164 _session->request_play_loop (true, false);
2166 _session->request_play_loop (true, true);
2170 //show the loop markers
2171 looploc->set_hidden (false, this);
2175 ARDOUR_UI::transport_play_selection ()
2181 editor->play_selection ();
2185 ARDOUR_UI::transport_play_preroll ()
2190 editor->play_with_preroll ();
2194 ARDOUR_UI::transport_rewind (int option)
2196 float current_transport_speed;
2199 current_transport_speed = _session->transport_speed();
2201 if (current_transport_speed >= 0.0f) {
2204 _session->request_transport_speed (-1.0f);
2207 _session->request_transport_speed (-4.0f);
2210 _session->request_transport_speed (-0.5f);
2215 _session->request_transport_speed (current_transport_speed * 1.5f);
2221 ARDOUR_UI::transport_forward (int option)
2227 float current_transport_speed = _session->transport_speed();
2229 if (current_transport_speed <= 0.0f) {
2232 _session->request_transport_speed (1.0f);
2235 _session->request_transport_speed (4.0f);
2238 _session->request_transport_speed (0.5f);
2243 _session->request_transport_speed (current_transport_speed * 1.5f);
2248 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2254 boost::shared_ptr<Route> r;
2256 if ((r = _session->route_by_remote_id (rid)) != 0) {
2258 boost::shared_ptr<Track> t;
2260 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2261 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2267 ARDOUR_UI::map_transport_state ()
2270 auto_loop_button.unset_active_state ();
2271 play_selection_button.unset_active_state ();
2272 roll_button.unset_active_state ();
2273 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2277 shuttle_box->map_transport_state ();
2279 float sp = _session->transport_speed();
2285 if (_session->get_play_range()) {
2287 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2288 roll_button.unset_active_state ();
2289 auto_loop_button.unset_active_state ();
2291 } else if (_session->get_play_loop ()) {
2293 auto_loop_button.set_active (true);
2294 play_selection_button.set_active (false);
2295 if (Config->get_loop_is_mode()) {
2296 roll_button.set_active (true);
2298 roll_button.set_active (false);
2303 roll_button.set_active (true);
2304 play_selection_button.set_active (false);
2305 auto_loop_button.set_active (false);
2308 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2309 /* light up both roll and play-selection if they are joined */
2310 roll_button.set_active (true);
2311 play_selection_button.set_active (true);
2314 stop_button.set_active (false);
2318 stop_button.set_active (true);
2319 roll_button.set_active (false);
2320 play_selection_button.set_active (false);
2321 if (Config->get_loop_is_mode ()) {
2322 auto_loop_button.set_active (_session->get_play_loop());
2324 auto_loop_button.set_active (false);
2326 update_disk_space ();
2331 ARDOUR_UI::blink_handler (bool blink_on)
2333 transport_rec_enable_blink (blink_on);
2334 solo_blink (blink_on);
2335 sync_blink (blink_on);
2336 audition_blink (blink_on);
2337 feedback_blink (blink_on);
2338 error_blink (blink_on);
2342 ARDOUR_UI::update_clocks ()
2344 if (!_session) return;
2346 if (editor && !editor->dragging_playhead()) {
2347 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2352 ARDOUR_UI::start_clocking ()
2354 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2355 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2357 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2362 ARDOUR_UI::stop_clocking ()
2364 clock_signal_connection.disconnect ();
2368 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2372 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2374 label->set_text (buf);
2375 bar->set_fraction (fraction);
2377 /* process events, redraws, etc. */
2379 while (gtk_events_pending()) {
2380 gtk_main_iteration ();
2383 return true; /* continue with save-as */
2387 ARDOUR_UI::save_session_as ()
2393 if (!save_as_dialog) {
2394 save_as_dialog = new SaveAsDialog;
2397 save_as_dialog->set_name (_session->name());
2399 int response = save_as_dialog->run ();
2401 save_as_dialog->hide ();
2404 case Gtk::RESPONSE_OK:
2413 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2414 sa.new_name = save_as_dialog->new_name ();
2415 sa.switch_to = save_as_dialog->switch_to();
2416 sa.copy_media = save_as_dialog->copy_media();
2417 sa.copy_external = save_as_dialog->copy_external();
2418 sa.include_media = save_as_dialog->include_media ();
2420 /* Only bother with a progress dialog if we're going to copy
2421 media into the save-as target. Without that choice, this
2422 will be very fast because we're only talking about a few kB's to
2423 perhaps a couple of MB's of data.
2426 ArdourDialog progress_dialog (_("Save As"), true);
2428 if (sa.include_media && sa.copy_media) {
2431 Gtk::ProgressBar progress_bar;
2433 progress_dialog.get_vbox()->pack_start (label);
2434 progress_dialog.get_vbox()->pack_start (progress_bar);
2436 progress_bar.show ();
2438 /* this signal will be emitted from within this, the calling thread,
2439 * after every file is copied. It provides information on percentage
2440 * complete (in terms of total data to copy), the number of files
2441 * copied so far, and the total number to copy.
2446 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2448 progress_dialog.show_all ();
2449 progress_dialog.present ();
2452 if (_session->save_as (sa)) {
2454 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2458 if (!sa.include_media) {
2459 unload_session (false);
2460 load_session (sa.final_session_folder_name, sa.new_name);
2465 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2469 struct tm local_time;
2472 localtime_r (&n, &local_time);
2473 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2475 save_state (timebuf, switch_to_it);
2480 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2484 prompter.get_result (snapname);
2486 bool do_save = (snapname.length() != 0);
2489 char illegal = Session::session_name_is_legal(snapname);
2491 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2492 "snapshot names may not contain a '%1' character"), illegal));
2498 vector<std::string> p;
2499 get_state_files_in_directory (_session->session_directory().root_path(), p);
2500 vector<string> n = get_file_names_no_extension (p);
2502 if (find (n.begin(), n.end(), snapname) != n.end()) {
2504 do_save = overwrite_file_dialog (prompter,
2505 _("Confirm Snapshot Overwrite"),
2506 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2510 save_state (snapname, switch_to_it);
2520 /** Ask the user for the name of a new snapshot and then take it.
2524 ARDOUR_UI::snapshot_session (bool switch_to_it)
2526 ArdourPrompter prompter (true);
2528 prompter.set_name ("Prompter");
2529 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2531 prompter.set_title (_("Save as..."));
2532 prompter.set_prompt (_("New session name"));
2534 prompter.set_title (_("Take Snapshot"));
2535 prompter.set_prompt (_("Name of new snapshot"));
2539 prompter.set_initial_text (_session->snap_name());
2543 struct tm local_time;
2546 localtime_r (&n, &local_time);
2547 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2548 prompter.set_initial_text (timebuf);
2551 bool finished = false;
2553 switch (prompter.run()) {
2554 case RESPONSE_ACCEPT:
2556 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2567 /** Ask the user for a new session name and then rename the session to it.
2571 ARDOUR_UI::rename_session ()
2577 ArdourPrompter prompter (true);
2580 prompter.set_name ("Prompter");
2581 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2582 prompter.set_title (_("Rename Session"));
2583 prompter.set_prompt (_("New session name"));
2586 switch (prompter.run()) {
2587 case RESPONSE_ACCEPT:
2589 prompter.get_result (name);
2591 bool do_rename = (name.length() != 0);
2594 char illegal = Session::session_name_is_legal (name);
2597 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2598 "session names may not contain a '%1' character"), illegal));
2603 switch (_session->rename (name)) {
2605 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2606 msg.set_position (WIN_POS_MOUSE);
2614 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2615 msg.set_position (WIN_POS_MOUSE);
2631 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2633 if (!_session || _session->deletion_in_progress()) {
2637 XMLNode* node = new XMLNode (X_("UI"));
2639 WM::Manager::instance().add_state (*node);
2641 node->add_child_nocopy (gui_object_state->get_state());
2643 _session->add_extra_xml (*node);
2645 if (export_video_dialog) {
2646 _session->add_extra_xml (export_video_dialog->get_state());
2649 save_state_canfail (name, switch_to_it);
2653 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2658 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2663 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2668 ARDOUR_UI::primary_clock_value_changed ()
2671 _session->request_locate (primary_clock->current_time ());
2676 ARDOUR_UI::big_clock_value_changed ()
2679 _session->request_locate (big_clock->current_time ());
2684 ARDOUR_UI::secondary_clock_value_changed ()
2687 _session->request_locate (secondary_clock->current_time ());
2692 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2694 if (_session == 0) {
2698 if (_session->step_editing()) {
2702 Session::RecordState const r = _session->record_status ();
2703 bool const h = _session->have_rec_enabled_track ();
2705 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2707 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2709 rec_button.set_active_state (Gtkmm2ext::Off);
2711 } else if (r == Session::Recording && h) {
2712 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2714 rec_button.unset_active_state ();
2719 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2723 prompter.get_result (name);
2725 if (name.length()) {
2726 int failed = _session->save_template (name);
2728 if (failed == -2) { /* file already exists. */
2729 bool overwrite = overwrite_file_dialog (prompter,
2730 _("Confirm Template Overwrite"),
2731 _("A template already exists with that name. Do you want to overwrite it?"));
2734 _session->save_template (name, true);
2746 ARDOUR_UI::save_template ()
2748 ArdourPrompter prompter (true);
2750 if (!check_audioengine(*editor)) {
2754 prompter.set_name (X_("Prompter"));
2755 prompter.set_title (_("Save Template"));
2756 prompter.set_prompt (_("Name for template:"));
2757 prompter.set_initial_text(_session->name() + _("-template"));
2758 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2760 bool finished = false;
2762 switch (prompter.run()) {
2763 case RESPONSE_ACCEPT:
2764 finished = process_save_template_prompter (prompter);
2775 ARDOUR_UI::edit_metadata ()
2777 SessionMetadataEditor dialog;
2778 dialog.set_session (_session);
2779 dialog.grab_focus ();
2784 ARDOUR_UI::import_metadata ()
2786 SessionMetadataImporter dialog;
2787 dialog.set_session (_session);
2792 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2794 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2796 MessageDialog msg (str,
2798 Gtk::MESSAGE_WARNING,
2799 Gtk::BUTTONS_YES_NO,
2803 msg.set_name (X_("OpenExistingDialog"));
2804 msg.set_title (_("Open Existing Session"));
2805 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2806 msg.set_position (Gtk::WIN_POS_CENTER);
2807 pop_back_splash (msg);
2809 switch (msg.run()) {
2818 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2820 BusProfile bus_profile;
2822 if (nsm || Profile->get_sae()) {
2824 bus_profile.master_out_channels = 2;
2825 bus_profile.input_ac = AutoConnectPhysical;
2826 bus_profile.output_ac = AutoConnectMaster;
2827 bus_profile.requested_physical_in = 0; // use all available
2828 bus_profile.requested_physical_out = 0; // use all available
2832 /* get settings from advanced section of NSD */
2834 if (sd.create_master_bus()) {
2835 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2837 bus_profile.master_out_channels = 0;
2840 if (sd.connect_inputs()) {
2841 bus_profile.input_ac = AutoConnectPhysical;
2843 bus_profile.input_ac = AutoConnectOption (0);
2846 bus_profile.output_ac = AutoConnectOption (0);
2848 if (sd.connect_outputs ()) {
2849 if (sd.connect_outs_to_master()) {
2850 bus_profile.output_ac = AutoConnectMaster;
2851 } else if (sd.connect_outs_to_physical()) {
2852 bus_profile.output_ac = AutoConnectPhysical;
2856 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2857 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2860 if (build_session (session_path, session_name, bus_profile)) {
2868 ARDOUR_UI::load_from_application_api (const std::string& path)
2870 ARDOUR_COMMAND_LINE::session_name = path;
2871 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2873 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2875 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2876 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2877 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2878 * -> SessionDialog is not displayed
2881 if (_session_dialog) {
2882 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2883 std::string session_path = path;
2884 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2885 session_path = Glib::path_get_dirname (session_path);
2887 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2888 _session_dialog->set_provided_session (session_name, session_path);
2889 _session_dialog->response (RESPONSE_NONE);
2890 _session_dialog->hide();
2895 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2896 /* /path/to/foo => /path/to/foo, foo */
2897 rv = load_session (path, basename_nosuffix (path));
2899 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2900 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2903 // if load_session fails -> pop up SessionDialog.
2905 ARDOUR_COMMAND_LINE::session_name = "";
2907 if (get_session_parameters (true, false)) {
2911 goto_editor_window ();
2915 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2917 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2919 string session_name;
2920 string session_path;
2921 string template_name;
2923 bool likely_new = false;
2924 bool cancel_not_quit;
2926 /* deal with any existing DIRTY session now, rather than later. don't
2927 * treat a non-dirty session this way, so that it stays visible
2928 * as we bring up the new session dialog.
2931 if (_session && ARDOUR_UI::instance()->video_timeline) {
2932 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2935 /* if there is already a session, relabel the button
2936 on the SessionDialog so that we don't Quit directly
2938 cancel_not_quit = (_session != 0);
2940 if (_session && _session->dirty()) {
2941 if (unload_session (false)) {
2942 /* unload cancelled by user */
2945 ARDOUR_COMMAND_LINE::session_name = "";
2948 if (!load_template.empty()) {
2949 should_be_new = true;
2950 template_name = load_template;
2953 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2954 session_path = ARDOUR_COMMAND_LINE::session_name;
2956 if (!session_path.empty()) {
2957 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2958 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2959 /* session/snapshot file, change path to be dir */
2960 session_path = Glib::path_get_dirname (session_path);
2965 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2967 _session_dialog = &session_dialog;
2970 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2972 /* if they named a specific statefile, use it, otherwise they are
2973 just giving a session folder, and we want to use it as is
2974 to find the session.
2977 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2979 if (suffix != string::npos) {
2980 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2981 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2982 session_name = Glib::path_get_basename (session_name);
2984 session_path = ARDOUR_COMMAND_LINE::session_name;
2985 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2990 session_dialog.clear_given ();
2993 if (should_be_new || session_name.empty()) {
2994 /* need the dialog to get info from user */
2996 cerr << "run dialog\n";
2998 switch (session_dialog.run()) {
2999 case RESPONSE_ACCEPT:
3002 /* this is used for async * app->ShouldLoad(). */
3003 continue; // while loop
3006 if (quit_on_cancel) {
3007 // JE - Currently (July 2014) this section can only get reached if the
3008 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3009 // point does NOT indicate an abnormal termination). Therefore, let's
3010 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3012 pthread_cancel_all ();
3020 session_dialog.hide ();
3023 /* if we run the startup dialog again, offer more than just "new session" */
3025 should_be_new = false;
3027 session_name = session_dialog.session_name (likely_new);
3028 session_path = session_dialog.session_folder ();
3034 string::size_type suffix = session_name.find (statefile_suffix);
3036 if (suffix != string::npos) {
3037 session_name = session_name.substr (0, suffix);
3040 /* this shouldn't happen, but we catch it just in case it does */
3042 if (session_name.empty()) {
3046 if (session_dialog.use_session_template()) {
3047 template_name = session_dialog.session_template_name();
3048 _session_is_new = true;
3051 if (session_name[0] == G_DIR_SEPARATOR ||
3052 #ifdef PLATFORM_WINDOWS
3053 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3055 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3056 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3061 /* absolute path or cwd-relative path specified for session name: infer session folder
3062 from what was given.
3065 session_path = Glib::path_get_dirname (session_name);
3066 session_name = Glib::path_get_basename (session_name);
3070 session_path = session_dialog.session_folder();
3072 char illegal = Session::session_name_is_legal (session_name);
3075 MessageDialog msg (session_dialog,
3076 string_compose (_("To ensure compatibility with various systems\n"
3077 "session names may not contain a '%1' character"),
3080 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3085 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3088 if (likely_new && !nsm) {
3090 std::string existing = Glib::build_filename (session_path, session_name);
3092 if (!ask_about_loading_existing_session (existing)) {
3093 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3098 _session_is_new = false;
3103 pop_back_splash (session_dialog);
3104 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3106 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3110 char illegal = Session::session_name_is_legal(session_name);
3113 pop_back_splash (session_dialog);
3114 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3115 "session names may not contain a '%1' character"), illegal));
3117 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3121 _session_is_new = true;
3124 if (likely_new && template_name.empty()) {
3126 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3130 ret = load_session (session_path, session_name, template_name);
3133 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3137 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3138 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3142 /* clear this to avoid endless attempts to load the
3146 ARDOUR_COMMAND_LINE::session_name = "";
3150 _session_dialog = NULL;
3156 ARDOUR_UI::close_session()
3158 if (!check_audioengine(*editor)) {
3162 if (unload_session (true)) {
3166 ARDOUR_COMMAND_LINE::session_name = "";
3168 if (get_session_parameters (true, false)) {
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;
3308 _session->set_clean ();
3311 #ifdef WINDOWS_VST_SUPPORT
3312 fst_stop_threading();
3316 Timers::TimerSuspender t;
3320 #ifdef WINDOWS_VST_SUPPORT
3321 fst_start_threading();
3330 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3332 Session *new_session;
3335 session_loaded = false;
3336 x = unload_session ();
3344 _session_is_new = true;
3347 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3350 catch (SessionException e) {
3352 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3353 msg.set_title (_("Loading Error"));
3354 msg.set_position (Gtk::WIN_POS_CENTER);
3355 pop_back_splash (msg);
3361 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3362 msg.set_title (_("Loading Error"));
3363 msg.set_position (Gtk::WIN_POS_CENTER);
3364 pop_back_splash (msg);
3369 /* Give the new session the default GUI state, if such things exist */
3372 n = Config->instant_xml (X_("Editor"));
3374 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3375 new_session->add_instant_xml (*n, false);
3377 n = Config->instant_xml (X_("Mixer"));
3379 new_session->add_instant_xml (*n, false);
3382 /* Put the playhead at 0 and scroll fully left */
3383 n = new_session->instant_xml (X_("Editor"));
3385 n->add_property (X_("playhead"), X_("0"));
3386 n->add_property (X_("left-frame"), X_("0"));
3389 set_session (new_session);
3391 session_loaded = true;
3393 new_session->save_state(new_session->name());
3399 ARDOUR_UI::launch_chat ()
3401 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3403 dialog.set_title (_("About the Chat"));
3404 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."));
3406 switch (dialog.run()) {
3409 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3410 #elif defined PLATFORM_WINDOWS
3411 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3413 open_uri("http://webchat.freenode.net/?channels=ardour");
3422 ARDOUR_UI::launch_manual ()
3424 PBD::open_uri (Config->get_tutorial_manual_url());
3428 ARDOUR_UI::launch_reference ()
3430 PBD::open_uri (Config->get_reference_manual_url());
3434 ARDOUR_UI::launch_tracker ()
3436 PBD::open_uri ("http://tracker.ardour.org");
3440 ARDOUR_UI::launch_subscribe ()
3442 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3446 ARDOUR_UI::launch_cheat_sheet ()
3449 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3451 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3456 ARDOUR_UI::launch_website ()
3458 PBD::open_uri ("http://ardour.org");
3462 ARDOUR_UI::launch_website_dev ()
3464 PBD::open_uri ("http://ardour.org/development.html");
3468 ARDOUR_UI::launch_forums ()
3470 PBD::open_uri ("https://community.ardour.org/forums");
3474 ARDOUR_UI::launch_howto_report ()
3476 PBD::open_uri ("http://ardour.org/reporting_bugs");
3480 ARDOUR_UI::loading_message (const std::string& msg)
3482 if (ARDOUR_COMMAND_LINE::no_splash) {
3490 splash->message (msg);
3494 ARDOUR_UI::show_splash ()
3498 splash = new Splash;
3508 ARDOUR_UI::hide_splash ()
3515 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3519 removed = rep.paths.size();
3522 MessageDialog msgd (_main_window,
3523 _("No files were ready for clean-up"),
3527 msgd.set_title (_("Clean-up"));
3528 msgd.set_secondary_text (_("If this seems suprising, \n\
3529 check for any existing snapshots.\n\
3530 These may still include regions that\n\
3531 require some unused files to continue to exist."));
3537 ArdourDialog results (_("Clean-up"), true, false);
3539 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3540 CleanupResultsModelColumns() {
3544 Gtk::TreeModelColumn<std::string> visible_name;
3545 Gtk::TreeModelColumn<std::string> fullpath;
3549 CleanupResultsModelColumns results_columns;
3550 Glib::RefPtr<Gtk::ListStore> results_model;
3551 Gtk::TreeView results_display;
3553 results_model = ListStore::create (results_columns);
3554 results_display.set_model (results_model);
3555 results_display.append_column (list_title, results_columns.visible_name);
3557 results_display.set_name ("CleanupResultsList");
3558 results_display.set_headers_visible (true);
3559 results_display.set_headers_clickable (false);
3560 results_display.set_reorderable (false);
3562 Gtk::ScrolledWindow list_scroller;
3565 Gtk::HBox dhbox; // the hbox for the image and text
3566 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3567 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3569 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3571 const string dead_directory = _session->session_directory().dead_path();
3574 %1 - number of files removed
3575 %2 - location of "dead"
3576 %3 - size of files affected
3577 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3580 const char* bprefix;
3581 double space_adjusted = 0;
3583 if (rep.space < 1000) {
3585 space_adjusted = rep.space;
3586 } else if (rep.space < 1000000) {
3587 bprefix = _("kilo");
3588 space_adjusted = floorf((float)rep.space / 1000.0);
3589 } else if (rep.space < 1000000 * 1000) {
3590 bprefix = _("mega");
3591 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3593 bprefix = _("giga");
3594 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3598 txt.set_markup (string_compose (P_("\
3599 The following file was deleted from %2,\n\
3600 releasing %3 %4bytes of disk space", "\
3601 The following %1 files were deleted from %2,\n\
3602 releasing %3 %4bytes of disk space", removed),
3603 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3605 txt.set_markup (string_compose (P_("\
3606 The following file was not in use and \n\
3607 has been moved to: %2\n\n\
3608 After a restart of %5\n\n\
3609 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3610 will release an additional %3 %4bytes of disk space.\n", "\
3611 The following %1 files were not in use and \n\
3612 have been moved to: %2\n\n\
3613 After a restart of %5\n\n\
3614 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3615 will release an additional %3 %4bytes of disk space.\n", removed),
3616 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3619 dhbox.pack_start (*dimage, true, false, 5);
3620 dhbox.pack_start (txt, true, false, 5);
3622 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3623 TreeModel::Row row = *(results_model->append());
3624 row[results_columns.visible_name] = *i;
3625 row[results_columns.fullpath] = *i;
3628 list_scroller.add (results_display);
3629 list_scroller.set_size_request (-1, 150);
3630 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3632 dvbox.pack_start (dhbox, true, false, 5);
3633 dvbox.pack_start (list_scroller, true, false, 5);
3634 ddhbox.pack_start (dvbox, true, false, 5);
3636 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3637 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3638 results.set_default_response (RESPONSE_CLOSE);
3639 results.set_position (Gtk::WIN_POS_MOUSE);
3641 results_display.show();
3642 list_scroller.show();
3649 //results.get_vbox()->show();
3650 results.set_resizable (false);
3657 ARDOUR_UI::cleanup ()
3659 if (_session == 0) {
3660 /* shouldn't happen: menu item is insensitive */
3665 MessageDialog checker (_("Are you sure you want to clean-up?"),
3667 Gtk::MESSAGE_QUESTION,
3670 checker.set_title (_("Clean-up"));
3672 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3673 ALL undo/redo information will be lost if you clean-up.\n\
3674 Clean-up will move all unused files to a \"dead\" location."));
3676 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3677 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3678 checker.set_default_response (RESPONSE_CANCEL);
3680 checker.set_name (_("CleanupDialog"));
3681 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3682 checker.set_position (Gtk::WIN_POS_MOUSE);
3684 switch (checker.run()) {
3685 case RESPONSE_ACCEPT:
3691 ARDOUR::CleanupReport rep;
3693 editor->prepare_for_cleanup ();
3695 /* do not allow flush until a session is reloaded */
3697 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3699 act->set_sensitive (false);
3702 if (_session->cleanup_sources (rep)) {
3703 editor->finish_cleanup ();
3707 editor->finish_cleanup ();
3710 display_cleanup_results (rep, _("Cleaned Files"), false);
3714 ARDOUR_UI::flush_trash ()
3716 if (_session == 0) {
3717 /* shouldn't happen: menu item is insensitive */
3721 ARDOUR::CleanupReport rep;
3723 if (_session->cleanup_trash_sources (rep)) {
3727 display_cleanup_results (rep, _("deleted file"), true);
3731 ARDOUR_UI::cleanup_peakfiles ()
3733 if (_session == 0) {
3734 /* shouldn't happen: menu item is insensitive */
3738 if (! _session->can_cleanup_peakfiles ()) {
3742 // get all region-views in this session
3744 TrackViewList empty;
3746 editor->get_regions_after(rs, (framepos_t) 0, empty);
3747 std::list<RegionView*> views = rs.by_layer();
3749 // remove displayed audio-region-views waveforms
3750 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3751 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3752 if (!arv) { continue ; }
3753 arv->delete_waves();
3756 // cleanup peak files:
3757 // - stop pending peakfile threads
3758 // - close peakfiles if any
3759 // - remove peak dir in session
3760 // - setup peakfiles (background thread)
3761 _session->cleanup_peakfiles ();
3763 // re-add waves to ARV
3764 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3765 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3766 if (!arv) { continue ; }
3767 arv->create_waves();
3772 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3774 uint32_t order_hint = UINT32_MAX;
3776 if (editor->get_selection().tracks.empty()) {
3781 we want the new routes to have their order keys set starting from
3782 the highest order key in the selection + 1 (if available).
3785 if (place == AddRouteDialog::AfterSelection) {
3786 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3788 order_hint = rtav->route()->order_key();
3791 } else if (place == AddRouteDialog::BeforeSelection) {
3792 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3794 order_hint = rtav->route()->order_key();
3796 } else if (place == AddRouteDialog::First) {
3799 /* leave order_hint at UINT32_MAX */
3802 if (order_hint == UINT32_MAX) {
3803 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3804 * not setting an order hint will place new routes last.
3809 _session->set_order_hint (order_hint);
3811 /* create a gap in the existing route order keys to accomodate new routes.*/
3812 boost::shared_ptr <RouteList> rd = _session->get_routes();
3813 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3814 boost::shared_ptr<Route> rt (*ri);
3816 if (rt->is_monitor()) {
3820 if (rt->order_key () >= order_hint) {
3821 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3827 ARDOUR_UI::start_duplicate_routes ()
3829 if (!duplicate_routes_dialog) {
3830 duplicate_routes_dialog = new DuplicateRouteDialog;
3833 if (duplicate_routes_dialog->restart (_session)) {
3837 duplicate_routes_dialog->present ();
3841 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3849 if (add_route_dialog->is_visible()) {
3850 /* we're already doing this */
3854 ResponseType r = (ResponseType) add_route_dialog->run ();
3856 add_route_dialog->hide();
3859 case RESPONSE_ACCEPT:
3866 if ((count = add_route_dialog->count()) <= 0) {
3870 setup_order_hint(add_route_dialog->insert_at());
3872 string template_path = add_route_dialog->track_template();
3873 DisplaySuspender ds;
3875 if (!template_path.empty()) {
3876 if (add_route_dialog->name_template_is_default()) {
3877 _session->new_route_from_template (count, template_path, string());
3879 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3884 ChanCount input_chan= add_route_dialog->channels ();
3885 ChanCount output_chan;
3886 string name_template = add_route_dialog->name_template ();
3887 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3888 RouteGroup* route_group = add_route_dialog->route_group ();
3889 AutoConnectOption oac = Config->get_output_auto_connect();
3891 if (oac & AutoConnectMaster) {
3892 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3893 output_chan.set (DataType::MIDI, 0);
3895 output_chan = input_chan;
3898 /* XXX do something with name template */
3900 switch (add_route_dialog->type_wanted()) {
3901 case AddRouteDialog::AudioTrack:
3902 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3904 case AddRouteDialog::MidiTrack:
3905 session_add_midi_track (route_group, count, name_template, instrument);
3907 case AddRouteDialog::MixedTrack:
3908 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3910 case AddRouteDialog::AudioBus:
3911 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3917 ARDOUR_UI::stop_video_server (bool ask_confirm)
3919 if (!video_server_process && ask_confirm) {
3920 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3922 if (video_server_process) {
3924 ArdourDialog confirm (_("Stop Video-Server"), true);
3925 Label m (_("Do you really want to stop the Video Server?"));
3926 confirm.get_vbox()->pack_start (m, true, true);
3927 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3928 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3929 confirm.show_all ();
3930 if (confirm.run() == RESPONSE_CANCEL) {
3934 delete video_server_process;
3935 video_server_process =0;
3940 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3942 ARDOUR_UI::start_video_server( float_window, true);
3946 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3952 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3953 if (video_server_process) {
3954 popup_error(_("The Video Server is already started."));
3956 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3962 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3964 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3966 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3968 video_server_dialog->set_transient_for (*float_window);
3971 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3972 video_server_dialog->hide();
3974 ResponseType r = (ResponseType) video_server_dialog->run ();
3975 video_server_dialog->hide();
3976 if (r != RESPONSE_ACCEPT) { return false; }
3977 if (video_server_dialog->show_again()) {
3978 Config->set_show_video_server_dialog(false);
3982 std::string icsd_exec = video_server_dialog->get_exec_path();
3983 std::string icsd_docroot = video_server_dialog->get_docroot();
3984 if (icsd_docroot.empty()) {
3985 #ifndef PLATFORM_WINDOWS
3986 icsd_docroot = X_("/");
3988 icsd_docroot = X_("C:\\");
3993 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
3994 warning << _("Specified docroot is not an existing directory.") << endmsg;
3997 #ifndef PLATFORM_WINDOWS
3998 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
3999 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4000 warning << _("Given Video Server is not an executable file.") << endmsg;
4004 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4005 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4006 warning << _("Given Video Server is not an executable file.") << endmsg;
4012 argp=(char**) calloc(9,sizeof(char*));
4013 argp[0] = strdup(icsd_exec.c_str());
4014 argp[1] = strdup("-P");
4015 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4016 argp[3] = strdup("-p");
4017 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4018 argp[5] = strdup("-C");
4019 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4020 argp[7] = strdup(icsd_docroot.c_str());
4022 stop_video_server();
4024 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4025 Config->set_video_advanced_setup(false);
4027 std::ostringstream osstream;
4028 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4029 Config->set_video_server_url(osstream.str());
4030 Config->set_video_server_docroot(icsd_docroot);
4031 Config->set_video_advanced_setup(true);
4034 if (video_server_process) {
4035 delete video_server_process;
4038 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4039 if (video_server_process->start()) {
4040 warning << _("Cannot launch the video-server") << endmsg;
4043 int timeout = 120; // 6 sec
4044 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4045 Glib::usleep (50000);
4047 if (--timeout <= 0 || !video_server_process->is_running()) break;
4050 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4052 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4053 delete video_server_process;
4054 video_server_process = 0;
4062 ARDOUR_UI::add_video (Gtk::Window* float_window)
4068 if (!start_video_server(float_window, false)) {
4069 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4074 add_video_dialog->set_transient_for (*float_window);
4077 if (add_video_dialog->is_visible()) {
4078 /* we're already doing this */
4082 ResponseType r = (ResponseType) add_video_dialog->run ();
4083 add_video_dialog->hide();
4084 if (r != RESPONSE_ACCEPT) { return; }
4086 bool local_file, orig_local_file;
4087 std::string path = add_video_dialog->file_name(local_file);
4089 std::string orig_path = path;
4090 orig_local_file = local_file;
4092 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4094 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4095 warning << string_compose(_("could not open %1"), path) << endmsg;
4098 if (!local_file && path.length() == 0) {
4099 warning << _("no video-file selected") << endmsg;
4103 std::string audio_from_video;
4104 bool detect_ltc = false;
4106 switch (add_video_dialog->import_option()) {
4107 case VTL_IMPORT_TRANSCODE:
4109 TranscodeVideoDialog *transcode_video_dialog;
4110 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4111 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4112 transcode_video_dialog->hide();
4113 if (r != RESPONSE_ACCEPT) {
4114 delete transcode_video_dialog;
4118 audio_from_video = transcode_video_dialog->get_audiofile();
4120 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4123 else if (!audio_from_video.empty()) {
4124 editor->embed_audio_from_video(
4126 video_timeline->get_offset(),
4127 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4130 switch (transcode_video_dialog->import_option()) {
4131 case VTL_IMPORT_TRANSCODED:
4132 path = transcode_video_dialog->get_filename();
4135 case VTL_IMPORT_REFERENCE:
4138 delete transcode_video_dialog;
4141 delete transcode_video_dialog;
4145 case VTL_IMPORT_NONE:
4149 /* strip _session->session_directory().video_path() from video file if possible */
4150 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4151 path=path.substr(_session->session_directory().video_path().size());
4152 if (path.at(0) == G_DIR_SEPARATOR) {
4153 path=path.substr(1);
4157 video_timeline->set_update_session_fps(auto_set_session_fps);
4159 if (video_timeline->video_file_info(path, local_file)) {
4160 XMLNode* node = new XMLNode(X_("Videotimeline"));
4161 node->add_property (X_("Filename"), path);
4162 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4163 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4164 if (orig_local_file) {
4165 node->add_property (X_("OriginalVideoFile"), orig_path);
4167 node->remove_property (X_("OriginalVideoFile"));
4169 _session->add_extra_xml (*node);
4170 _session->set_dirty ();
4172 if (!audio_from_video.empty() && detect_ltc) {
4173 std::vector<LTCFileReader::LTCMap> ltc_seq;
4176 /* TODO ask user about TV standard (LTC alignment if any) */
4177 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4178 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4180 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4182 /* TODO seek near end of file, and read LTC until end.
4183 * if it fails to find any LTC frames, scan complete file
4185 * calculate drift of LTC compared to video-duration,
4186 * ask user for reference (timecode from start/mid/end)
4189 // LTCFileReader will have written error messages
4192 ::g_unlink(audio_from_video.c_str());
4194 if (ltc_seq.size() == 0) {
4195 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4197 /* the very first TC in the file is somteimes not aligned properly */
4198 int i = ltc_seq.size() -1;
4199 ARDOUR::frameoffset_t video_start_offset =
4200 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4201 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4202 video_timeline->set_offset(video_start_offset);
4206 _session->maybe_update_session_range(
4207 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4208 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4211 if (add_video_dialog->launch_xjadeo() && local_file) {
4212 editor->set_xjadeo_sensitive(true);
4213 editor->toggle_xjadeo_proc(1);
4215 editor->toggle_xjadeo_proc(0);
4217 editor->toggle_ruler_video(true);
4222 ARDOUR_UI::remove_video ()
4224 video_timeline->close_session();
4225 editor->toggle_ruler_video(false);
4228 video_timeline->set_offset_locked(false);
4229 video_timeline->set_offset(0);
4231 /* delete session state */
4232 XMLNode* node = new XMLNode(X_("Videotimeline"));
4233 _session->add_extra_xml(*node);
4234 node = new XMLNode(X_("Videomonitor"));
4235 _session->add_extra_xml(*node);
4236 node = new XMLNode(X_("Videoexport"));
4237 _session->add_extra_xml(*node);
4238 stop_video_server();
4242 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4244 if (localcacheonly) {
4245 video_timeline->vmon_update();
4247 video_timeline->flush_cache();
4249 editor->queue_visual_videotimeline_update();
4253 ARDOUR_UI::export_video (bool range)
4255 if (ARDOUR::Config->get_show_video_export_info()) {
4256 ExportVideoInfobox infobox (_session);
4257 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4258 if (infobox.show_again()) {
4259 ARDOUR::Config->set_show_video_export_info(false);
4262 case GTK_RESPONSE_YES:
4263 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4269 export_video_dialog->set_session (_session);
4270 export_video_dialog->apply_state(editor->get_selection().time, range);
4271 export_video_dialog->run ();
4272 export_video_dialog->hide ();
4276 ARDOUR_UI::mixer_settings () const
4281 node = _session->instant_xml(X_("Mixer"));
4283 node = Config->instant_xml(X_("Mixer"));
4287 node = new XMLNode (X_("Mixer"));
4294 ARDOUR_UI::main_window_settings () const
4299 node = _session->instant_xml(X_("Main"));
4301 node = Config->instant_xml(X_("Main"));
4305 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4306 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4311 node = new XMLNode (X_("Main"));
4318 ARDOUR_UI::editor_settings () const
4323 node = _session->instant_xml(X_("Editor"));
4325 node = Config->instant_xml(X_("Editor"));
4329 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4330 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4335 node = new XMLNode (X_("Editor"));
4342 ARDOUR_UI::keyboard_settings () const
4346 node = Config->extra_xml(X_("Keyboard"));
4349 node = new XMLNode (X_("Keyboard"));
4356 ARDOUR_UI::create_xrun_marker (framepos_t where)
4359 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4360 _session->locations()->add (location);
4365 ARDOUR_UI::halt_on_xrun_message ()
4367 cerr << "HALT on xrun\n";
4368 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4373 ARDOUR_UI::xrun_handler (framepos_t where)
4379 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4381 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4382 create_xrun_marker(where);
4385 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4386 halt_on_xrun_message ();
4391 ARDOUR_UI::disk_overrun_handler ()
4393 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4395 if (!have_disk_speed_dialog_displayed) {
4396 have_disk_speed_dialog_displayed = true;
4397 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4398 The disk system on your computer\n\
4399 was not able to keep up with %1.\n\
4401 Specifically, it failed to write data to disk\n\
4402 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4403 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4409 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4410 static MessageDialog *scan_dlg = NULL;
4411 static ProgressBar *scan_pbar = NULL;
4412 static HBox *scan_tbox = NULL;
4413 static Gtk::Button *scan_timeout_button;
4416 ARDOUR_UI::cancel_plugin_scan ()
4418 PluginManager::instance().cancel_plugin_scan();
4422 ARDOUR_UI::cancel_plugin_timeout ()
4424 PluginManager::instance().cancel_plugin_timeout();
4425 scan_timeout_button->set_sensitive (false);
4429 ARDOUR_UI::plugin_scan_timeout (int timeout)
4431 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4435 scan_pbar->set_sensitive (false);
4436 scan_timeout_button->set_sensitive (true);
4437 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4440 scan_pbar->set_sensitive (false);
4441 scan_timeout_button->set_sensitive (false);
4447 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4449 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4453 const bool cancelled = PluginManager::instance().cancelled();
4454 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4455 if (cancelled && scan_dlg->is_mapped()) {
4460 if (cancelled || !can_cancel) {
4465 static Gtk::Button *cancel_button;
4467 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4468 VBox* vbox = scan_dlg->get_vbox();
4469 vbox->set_size_request(400,-1);
4470 scan_dlg->set_title (_("Scanning for plugins"));
4472 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4473 cancel_button->set_name ("EditorGTKButton");
4474 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4475 cancel_button->show();
4477 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4479 scan_tbox = manage( new HBox() );
4481 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4482 scan_timeout_button->set_name ("EditorGTKButton");
4483 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4484 scan_timeout_button->show();
4486 scan_pbar = manage(new ProgressBar());
4487 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4488 scan_pbar->set_text(_("Scan Timeout"));
4491 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4492 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4494 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4497 assert(scan_dlg && scan_tbox && cancel_button);
4499 if (type == X_("closeme")) {
4503 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4506 if (!can_cancel || !cancelled) {
4507 scan_timeout_button->set_sensitive(false);
4509 cancel_button->set_sensitive(can_cancel && !cancelled);
4515 ARDOUR_UI::gui_idle_handler ()
4518 /* due to idle calls, gtk_events_pending() may always return true */
4519 while (gtk_events_pending() && --timeout) {
4520 gtk_main_iteration ();
4525 ARDOUR_UI::disk_underrun_handler ()
4527 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4529 if (!have_disk_speed_dialog_displayed) {
4530 have_disk_speed_dialog_displayed = true;
4531 MessageDialog* msg = new MessageDialog (
4532 _main_window, string_compose (_("The disk system on your computer\n\
4533 was not able to keep up with %1.\n\
4535 Specifically, it failed to read data from disk\n\
4536 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4537 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4543 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4545 have_disk_speed_dialog_displayed = false;
4550 ARDOUR_UI::session_dialog (std::string msg)
4552 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4556 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4563 ARDOUR_UI::pending_state_dialog ()
4565 HBox* hbox = manage (new HBox());
4566 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4567 ArdourDialog dialog (_("Crash Recovery"), true);
4568 Label message (string_compose (_("\
4569 This session appears to have been in the\n\
4570 middle of recording when %1 or\n\
4571 the computer was shutdown.\n\
4573 %1 can recover any captured audio for\n\
4574 you, or it can ignore it. Please decide\n\
4575 what you would like to do.\n"), PROGRAM_NAME));
4576 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4577 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4578 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4579 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4580 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4581 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4582 dialog.set_default_response (RESPONSE_ACCEPT);
4583 dialog.set_position (WIN_POS_CENTER);
4588 switch (dialog.run ()) {
4589 case RESPONSE_ACCEPT:
4597 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4599 HBox* hbox = new HBox();
4600 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4601 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4602 Label message (string_compose (_("\
4603 This session was created with a sample rate of %1 Hz, but\n\
4604 %2 is currently running at %3 Hz. If you load this session,\n\
4605 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4607 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4608 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4609 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4610 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4611 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4612 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4613 dialog.set_default_response (RESPONSE_ACCEPT);
4614 dialog.set_position (WIN_POS_CENTER);
4619 switch (dialog.run()) {
4620 case RESPONSE_ACCEPT:
4630 ARDOUR_UI::use_config ()
4632 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4634 set_transport_controllable_state (*node);
4639 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4641 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4642 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4644 primary_clock->set (pos);
4647 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4648 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4650 secondary_clock->set (pos);
4653 if (big_clock_window) {
4654 big_clock->set (pos);
4656 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4660 ARDOUR_UI::step_edit_status_change (bool yn)
4662 // XXX should really store pre-step edit status of things
4663 // we make insensitive
4666 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4667 rec_button.set_sensitive (false);
4669 rec_button.unset_active_state ();;
4670 rec_button.set_sensitive (true);
4675 ARDOUR_UI::record_state_changed ()
4677 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4679 if (!_session || !big_clock_window) {
4680 /* why bother - the clock isn't visible */
4684 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4685 big_clock->set_active (true);
4687 big_clock->set_active (false);
4692 ARDOUR_UI::first_idle ()
4695 _session->allow_auto_play (true);
4699 editor->first_idle();
4702 Keyboard::set_can_save_keybindings (true);
4707 ARDOUR_UI::store_clock_modes ()
4709 XMLNode* node = new XMLNode(X_("ClockModes"));
4711 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4712 XMLNode* child = new XMLNode (X_("Clock"));
4714 child->add_property (X_("name"), (*x)->name());
4715 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4716 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4718 node->add_child_nocopy (*child);
4721 _session->add_extra_xml (*node);
4722 _session->set_dirty ();
4725 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4726 : Controllable (name), ui (u), type(tp)
4732 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4735 /* do nothing: these are radio-style actions */
4739 const char *action = 0;
4743 action = X_("Roll");
4746 action = X_("Stop");
4749 action = X_("GotoStart");
4752 action = X_("GotoEnd");
4755 action = X_("Loop");
4758 action = X_("PlaySelection");
4761 action = X_("Record");
4771 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4779 ARDOUR_UI::TransportControllable::get_value (void) const
4806 ARDOUR_UI::setup_profile ()
4808 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4809 Profile->set_small_screen ();
4812 if (g_getenv ("ARDOUR_SAE")) {
4813 Profile->set_sae ();
4814 Profile->set_single_package ();
4817 if (g_getenv ("TRX")) {
4818 Profile->set_trx ();
4821 if (g_getenv ("MIXBUS")) {
4822 Profile->set_mixbus ();
4827 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4829 MissingFileDialog dialog (s, str, type);
4834 int result = dialog.run ();
4841 return 1; // quit entire session load
4844 result = dialog.get_action ();
4850 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4852 AmbiguousFileDialog dialog (file, hits);
4859 return dialog.get_which ();
4862 /** Allocate our thread-local buffers */
4864 ARDOUR_UI::get_process_buffers ()
4866 _process_thread->get_buffers ();
4869 /** Drop our thread-local buffers */
4871 ARDOUR_UI::drop_process_buffers ()
4873 _process_thread->drop_buffers ();
4877 ARDOUR_UI::feedback_detected ()
4879 _feedback_exists = true;
4883 ARDOUR_UI::successful_graph_sort ()
4885 _feedback_exists = false;
4889 ARDOUR_UI::midi_panic ()
4892 _session->midi_panic();
4897 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4899 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4900 const char* end_big = "</span>";
4901 const char* start_mono = "<tt>";
4902 const char* end_mono = "</tt>";
4904 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4905 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4906 "From now on, use the -2000 version with older versions of %3"),
4907 xml_path, backup_path, PROGRAM_NAME,
4909 start_mono, end_mono), true);
4916 ARDOUR_UI::reset_peak_display ()
4918 if (!_session || !_session->master_out() || !editor_meter) return;
4919 editor_meter->clear_meters();
4920 editor_meter_max_peak = -INFINITY;
4921 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4925 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4927 if (!_session || !_session->master_out()) return;
4928 if (group == _session->master_out()->route_group()) {
4929 reset_peak_display ();
4934 ARDOUR_UI::reset_route_peak_display (Route* route)
4936 if (!_session || !_session->master_out()) return;
4937 if (_session->master_out().get() == route) {
4938 reset_peak_display ();
4943 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4945 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4946 audio_midi_setup->set_position (WIN_POS_CENTER);
4951 response = audio_midi_setup->run();
4953 case Gtk::RESPONSE_OK:
4954 if (!AudioEngine::instance()->running()) {
4968 ARDOUR_UI::transport_numpad_timeout ()
4970 _numpad_locate_happening = false;
4971 if (_numpad_timeout_connection.connected() )
4972 _numpad_timeout_connection.disconnect();
4977 ARDOUR_UI::transport_numpad_decimal ()
4979 _numpad_timeout_connection.disconnect();
4981 if (_numpad_locate_happening) {
4982 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4983 _numpad_locate_happening = false;
4985 _pending_locate_num = 0;
4986 _numpad_locate_happening = true;
4987 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
4992 ARDOUR_UI::transport_numpad_event (int num)
4994 if ( _numpad_locate_happening ) {
4995 _pending_locate_num = _pending_locate_num*10 + num;
4998 case 0: toggle_roll(false, false); break;
4999 case 1: transport_rewind(1); break;
5000 case 2: transport_forward(1); break;
5001 case 3: transport_record(true); break;
5002 case 4: toggle_session_auto_loop(); break;
5003 case 5: transport_record(false); toggle_session_auto_loop(); break;
5004 case 6: toggle_punch(); break;
5005 case 7: toggle_click(); break;
5006 case 8: toggle_auto_return(); break;
5007 case 9: toggle_follow_edits(); break;
5013 ARDOUR_UI::set_flat_buttons ()
5015 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5019 ARDOUR_UI::audioengine_became_silent ()
5021 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5023 Gtk::MESSAGE_WARNING,
5027 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5029 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5030 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5031 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5032 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5033 Gtk::HBox pay_button_box;
5034 Gtk::HBox subscribe_button_box;
5036 pay_button_box.pack_start (pay_button, true, false);
5037 subscribe_button_box.pack_start (subscribe_button, true, false);
5039 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 */
5041 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5042 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5044 msg.get_vbox()->pack_start (pay_label);
5045 msg.get_vbox()->pack_start (pay_button_box);
5046 msg.get_vbox()->pack_start (subscribe_label);
5047 msg.get_vbox()->pack_start (subscribe_button_box);
5049 msg.get_vbox()->show_all ();
5051 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5052 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5053 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5058 case Gtk::RESPONSE_YES:
5059 AudioEngine::instance()->reset_silence_countdown ();
5062 case Gtk::RESPONSE_NO:
5064 save_state_canfail ("");
5068 case Gtk::RESPONSE_CANCEL:
5070 /* don't reset, save session and exit */
5076 ARDOUR_UI::hide_application ()
5078 Application::instance ()-> hide ();
5082 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5084 /* icons, titles, WM stuff */
5086 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5088 if (window_icons.empty()) {
5089 Glib::RefPtr<Gdk::Pixbuf> icon;
5090 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5091 window_icons.push_back (icon);
5093 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5094 window_icons.push_back (icon);
5096 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5097 window_icons.push_back (icon);
5099 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5100 window_icons.push_back (icon);
5104 if (!window_icons.empty()) {
5105 window.set_default_icon_list (window_icons);
5108 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5110 if (!name.empty()) {
5114 window.set_title (title.get_string());
5115 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5117 window.set_flags (CAN_FOCUS);
5118 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5120 /* This is a hack to ensure that GTK-accelerators continue to
5121 * work. Once we switch over to entirely native bindings, this will be
5122 * unnecessary and should be removed
5124 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5126 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5127 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5128 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5129 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5133 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5135 Gtkmm2ext::Bindings* bindings = 0;
5136 Gtk::Window* window = 0;
5138 /* until we get ardour bindings working, we are not handling key
5142 if (ev->type != GDK_KEY_PRESS) {
5146 if (event_window == &_main_window) {
5148 window = event_window;
5150 /* find current tab contents */
5152 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5154 /* see if it uses the ardour binding system */
5157 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5159 bindings = &_global_bindings;
5162 } else if (event_window != 0) {
5164 window = event_window;
5166 /* see if window uses ardour binding system */
5168 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5172 /* An empty binding set is treated as if it doesn't exist */
5174 if (bindings && bindings->empty()) {
5178 return key_press_focus_accelerator_handler (*window, ev, bindings);
5182 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5184 GtkWindow* win = window.gobj();
5185 GtkWidget* focus = gtk_window_get_focus (win);
5186 bool special_handling_of_unmodified_accelerators = false;
5187 /* consider all relevant modifiers but not LOCK or SHIFT */
5188 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5190 GdkModifierType modifier = GdkModifierType (ev->state);
5191 modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
5192 Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
5196 /* some widget has keyboard focus */
5198 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5200 /* A particular kind of focusable widget currently has keyboard
5201 * focus. All unmodified key events should go to that widget
5202 * first and not be used as an accelerator by default
5205 special_handling_of_unmodified_accelerators = true;
5209 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7\n",
5212 show_gdk_event_state (ev->state),
5213 special_handling_of_unmodified_accelerators,
5214 Keyboard::some_magic_widget_has_focus(),
5216 (focus ? gtk_widget_get_name (focus) : "no focus widget")));
5218 /* This exists to allow us to override the way GTK handles
5219 key events. The normal sequence is:
5221 a) event is delivered to a GtkWindow
5222 b) accelerators/mnemonics are activated
5223 c) if (b) didn't handle the event, propagate to
5224 the focus widget and/or focus chain
5226 The problem with this is that if the accelerators include
5227 keys without modifiers, such as the space bar or the
5228 letter "e", then pressing the key while typing into
5229 a text entry widget results in the accelerator being
5230 activated, instead of the desired letter appearing
5233 There is no good way of fixing this, but this
5234 represents a compromise. The idea is that
5235 key events involving modifiers (not Shift)
5236 get routed into the activation pathway first, then
5237 get propagated to the focus widget if necessary.
5239 If the key event doesn't involve modifiers,
5240 we deliver to the focus widget first, thus allowing
5241 it to get "normal text" without interference
5244 Of course, this can also be problematic: if there
5245 is a widget with focus, then it will swallow
5246 all "normal text" accelerators.
5250 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5252 /* no special handling or there are modifiers in effect: accelerate first */
5254 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5255 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5256 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5258 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5262 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5263 KeyboardKey k (ev->state, ev->keyval);
5265 if (bindings->activate (k, Bindings::Press)) {
5266 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5271 if (try_gtk_accel_binding (win, ev, !special_handling_of_unmodified_accelerators, modifier)) {
5272 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5277 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5279 if (gtk_window_propagate_key_event (win, ev)) {
5280 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5286 /* no modifiers, propagate first */
5288 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5290 if (gtk_window_propagate_key_event (win, ev)) {
5291 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5295 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5299 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5300 KeyboardKey k (ev->state, ev->keyval);
5302 if (bindings->activate (k, Bindings::Press)) {
5303 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5309 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try GTK bindings\n");
5311 if (try_gtk_accel_binding (win, ev, !special_handling_of_unmodified_accelerators, modifier)) {
5312 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5317 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5319 KeyboardKey k (ev->state, ev->keyval);
5321 if (_global_bindings.activate (k, Bindings::Press)) {
5322 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5326 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5331 ARDOUR_UI::try_gtk_accel_binding (GtkWindow* win, GdkEventKey* ev, bool translate, GdkModifierType modifier)
5333 uint32_t fakekey = ev->keyval;
5337 /* pretend that certain key events that GTK does not allow
5338 to be used as accelerators are actually something that
5339 it does allow. but only where there are no modifiers.
5342 if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) {
5343 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tactivate (was %1 now %2) without special hanlding of unmodified accels, modifier was %3\n",
5344 ev->keyval, fakekey, show_gdk_event_state (modifier)));
5348 if (gtk_accel_groups_activate (G_OBJECT(win), fakekey, modifier)) {
5349 DEBUG_TRACE (DEBUG::Accelerators, "\tGTK accel group activated\n");