X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=c1ebaac229049773173e781b08ec9d17f8515d0b;hb=f50c839ea82308632a51535594859eae3107a01d;hp=73fa305955938cbff7c76b0ee4b6221a566a129d;hpb=2c41df947488671e78fc3947ed0065103024a09f;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 73fa305955..c1ebaac229 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -47,9 +47,10 @@ #include #include "pbd/gstdio_compat.h" -#include #include +#include #include +#include #include "pbd/error.h" #include "pbd/basename.h" @@ -62,6 +63,7 @@ #include "pbd/openuri.h" #include "pbd/stl_delete.h" #include "pbd/types_convert.h" +#include "pbd/unwind.h" #include "pbd/file_utils.h" #include "pbd/localtime_r.h" #include "pbd/pthread_utils.h" @@ -73,18 +75,19 @@ #include "gtkmm2ext/bindings.h" #include "gtkmm2ext/gtk_ui.h" #include "gtkmm2ext/utils.h" -#include "gtkmm2ext/click_box.h" -#include "gtkmm2ext/fastmeter.h" -#include "gtkmm2ext/popup.h" #include "gtkmm2ext/window_title.h" +#include "widgets/fastmeter.h" +#include "widgets/prompter.h" + #include "ardour/ardour.h" #include "ardour/audio_backend.h" #include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/audiofilesource.h" #include "ardour/automation_watch.h" -#include "ardour/diskstream.h" +#include "ardour/disk_reader.h" +#include "ardour/disk_writer.h" #include "ardour/filename_extensions.h" #include "ardour/filesystem_paths.h" #include "ardour/ltc_file_reader.h" @@ -121,7 +124,7 @@ #undef check #endif -#include "timecode/time.h" +#include "temporal/time.h" typedef uint64_t microseconds_t; @@ -135,6 +138,7 @@ typedef uint64_t microseconds_t; #include "audio_clock.h" #include "audio_region_view.h" #include "big_clock_window.h" +#include "big_transport_window.h" #include "bundle_manager.h" #include "duplicate_routes_dialog.h" #include "debug.h" @@ -162,12 +166,12 @@ typedef uint64_t microseconds_t; #include "opts.h" #include "pingback.h" #include "processor_box.h" -#include "prompter.h" #include "public_editor.h" #include "rc_option_editor.h" #include "route_time_axis.h" #include "route_params_ui.h" #include "save_as_dialog.h" +#include "save_template_dialog.h" #include "script_selector.h" #include "session_archive_dialog.h" #include "session_dialog.h" @@ -176,6 +180,7 @@ typedef uint64_t microseconds_t; #include "speaker_dialog.h" #include "splash.h" #include "startup.h" +#include "template_dialog.h" #include "time_axis_view_item.h" #include "time_info_box.h" #include "timers.h" @@ -191,14 +196,15 @@ using namespace ARDOUR; using namespace ARDOUR_UI_UTILS; using namespace PBD; using namespace Gtkmm2ext; +using namespace ArdourWidgets; using namespace Gtk; using namespace std; using namespace Editing; ARDOUR_UI *ARDOUR_UI::theArdourUI = 0; -sigc::signal ARDOUR_UI::Clock; -sigc::signal ARDOUR_UI::CloseAllDialogs; +sigc::signal ARDOUR_UI::Clock; +sigc::signal ARDOUR_UI::CloseAllDialogs; static bool ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version) @@ -211,7 +217,7 @@ ask_about_configuration_copy (string const & old_dir, string const & new_dir, in Gtk::MESSAGE_INFO, Gtk::BUTTONS_YES_NO, true /* modal, though it hardly matters since it is the only window */ - ); + ); msg.set_default_response (Gtk::RESPONSE_YES); msg.show_all (); @@ -221,8 +227,8 @@ ask_about_configuration_copy (string const & old_dir, string const & new_dir, in static void libxml_generic_error_func (void* /* parsing_context*/, - const char* msg, - ...) + const char* msg, + ...) { va_list ap; char buf[2048]; @@ -263,6 +269,7 @@ libxml_structured_error_func (void* /* parsing_context*/, ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp) , session_loaded (false) + , session_load_in_progress (false) , gui_object_state (new GUIObjectState) , primary_clock (new MainClock (X_("primary"), X_("transport"), true )) , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false)) @@ -279,13 +286,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , _initial_verbose_plugin_scan (false) , first_time_engine_run (true) , secondary_clock_spacer (0) - , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)) - , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)) - , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)) - , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)) - , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)) - , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)) - , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)) , auto_input_button (ArdourButton::led_default_elements) , time_info_box (0) , auto_return_button (ArdourButton::led_default_elements) @@ -294,8 +294,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , solo_alert_button (_("Solo")) , feedback_alert_button (_("Feedback")) , error_alert_button ( ArdourButton::just_led_default_elements ) - , editor_meter(0) , editor_meter_peak_display() + , editor_meter(0) , _suspend_editor_meter_callbacks (false) , _numpad_locate_happening (false) , _session_is_new (false) @@ -317,6 +317,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this)) , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this)) , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this)) + , big_transport_window (X_("big-transport"), _("Transport Controls"), boost::bind (&ARDOUR_UI::create_big_transport_window, this)) , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO)) , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI)) , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this)) @@ -374,25 +375,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) boost::function pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1)); UIConfiguration::instance().map_parameters (pc); - roll_button.set_controllable (roll_controllable); - stop_button.set_controllable (stop_controllable); - goto_start_button.set_controllable (goto_start_controllable); - goto_end_button.set_controllable (goto_end_controllable); - auto_loop_button.set_controllable (auto_loop_controllable); - play_selection_button.set_controllable (play_selection_controllable); - rec_button.set_controllable (rec_controllable); - - roll_button.set_name ("transport button"); - stop_button.set_name ("transport button"); - goto_start_button.set_name ("transport button"); - goto_end_button.set_name ("transport button"); - auto_loop_button.set_name ("transport button"); - play_selection_button.set_name ("transport button"); - rec_button.set_name ("transport recenable button"); - midi_panic_button.set_name ("transport button"); - - ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context()); - ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context()); + transport_ctrl.setup (this); + + ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context()); + ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context()); ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context()); @@ -461,7 +447,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) TimeAxisViewItem::set_constant_heights (); - /* Set this up so that our window proxies can register actions */ + /* Set this up so that our window proxies can register actions */ ActionManager::init (); @@ -480,6 +466,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) bundle_manager.set_state (*ui_xml, 0); location_ui.set_state (*ui_xml, 0); big_clock_window.set_state (*ui_xml, 0); + big_transport_window.set_state (*ui_xml, 0); audio_port_matrix.set_state (*ui_xml, 0); midi_port_matrix.set_state (*ui_xml, 0); export_video_dialog.set_state (*ui_xml, 0); @@ -502,6 +489,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) WM::Manager::instance().register_window (&bundle_manager); WM::Manager::instance().register_window (&location_ui); WM::Manager::instance().register_window (&big_clock_window); + WM::Manager::instance().register_window (&big_transport_window); WM::Manager::instance().register_window (&audio_port_matrix); WM::Manager::instance().register_window (&midi_port_matrix); WM::Manager::instance().register_window (&idleometer); @@ -527,8 +515,8 @@ ARDOUR_UI::pre_release_dialog () ArdourDialog d (_("Pre-Release Warning"), true, false); d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); - Label* label = manage (new Label); - label->set_markup (string_compose (_("Welcome to this pre-release build of %1 %2\n\n\ + Label* label = manage (new Label); + label->set_markup (string_compose (_("Welcome to this pre-release build of %1 %2\n\n\ There are still several issues and bugs to be worked on,\n\ as well as general workflow improvements, before this can be considered\n\ release software. So, a few guidelines:\n\ @@ -538,7 +526,7 @@ release software. So, a few guidelines:\n\ 2) Please wait for a helpful writeup of new features.\n\ 3) Please do NOT use the forums at ardour.org to report issues.\n\ 4) Please DO use the bugtracker at http://tracker.ardour.org/ to report issues\n\ - making sure to note the product version number as 5.0-pre.\n\ + making sure to note the product version number as 6.0-pre.\n\ 5) Please DO use the ardour-users mailing list to discuss ideas and pass on comments.\n\ 6) Please DO join us on IRC for real time discussions about %1 %2. You\n\ can get there directly from within the program via the Help->Chat menu option.\n\ @@ -548,11 +536,11 @@ Full information on all the above can be found on the support page at\n\ http://ardour.org/support\n\ "), PROGRAM_NAME, VERSIONSTRING)); - d.get_vbox()->set_border_width (12); - d.get_vbox()->pack_start (*label, false, false, 12); - d.get_vbox()->show_all (); + d.get_vbox()->set_border_width (12); + d.get_vbox()->pack_start (*label, false, false, 12); + d.get_vbox()->show_all (); - d.run (); + d.run (); } GlobalPortMatrixWindow* @@ -674,6 +662,8 @@ ARDOUR_UI::post_engine () throw failed_constructor (); } + transport_ctrl.map_actions (); + /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */ XMLNode* n = Config->extra_xml (X_("UI")); if (n) { @@ -764,7 +754,7 @@ ARDOUR_UI::post_engine () vector::iterator l; for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) { - output << " " << (*p).substr (9, string::npos); + output << " " << (*p).substr (10, string::npos); output << "" << *l << "" << endl; } output << " \n " << endl; @@ -776,7 +766,7 @@ ARDOUR_UI::post_engine () GError *err = NULL; gint fd; - if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) { + if ((fd = g_file_open_tmp ("list-of-menu-actionsXXXXXX.html", &file_name, &err)) < 0) { if (err) { error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg; g_error_free (err); @@ -863,7 +853,7 @@ ARDOUR_UI::~ARDOUR_UI () delete gui_object_state; gui_object_state = 0; delete main_window_visibility; FastMeter::flush_pattern_cache (); - PixFader::flush_pattern_cache (); + ArdourFader::flush_pattern_cache (); } #ifndef NDEBUG @@ -1101,7 +1091,7 @@ ARDOUR_UI::starting () * The wrapper startup script should set the environment variable 'ARDOUR_SELF' */ const char *process_name = g_getenv ("ARDOUR_SELF"); - nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4"); + nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6"); unsigned int i = 0; // wait for announce reply from nsm server @@ -1184,15 +1174,13 @@ ARDOUR_UI::starting () Searchpath ds (ARDOUR::ardour_data_search_path()); ds.add_subdirectory_to_paths ("sessions"); vector demos; - find_files_matching_pattern (demos, ds, "*.tar.xz"); + find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix); ARDOUR::RecentSessions rs; ARDOUR::read_recent_sessions (rs); for (vector::iterator i = demos.begin(); i != demos.end (); ++i) { - /* "demo-session" must be inside "demo-session.tar.xz" - * strip ".tar.xz" - */ + /* "demo-session" must be inside "demo-session." */ std::string name = basename_nosuffix (basename_nosuffix (*i)); std::string path = Glib::build_filename (dspd, name); /* skip if session-dir already exists */ @@ -1282,11 +1270,6 @@ ARDOUR_UI::starting () BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME)); - if (splash) { - // in 1 second, hide the splash screen - Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000); - } - /* all other dialogs are created conditionally */ return 0; @@ -1548,8 +1531,7 @@ ARDOUR_UI::every_second () void ARDOUR_UI::every_point_one_seconds () { - // TODO get rid of this.. - // ShuttleControl is updated directly via TransportStateChange signal + if (editor) editor->build_region_boundary_cache(); } void @@ -1580,7 +1562,7 @@ ARDOUR_UI::set_fps_timeout_connection () * signals to the GUI Thread.. */ interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */ - * _session->frame_rate() / _session->nominal_frame_rate() + * _session->sample_rate() / _session->nominal_sample_rate() / _session->timecode_frames_per_second() ); #ifdef PLATFORM_WINDOWS @@ -1600,7 +1582,7 @@ ARDOUR_UI::set_fps_timeout_connection () } void -ARDOUR_UI::update_sample_rate (framecnt_t) +ARDOUR_UI::update_sample_rate (samplecnt_t) { char buf[64]; @@ -1612,7 +1594,7 @@ ARDOUR_UI::update_sample_rate (framecnt_t) } else { - framecnt_t rate = AudioEngine::instance()->sample_rate(); + samplecnt_t rate = AudioEngine::instance()->sample_rate(); if (rate == 0) { /* no sample rate available */ @@ -1704,6 +1686,7 @@ ARDOUR_UI::update_xrun_count () if (_session) { const unsigned int x = _session->get_xrun_count (); + dsp_load_indicator.set_xrun_count (x); if (x > 9999) { snprintf (buf, sizeof (buf), _("X: >10K"), X_("red")); } else { @@ -1711,6 +1694,7 @@ ARDOUR_UI::update_xrun_count () } } else { snprintf (buf, sizeof (buf), _("X: ?"), X_("yellow")); + dsp_load_indicator.set_xrun_count (UINT_MAX); } xrun_label.set_markup (buf); set_tip (xrun_label, _("Audio dropouts. Shift+click to reset")); @@ -1726,6 +1710,7 @@ ARDOUR_UI::update_cpu_load () */ double const c = AudioEngine::instance()->get_dsp_load (); + dsp_load_indicator.set_dsp_load (c); snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), c >= 90 ? X_("red") : X_("green"), c); cpu_load_label.set_markup (buf); } @@ -1785,46 +1770,52 @@ void ARDOUR_UI::update_disk_space() { if (_session == 0) { + disk_space_indicator.set_available_disk_sec (-1); return; } - boost::optional opt_frames = _session->available_capture_duration(); + boost::optional opt_samples = _session->available_capture_duration(); char buf[64]; - framecnt_t fr = _session->frame_rate(); + samplecnt_t fr = _session->sample_rate(); if (fr == 0) { /* skip update - no SR available */ + disk_space_indicator.set_available_disk_sec (-1); return; } - if (!opt_frames) { + if (!opt_samples) { /* Available space is unknown */ snprintf (buf, sizeof (buf), "%s", _("Disk: Unknown")); - } else if (opt_frames.get_value_or (0) == max_framecnt) { + disk_space_indicator.set_available_disk_sec (-1); + } else if (opt_samples.get_value_or (0) == max_samplecnt) { snprintf (buf, sizeof (buf), "%s", _("Disk: 24hrs+")); + disk_space_indicator.set_available_disk_sec (max_samplecnt); } else { rec_enabled_streams = 0; _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false); - framecnt_t frames = opt_frames.get_value_or (0); + samplecnt_t samples = opt_samples.get_value_or (0); if (rec_enabled_streams) { - frames /= rec_enabled_streams; + samples /= rec_enabled_streams; } int hrs; int mins; int secs; - hrs = frames / (fr * 3600); + disk_space_indicator.set_available_disk_sec (samples / (float)fr); + + hrs = samples / (fr * 3600); if (hrs > 24) { snprintf (buf, sizeof (buf), "%s", _("Disk: >24 hrs")); } else { - frames -= hrs * fr * 3600; - mins = frames / (fr * 60); - frames -= mins * fr * 60; - secs = frames / fr; + samples -= hrs * fr * 3600; + mins = samples / (fr * 60); + samples -= mins * fr * 60; + secs = samples / fr; bool const low = (hrs == 0 && mins <= 30); @@ -1927,10 +1918,6 @@ ARDOUR_UI::open_recent_session () can_return = false; } - if (splash) { - // in 1 second, hide the splash screen - Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000); - } } bool @@ -1938,9 +1925,9 @@ ARDOUR_UI::check_audioengine (Gtk::Window& parent) { if (!AudioEngine::instance()->connected()) { MessageDialog msg (parent, string_compose ( - _("%1 is not connected to any audio backend.\n" - "You cannot open or close sessions in this condition"), - PROGRAM_NAME)); + _("%1 is not connected to any audio backend.\n" + "You cannot open or close sessions in this condition"), + PROGRAM_NAME)); pop_back_splash (msg); msg.run (); return false; @@ -1974,7 +1961,7 @@ ARDOUR_UI::open_session () string default_session_folder = Config->get_default_session_parent_dir(); open_session_selector.add_shortcut_folder (default_session_folder); } - catch (Glib::Error & e) { + catch (Glib::Error const& e) { std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl; } @@ -1984,7 +1971,7 @@ ARDOUR_UI::open_session () open_session_selector.add_filter (session_filter); FileFilter archive_filter; - archive_filter.add_pattern (X_("*.tar.xz")); + archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix)); archive_filter.set_name (_("Session Archives")); open_session_selector.add_filter (archive_filter); @@ -2021,16 +2008,6 @@ ARDOUR_UI::open_session () } } -void -ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n) -{ - if (!_session) { - return; - } - - _session->vca_manager().create_vca (n, name_template); -} - void ARDOUR_UI::session_add_mixed_track ( const ChanCount& input, @@ -2043,10 +2020,7 @@ ARDOUR_UI::session_add_mixed_track ( Plugin::PresetRecord* pset, ARDOUR::PresentationInfo::order_t order) { - if (_session == 0) { - warning << _("You cannot add a track without a session already loaded.") << endmsg; - return; - } + assert (_session); if (Profile->get_mixbus ()) { strict_io = true; @@ -2136,10 +2110,7 @@ ARDOUR_UI::session_add_audio_route ( list > tracks; RouteList routes; - if (_session == 0) { - warning << _("You cannot add a track or bus without a session already loaded.") << endmsg; - return; - } + assert (_session); try { if (track) { @@ -2199,7 +2170,7 @@ ARDOUR_UI::transport_goto_start () */ if (editor) { - editor->center_screen (_session->current_start_frame ()); + editor->center_screen (_session->current_start_sample ()); } } } @@ -2227,30 +2198,30 @@ ARDOUR_UI::transport_goto_wallclock () time_t now; struct tm tmnow; - framepos_t frames; + samplepos_t samples; time (&now); localtime_r (&now, &tmnow); - framecnt_t frame_rate = _session->frame_rate(); + samplecnt_t sample_rate = _session->sample_rate(); - if (frame_rate == 0) { + if (sample_rate == 0) { /* no frame rate available */ return; } - frames = tmnow.tm_hour * (60 * 60 * frame_rate); - frames += tmnow.tm_min * (60 * frame_rate); - frames += tmnow.tm_sec * frame_rate; + samples = tmnow.tm_hour * (60 * 60 * sample_rate); + samples += tmnow.tm_min * (60 * sample_rate); + samples += tmnow.tm_sec * sample_rate; - _session->request_locate (frames, _session->transport_rolling ()); + _session->request_locate (samples, _session->transport_rolling ()); /* force displayed area in editor to start no matter what "follow playhead" setting is. */ if (editor) { - editor->center_screen (frames); + editor->center_screen (samples); } } } @@ -2259,15 +2230,15 @@ void ARDOUR_UI::transport_goto_end () { if (_session) { - framepos_t const frame = _session->current_end_frame(); - _session->request_locate (frame); + samplepos_t const sample = _session->current_end_sample(); + _session->request_locate (sample); /* force displayed area in editor to start no matter what "follow playhead" setting is. */ if (editor) { - editor->center_screen (frame); + editor->center_screen (sample); } } } @@ -2480,9 +2451,9 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) * want to do this. */ - 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 + if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_sample() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits _session->request_play_range (&editor->get_selection().time, true); - _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here + _session->set_requested_return_sample( editor->get_selection().time.front().start ); //force an auto-return here } _session->request_transport_speed (1.0f); } @@ -2641,10 +2612,6 @@ void ARDOUR_UI::map_transport_state () { if (!_session) { - auto_loop_button.unset_active_state (); - play_selection_button.unset_active_state (); - roll_button.unset_active_state (); - stop_button.set_active_state (Gtkmm2ext::ExplicitActive); layered_button.set_sensitive (false); return; } @@ -2654,52 +2621,9 @@ ARDOUR_UI::map_transport_state () float sp = _session->transport_speed(); if (sp != 0.0f) { - - /* we're rolling */ - - if (_session->get_play_range()) { - - play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive); - roll_button.unset_active_state (); - auto_loop_button.unset_active_state (); - - } else if (_session->get_play_loop ()) { - - auto_loop_button.set_active (true); - play_selection_button.set_active (false); - if (Config->get_loop_is_mode()) { - roll_button.set_active (true); - } else { - roll_button.set_active (false); - } - - } else { - - roll_button.set_active (true); - play_selection_button.set_active (false); - auto_loop_button.set_active (false); - } - - if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) { - /* light up both roll and play-selection if they are joined */ - roll_button.set_active (true); - play_selection_button.set_active (true); - } layered_button.set_sensitive (!_session->actively_recording ()); - - stop_button.set_active (false); - } else { - layered_button.set_sensitive (true); - stop_button.set_active (true); - roll_button.set_active (false); - play_selection_button.set_active (false); - if (Config->get_loop_is_mode ()) { - auto_loop_button.set_active (_session->get_play_loop()); - } else { - auto_loop_button.set_active (false); - } update_disk_space (); } } @@ -2707,7 +2631,6 @@ ARDOUR_UI::map_transport_state () void ARDOUR_UI::blink_handler (bool blink_on) { - transport_rec_enable_blink (blink_on); sync_blink (blink_on); if (!UIConfiguration::instance().get_blink_alert_indicators()) { @@ -2717,6 +2640,9 @@ ARDOUR_UI::blink_handler (bool blink_on) solo_blink (blink_on); audition_blink (blink_on); feedback_blink (blink_on); + + dsp_load_indicator.blink(blink_on); + disk_space_indicator.blink(blink_on); } void @@ -2725,7 +2651,7 @@ ARDOUR_UI::update_clocks () if (!_session) return; if (editor && !editor->dragging_playhead()) { - Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */ + Clock (_session->audible_sample()); /* EMIT_SIGNAL */ } } @@ -2771,6 +2697,33 @@ ARDOUR_UI::save_session_as () return; } + if (_session->dirty()) { + vector actions; + actions.push_back (_("Abort save-as")); + actions.push_back (_("Don't save now, just save-as")); + actions.push_back (_("Save it first")); + switch (ask_about_saving_session(actions)) { + case -1: + return; + break; + case 1: + if (save_state_canfail ("")) { + MessageDialog msg (_main_window, + string_compose (_("\ +%1 was unable to save your session.\n\n\ +If you still wish to proceeed, please use the\n\n\ +\"Don't save now\" option."), PROGRAM_NAME)); + pop_back_splash(msg); + msg.run (); + return; + } + // no break + case 0: + _session->remove_pending_capture_state (); + break; + } + } + if (!save_as_dialog) { save_as_dialog = new SaveAsDialog; } @@ -2846,7 +2799,6 @@ ARDOUR_UI::save_session_as () if (!sa.include_media && sa.switch_to) { unload_session (false); load_session (sa.final_session_folder_name, sa.new_name); - hide_splash (); } } @@ -2870,7 +2822,7 @@ ARDOUR_UI::archive_session () return; } - if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) { + if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) { MessageDialog msg (_("Session Archiving failed.")); msg.run (); } @@ -2886,13 +2838,16 @@ ARDOUR_UI::quick_snapshot_session (bool switch_to_it) time (&n); localtime_r (&n, &local_time); strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time); + if (switch_to_it && _session->dirty ()) { + save_state_canfail (""); + } save_state (timebuf, switch_to_it); } bool -ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it) +ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it) { string snapname; @@ -2904,7 +2859,7 @@ ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool swi char illegal = Session::session_name_is_legal(snapname); if (illegal) { MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n" - "snapshot names may not contain a '%1' character"), illegal)); + "snapshot names may not contain a '%1' character"), illegal)); msg.run (); return false; } @@ -2938,8 +2893,34 @@ ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool swi void ARDOUR_UI::snapshot_session (bool switch_to_it) { - ArdourPrompter prompter (true); + if (switch_to_it && _session->dirty()) { + vector actions; + actions.push_back (_("Abort saving snapshot")); + actions.push_back (_("Don't save now, just snapshot")); + actions.push_back (_("Save it first")); + switch (ask_about_saving_session(actions)) { + case -1: + return; + break; + case 1: + if (save_state_canfail ("")) { + MessageDialog msg (_main_window, + string_compose (_("\ +%1 was unable to save your session.\n\n\ +If you still wish to proceeed, please use the\n\n\ +\"Don't save now\" option."), PROGRAM_NAME)); + pop_back_splash(msg); + msg.run (); + return; + } + // no break + case 0: + _session->remove_pending_capture_state (); + break; + } + } + Prompter prompter (true); prompter.set_name ("Prompter"); prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); if (switch_to_it) { @@ -2983,7 +2964,7 @@ ARDOUR_UI::rename_session () return; } - ArdourPrompter prompter (true); + Prompter prompter (true); string name; prompter.set_name ("Prompter"); @@ -3004,7 +2985,7 @@ ARDOUR_UI::rename_session () if (illegal) { MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n" - "session names may not contain a '%1' character"), illegal)); + "session names may not contain a '%1' character"), illegal)); msg.run (); goto again; } @@ -3096,88 +3077,49 @@ ARDOUR_UI::secondary_clock_value_changed () _session->request_locate (secondary_clock->current_time ()); } } - void -ARDOUR_UI::transport_rec_enable_blink (bool onoff) -{ - if (_session == 0) { - return; - } - - if (_session->step_editing()) { - return; - } - - Session::RecordState const r = _session->record_status (); - bool const h = _session->have_rec_enabled_track (); - - if (r == Session::Enabled || (r == Session::Recording && !h)) { - if (onoff) { - rec_button.set_active_state (Gtkmm2ext::ExplicitActive); - } else { - rec_button.set_active_state (Gtkmm2ext::Off); - } - } else if (r == Session::Recording && h) { - rec_button.set_active_state (Gtkmm2ext::ExplicitActive); - } else { - rec_button.unset_active_state (); - } -} - -bool -ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter) +ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d) { - string name; - - prompter.get_result (name); + if (response == RESPONSE_ACCEPT) { + const string name = d->get_template_name (); + const string desc = d->get_description (); - if (name.length()) { - int failed = _session->save_template (name); + int failed = _session->save_template (name, desc); if (failed == -2) { /* file already exists. */ - bool overwrite = overwrite_file_dialog (prompter, + bool overwrite = overwrite_file_dialog (*d, _("Confirm Template Overwrite"), _("A template already exists with that name. Do you want to overwrite it?")); if (overwrite) { - _session->save_template (name, true); + _session->save_template (name, desc, true); } else { - return false; + d->show (); + return; } } } - - return true; + delete d; } void ARDOUR_UI::save_template () { - ArdourPrompter prompter (true); - if (!check_audioengine (_main_window)) { return; } - prompter.set_name (X_("Prompter")); - prompter.set_title (_("Save Template")); - prompter.set_prompt (_("Name for template:")); - prompter.set_initial_text(_session->name() + _("-template")); - prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); - - bool finished = false; - while (!finished) { - switch (prompter.run()) { - case RESPONSE_ACCEPT: - finished = process_save_template_prompter (prompter); - break; + const std::string desc = SessionMetadata::Metadata()->description (); + SaveTemplateDialog* d = new SaveTemplateDialog (_session->name (), desc); + d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::save_template_dialog_response), d)); + d->show (); +} - default: - finished = true; - break; - } - } +void ARDOUR_UI::manage_templates () +{ + TemplateDialog td; + td.run(); } void @@ -3229,44 +3171,14 @@ ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& sess BusProfile bus_profile; if (nsm) { - bus_profile.master_out_channels = 2; - bus_profile.input_ac = AutoConnectPhysical; - bus_profile.output_ac = AutoConnectMaster; - bus_profile.requested_physical_in = 0; // use all available - bus_profile.requested_physical_out = 0; // use all available - } else { - /* get settings from advanced section of NSD */ - - if (sd.create_master_bus()) { - bus_profile.master_out_channels = (uint32_t) sd.master_channel_count(); - } else { - bus_profile.master_out_channels = 0; - } - - if (sd.connect_inputs()) { - bus_profile.input_ac = AutoConnectPhysical; - } else { - bus_profile.input_ac = AutoConnectOption (0); - } - - bus_profile.output_ac = AutoConnectOption (0); - - if (sd.connect_outputs ()) { - if (sd.connect_outs_to_master()) { - bus_profile.output_ac = AutoConnectMaster; - } else if (sd.connect_outs_to_physical()) { - bus_profile.output_ac = AutoConnectPhysical; - } - } - - bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count(); - bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count(); + bus_profile.master_out_channels = (uint32_t) sd.master_channel_count(); } - if (build_session (session_path, session_name, bus_profile)) { + // NULL profile: no master, no monitor + if (build_session (session_path, session_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL)) { return -1; } @@ -3423,14 +3335,11 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri break; default: if (quit_on_cancel) { - // JE - Currently (July 2014) this section can only get reached if the - // user quits from the main 'Session Setup' dialog (i.e. reaching this - // point does NOT indicate an abnormal termination). Therefore, let's - // behave gracefully (i.e. let's do some cleanup) before we call exit() + ARDOUR_UI::finish (); + Gtkmm2ext::Application::instance()->cleanup(); ARDOUR::cleanup (); pthread_cancel_all (); - - exit (1); + return -1; // caller is responsible to call exit() } else { return ret; } @@ -3447,7 +3356,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri session_path = session_dialog.session_folder (); if (nsm) { - likely_new = true; + likely_new = true; } if (!likely_new) { @@ -3484,12 +3393,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri if (session_name[0] == G_DIR_SEPARATOR || #ifdef PLATFORM_WINDOWS - (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR) + (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR) #else - (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) || - (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR) + (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) || + (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR) #endif - ) + ) { /* absolute path or cwd-relative path specified for session name: infer session folder @@ -3507,9 +3416,9 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri if (illegal) { MessageDialog msg (session_dialog, - string_compose (_("To ensure compatibility with various systems\n" - "session names may not contain a '%1' character"), - illegal)); + string_compose (_("To ensure compatibility with various systems\n" + "session names may not contain a '%1' character"), + illegal)); msg.run (); ARDOUR_COMMAND_LINE::session_name = ""; // cancel that continue; @@ -3546,7 +3455,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri if (illegal) { pop_back_splash (session_dialog); MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n" - "session names may not contain a '%1' character"), illegal)); + "session names may not contain a '%1' character"), illegal)); msg.run (); ARDOUR_COMMAND_LINE::session_name = ""; // cancel that continue; @@ -3555,7 +3464,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri _session_is_new = true; } - if (likely_new && template_name.empty()) { + if (!template_name.empty() && template_name.substr (0, 11) == "urn:ardour:") { + + ret = build_session_from_dialog (session_dialog, session_path, session_name); + meta_session_setup (template_name.substr (11)); + + } else if (likely_new && template_name.empty()) { ret = build_session_from_dialog (session_dialog, session_path, session_name); @@ -3602,10 +3516,6 @@ ARDOUR_UI::close_session() if (get_session_parameters (true, false)) { exit (1); } - if (splash && splash->is_visible()) { - // in 1 second, hide the splash screen - Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000); - } } /** @param snap_name Snapshot name (without .ardour suffix). @@ -3614,6 +3524,18 @@ ARDOUR_UI::close_session() int ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template) { + /* load_session calls flush_pending() which allows + * GUI interaction and potentially loading another session + * (that was easy via snapshot sidebar). + * Recursing into load_session() from load_session() and recusive + * event loops causes all kind of crashes. + */ + assert (!session_load_in_progress); + if (session_load_in_progress) { + return -1; + } + PBD::Unwinder lsu (session_load_in_progress, true); + Session *new_session; int unload_status; int retval = -1; @@ -3639,7 +3561,7 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, /* this one is special */ - catch (AudioEngine::PortRegistrationFailure& err) { + catch (AudioEngine::PortRegistrationFailure const& err) { MessageDialog msg (err.what(), true, @@ -3664,9 +3586,9 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, } goto out; } - catch (SessionException e) { + catch (SessionException const& e) { MessageDialog msg (string_compose( - _("Session \"%1 (snapshot %2)\" did not load successfully: %3"), + _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"), path, snap_name, e.what()), true, Gtk::MESSAGE_INFO, @@ -3687,8 +3609,8 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, catch (...) { MessageDialog msg (string_compose( - _("Session \"%1 (snapshot %2)\" did not load successfully"), - path, snap_name), + _("Session \"%1 (snapshot %2)\" did not load successfully."), + path, snap_name), true, Gtk::MESSAGE_INFO, BUTTONS_OK); @@ -3760,12 +3682,27 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, #endif retval = 0; + if (!mix_template.empty ()) { + /* if mix_template is given, assume this is a new session */ + string metascript = Glib::build_filename (mix_template, "template.lua"); + meta_session_setup (metascript); + } + + out: + /* For successful session load the splash is hidden by ARDOUR_UI::first_idle, + * which is queued by set_session(). + * If session-loading fails we hide it explicitly. + * This covers both cases in a central place. + */ + if (retval) { + hide_splash (); + } return retval; } int -ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile) +ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile* bus_profile) { Session *new_session; int x; @@ -3782,10 +3719,10 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, _session_is_new = true; try { - new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile); + new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile); } - catch (SessionException e) { + catch (SessionException const& e) { cerr << "Here are the errors associated with this failed session:\n"; dump_errors (cerr); cerr << "---------\n"; @@ -3842,6 +3779,141 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, return 0; } + +static void _lua_print (std::string s) { +#ifndef NDEBUG + std::cout << "LuaInstance: " << s << "\n"; +#endif + PBD::info << "LuaInstance: " << s << endmsg; +} + +std::map +ARDOUR_UI::route_setup_info (const std::string& script_path) +{ + std::map rv; + + if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) { + return rv; + } + + LuaState lua; + lua.Print.connect (&_lua_print); + lua.sandbox (true); + + lua_State* L = lua.getState(); + LuaInstance::register_classes (L); + LuaBindings::set_session (L, _session); + luabridge::push (L, &PublicEditor::instance()); + lua_setglobal (L, "Editor"); + + lua.do_command ("function ardour () end"); + lua.do_file (script_path); + + try { + luabridge::LuaRef fn = luabridge::getGlobal (L, "route_setup"); + if (!fn.isFunction ()) { + return rv; + } + luabridge::LuaRef rs = fn (); + if (!rs.isTable ()) { + return rv; + } + for (luabridge::Iterator i(rs); !i.isNil (); ++i) { + if (!i.key().isString()) { + continue; + } + std::string key = i.key().tostring(); + if (i.value().isString() || i.value().isNumber() || i.value().isBoolean()) { + rv[key] = i.value().tostring(); + } + } + } catch (luabridge::LuaException const& e) { + cerr << "LuaException:" << e.what () << endl; + } catch (...) { } + return rv; +} + +void +ARDOUR_UI::meta_route_setup (const std::string& script_path) +{ + if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) { + return; + } + assert (add_route_dialog); + + int count; + if ((count = add_route_dialog->count()) <= 0) { + return; + } + + LuaState lua; + lua.Print.connect (&_lua_print); + lua.sandbox (true); + + lua_State* L = lua.getState(); + LuaInstance::register_classes (L); + LuaBindings::set_session (L, _session); + luabridge::push (L, &PublicEditor::instance()); + lua_setglobal (L, "Editor"); + + lua.do_command ("function ardour () end"); + lua.do_file (script_path); + + luabridge::LuaRef args (luabridge::newTable (L)); + + args["name"] = add_route_dialog->name_template (); + args["insert_at"] = translate_order (add_route_dialog->insert_at()); + args["group"] = add_route_dialog->route_group (); + args["strict_io"] = add_route_dialog->use_strict_io (); + args["instrument"] = add_route_dialog->requested_instrument (); + args["track_mode"] = add_route_dialog->mode (); + args["channels"] = add_route_dialog->channel_count (); + args["how_many"] = count; + + try { + luabridge::LuaRef fn = luabridge::getGlobal (L, "factory"); + if (fn.isFunction()) { + fn (args)(); + } + } catch (luabridge::LuaException const& e) { + cerr << "LuaException:" << e.what () << endl; + } catch (...) { + display_insufficient_ports_message (); + } +} + +void +ARDOUR_UI::meta_session_setup (const std::string& script_path) +{ + if (!Glib::file_test (script_path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) { + return; + } + + LuaState lua; + lua.Print.connect (&_lua_print); + lua.sandbox (true); + + lua_State* L = lua.getState(); + LuaInstance::register_classes (L); + LuaBindings::set_session (L, _session); + luabridge::push (L, &PublicEditor::instance()); + lua_setglobal (L, "Editor"); + + lua.do_command ("function ardour () end"); + lua.do_file (script_path); + + try { + luabridge::LuaRef fn = luabridge::getGlobal (L, "factory"); + if (fn.isFunction()) { + fn ()(); + } + } catch (luabridge::LuaException const& e) { + cerr << "LuaException:" << e.what () << endl; + } catch (...) { + display_insufficient_ports_message (); + } +} + void ARDOUR_UI::launch_chat () { @@ -3954,8 +4026,8 @@ ARDOUR_UI::show_splash () void ARDOUR_UI::hide_splash () { - delete splash; - splash = 0; + delete splash; + splash = 0; } void @@ -3967,12 +4039,12 @@ ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* lis if (removed == 0) { MessageDialog msgd (_main_window, - _("No files were ready for clean-up"), - true, - Gtk::MESSAGE_INFO, - Gtk::BUTTONS_OK); + _("No files were ready for clean-up"), + true, + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK); msgd.set_title (_("Clean-up")); - msgd.set_secondary_text (_("If this seems suprising, \n\ + msgd.set_secondary_text (_("If this seems surprising, \n\ check for any existing snapshots.\n\ These may still include regions that\n\ require some unused files to continue to exist.")); @@ -3984,12 +4056,12 @@ require some unused files to continue to exist.")); ArdourDialog results (_("Clean-up"), true, false); struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord { - CleanupResultsModelColumns() { - add (visible_name); - add (fullpath); - } - Gtk::TreeModelColumn visible_name; - Gtk::TreeModelColumn fullpath; + CleanupResultsModelColumns() { + add (visible_name); + add (fullpath); + } + Gtk::TreeModelColumn visible_name; + Gtk::TreeModelColumn fullpath; }; @@ -4190,7 +4262,7 @@ ARDOUR_UI::cleanup_peakfiles () RegionSelection rs; TrackViewList empty; empty.clear(); - editor->get_regions_after(rs, (framepos_t) 0, empty); + editor->get_regions_after(rs, (samplepos_t) 0, empty); std::list views = rs.by_layer(); // remove displayed audio-region-views waveforms @@ -4219,7 +4291,7 @@ PresentationInfo::order_t ARDOUR_UI::translate_order (RouteDialogs::InsertAt place) { if (editor->get_selection().tracks.empty()) { - return PresentationInfo::max_order; + return place == RouteDialogs::First ? 0 : PresentationInfo::max_order; } PresentationInfo::order_t order_hint = PresentationInfo::max_order; @@ -4286,10 +4358,16 @@ ARDOUR_UI::add_route () void ARDOUR_UI::add_route_dialog_response (int r) { + if (!_session) { + warning << _("You cannot add tracks or busses without a session already loaded.") << endmsg; + return; + } + int count; switch (r) { case AddRouteDialog::Add: + add_route_dialog->reset_name_edited (); break; case AddRouteDialog::AddAndClose: add_route_dialog->ArdourDialog::on_response (r); @@ -4299,26 +4377,31 @@ ARDOUR_UI::add_route_dialog_response (int r) return; } + std::string template_path = add_route_dialog->get_template_path(); + if (!template_path.empty() && template_path.substr (0, 11) == "urn:ardour:") { + meta_route_setup (template_path.substr (11)); + return; + } + if ((count = add_route_dialog->count()) <= 0) { return; } PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at()); - string template_path = add_route_dialog->track_template(); + const string name_template = add_route_dialog->name_template (); DisplaySuspender ds; - if (!template_path.empty()) { - if (add_route_dialog->name_template_is_default()) { - _session->new_route_from_template (count, order, template_path, string()); + if (!template_path.empty ()) { + if (add_route_dialog->name_template_is_default ()) { + _session->new_route_from_template (count, order, template_path, string ()); } else { - _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template()); + _session->new_route_from_template (count, order, template_path, name_template); } return; } ChanCount input_chan= add_route_dialog->channels (); ChanCount output_chan; - string name_template = add_route_dialog->name_template (); PluginInfoPtr instrument = add_route_dialog->requested_instrument (); RouteGroup* route_group = add_route_dialog->route_group (); AutoConnectOption oac = Config->get_output_auto_connect(); @@ -4337,22 +4420,22 @@ ARDOUR_UI::add_route_dialog_response (int r) switch (add_route_dialog->type_wanted()) { case AddRouteDialog::AudioTrack: - session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order); + session_add_audio_route (true, input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order); break; case AddRouteDialog::MidiTrack: - session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order); + session_add_midi_route (true, route_group, count, name_template, strict_io, instrument, 0, order); break; case AddRouteDialog::MixedTrack: session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order); break; case AddRouteDialog::AudioBus: - session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order); + session_add_audio_route (false, input_chan.n_audio(), output_chan.n_audio(), ARDOUR::Normal, route_group, count, name_template, strict_io, order); break; case AddRouteDialog::MidiBus: session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order); break; case AddRouteDialog::VCAMaster: - session_add_vca (name_template, count); + _session->vca_manager().create_vca (count, name_template); break; } } @@ -4628,10 +4711,10 @@ ARDOUR_UI::add_video (Gtk::Window* float_window) LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps()); /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */ - ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15); + ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC samples to decode*/ 15); /* TODO seek near end of file, and read LTC until end. - * if it fails to find any LTC frames, scan complete file + * if it fails to find any LTC samples, scan complete file * * calculate drift of LTC compared to video-duration, * ask user for reference (timecode from start/mid/end) @@ -4647,16 +4730,16 @@ ARDOUR_UI::add_video (Gtk::Window* float_window) } else { /* the very first TC in the file is somteimes not aligned properly */ int i = ltc_seq.size() -1; - ARDOUR::frameoffset_t video_start_offset = - _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec); + ARDOUR::sampleoffset_t video_start_offset = + _session->nominal_sample_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec); PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg; video_timeline->set_offset(video_start_offset); } } _session->maybe_update_session_range( - std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0), - std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0)); + std::max(video_timeline->get_offset(), (ARDOUR::sampleoffset_t) 0), + std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::sampleoffset_t) 0)); if (add_video_dialog->launch_xjadeo() && local_file) { @@ -4822,7 +4905,7 @@ ARDOUR_UI::keyboard_settings () const } void -ARDOUR_UI::create_xrun_marker (framepos_t where) +ARDOUR_UI::create_xrun_marker (samplepos_t where) { if (_session) { Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0); @@ -4833,13 +4916,13 @@ ARDOUR_UI::create_xrun_marker (framepos_t where) void ARDOUR_UI::halt_on_xrun_message () { - cerr << "HALT on xrun\n"; - MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up.")); + cerr << "HALT on xrun\n"; + MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up.")); msg.run (); } void -ARDOUR_UI::xrun_handler (framepos_t where) +ARDOUR_UI::xrun_handler (samplepos_t where) { if (!_session) { return; @@ -4847,6 +4930,10 @@ ARDOUR_UI::xrun_handler (framepos_t where) ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where) + if (_session && _session->actively_recording()) { + dsp_load_indicator.set_xrun_while_recording(); + } + if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) { create_xrun_marker(where); } @@ -5063,7 +5150,7 @@ what you would like to do.\n"), PROGRAM_NAME)); } int -ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual) +ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual) { HBox* hbox = new HBox(); Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG); @@ -5089,14 +5176,14 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual case RESPONSE_ACCEPT: return 0; default: - break; + break; } - return 1; + return 1; } void -ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual) +ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual) { MessageDialog msg (string_compose (_("\ This session was created with a sample rate of %1 Hz, but\n\ @@ -5120,18 +5207,36 @@ ARDOUR_UI::use_config () } void -ARDOUR_UI::update_transport_clocks (framepos_t pos) +ARDOUR_UI::update_transport_clocks (samplepos_t pos) { - if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) { - primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); - } else { - primary_clock->set (pos); + switch (UIConfiguration::instance().get_primary_clock_delta_mode()) { + case NoDelta: + primary_clock->set (pos); + break; + case DeltaEditPoint: + primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); + break; + case DeltaOriginMarker: + { + Location* loc = _session->locations()->clock_origin_location (); + primary_clock->set (pos, false, loc ? loc->start() : 0); + } + break; } - if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) { - secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); - } else { - secondary_clock->set (pos); + switch (UIConfiguration::instance().get_secondary_clock_delta_mode()) { + case NoDelta: + secondary_clock->set (pos); + break; + case DeltaEditPoint: + secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); + break; + case DeltaOriginMarker: + { + Location* loc = _session->locations()->clock_origin_location (); + secondary_clock->set (pos, false, loc ? loc->start() : 0); + } + break; } if (big_clock_window) { @@ -5140,20 +5245,6 @@ ARDOUR_UI::update_transport_clocks (framepos_t pos) ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos); } -void -ARDOUR_UI::step_edit_status_change (bool yn) -{ - // XXX should really store pre-step edit status of things - // we make insensitive - - if (yn) { - rec_button.set_active_state (Gtkmm2ext::ImplicitActive); - rec_button.set_sensitive (false); - } else { - rec_button.unset_active_state ();; - rec_button.set_sensitive (true); - } -} void ARDOUR_UI::record_state_changed () @@ -5188,6 +5279,15 @@ ARDOUR_UI::first_idle () editor->first_idle(); } + /* in 1 second, hide the splash screen + * + * Consider hiding it *now*. If a user opens opens a dialog + * during that one second while the splash is still visible, + * the dialog will push-back the splash. + * Closing the dialog later will pop it back. + */ + Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000); + Keyboard::set_can_save_keybindings (true); return false; } @@ -5211,86 +5311,6 @@ ARDOUR_UI::store_clock_modes () _session->set_dirty (); } -ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp) - : Controllable (name), ui (u), type(tp) -{ - -} - -void -ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/) -{ - if (val < 0.5) { - /* do nothing: these are radio-style actions */ - return; - } - - const char *action = 0; - - switch (type) { - case Roll: - action = X_("Roll"); - break; - case Stop: - action = X_("Stop"); - break; - case GotoStart: - action = X_("GotoStart"); - break; - case GotoEnd: - action = X_("GotoEnd"); - break; - case AutoLoop: - action = X_("Loop"); - break; - case PlaySelection: - action = X_("PlaySelection"); - break; - case RecordEnable: - action = X_("Record"); - break; - default: - break; - } - - if (action == 0) { - return; - } - - Glib::RefPtr act = ActionManager::get_action ("Transport", action); - - if (act) { - act->activate (); - } -} - -double -ARDOUR_UI::TransportControllable::get_value (void) const -{ - float val = 0.0; - - switch (type) { - case Roll: - break; - case Stop: - break; - case GotoStart: - break; - case GotoEnd: - break; - case AutoLoop: - break; - case PlaySelection: - break; - case RecordEnable: - break; - default: - break; - } - - return val; -} - void ARDOUR_UI::setup_profile () { @@ -5386,11 +5406,11 @@ ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_pat const char* end_mono = ""; MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n" - "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n" - "From now on, use the backup copy with older versions of %3"), - xml_path, backup_path, PROGRAM_NAME, - start_big, end_big, - start_mono, end_mono), true); + "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n" + "From now on, use the backup copy with older versions of %3"), + xml_path, backup_path, PROGRAM_NAME, + start_big, end_big, + start_mono, end_mono), true); msg.run (); } @@ -5618,7 +5638,7 @@ ARDOUR_UI::audioengine_became_silent () void ARDOUR_UI::hide_application () { - Application::instance ()-> hide (); + Application::instance ()-> hide (); } void @@ -5744,7 +5764,7 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey bool special_handling_of_unmodified_accelerators = false; const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK)); - if (focus) { + if (focus) { /* some widget has keyboard focus */ @@ -5767,13 +5787,13 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey } } - DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n", - win, - ev->keyval, - Gtkmm2ext::show_gdk_event_state (ev->state), + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n", + win, + ev->keyval, + Gtkmm2ext::show_gdk_event_state (ev->state), special_handling_of_unmodified_accelerators, Keyboard::some_magic_widget_has_focus(), - focus, + focus, (focus ? gtk_widget_get_name (focus) : "no focus widget"), ((ev->state & mask) ? "yes" : "no"), window.get_title())); @@ -5814,7 +5834,7 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey /* no special handling or there are modifiers in effect: accelerate first */ - DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n"); + DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n"); DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n", ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval))); @@ -5849,12 +5869,12 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey return true; } - DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n"); + DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n"); - if (gtk_window_propagate_key_event (win, ev)) { - DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n"); - return true; - } + if (gtk_window_propagate_key_event (win, ev)) { + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n"); + return true; + } } else {