X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=9c534c406a2c748cdf05548a57ceb36d1d6a9ef8;hb=46e25db073834ca66c410808c96e3b4180df860f;hp=0230d5ce4a8e3bb4cc09e16a477e7552b8db45cb;hpb=a6517a01902370e6c6dfa3e4a153e214b68cf4a7;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 0230d5ce4a..9c534c406a 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -78,6 +78,7 @@ #include "ardour/midi_track.h" #include "ardour/filesystem_paths.h" #include "ardour/filename_extensions.h" +#include "ardour/process_thread.h" typedef uint64_t microseconds_t; @@ -91,6 +92,7 @@ typedef uint64_t microseconds_t; #include "engine_dialog.h" #include "gain_meter.h" #include "global_port_matrix.h" +#include "gui_object.h" #include "gui_thread.h" #include "keyboard.h" #include "location_ui.h" @@ -133,15 +135,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp) + , gui_object_state (new GUIObjectState) , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true)) , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true)) - , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true)) - , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true)) - - /* preroll stuff */ - - , preroll_button (_("pre\nroll")) - , postroll_button (_("post\nroll")) /* big clock */ @@ -157,25 +153,19 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)) , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)) - , roll_button (roll_controllable) - , stop_button (stop_controllable) - , goto_start_button (goto_start_controllable) - , goto_end_button (goto_end_controllable) - , auto_loop_button (auto_loop_controllable) - , play_selection_button (play_selection_controllable) - , rec_button (rec_controllable) + , auto_return_button (ArdourButton::led_default_elements) + , auto_play_button (ArdourButton::led_default_elements) + , auto_input_button (ArdourButton::led_default_elements) - , auto_return_button (_("Auto Return")) - , auto_play_button (_("Auto Play")) - , auto_input_button (_("Auto Input")) - , click_button (_("Click")) - , time_master_button (_("time\nmaster")) + , time_master_button (ArdourButton::led_default_elements) , auditioning_alert_button (_("AUDITION")) , solo_alert_button (_("SOLO")) , error_log_button (_("Errors")) + , _status_bar_visibility (X_("status-bar")) + { using namespace Gtk::Menu_Helpers; @@ -230,14 +220,28 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) original_big_clock_height = -1; original_big_clock_font_size = 0; - roll_button.unset_flags (Gtk::CAN_FOCUS); - stop_button.unset_flags (Gtk::CAN_FOCUS); - goto_start_button.unset_flags (Gtk::CAN_FOCUS); - goto_end_button.unset_flags (Gtk::CAN_FOCUS); - auto_loop_button.unset_flags (Gtk::CAN_FOCUS); - play_selection_button.unset_flags (Gtk::CAN_FOCUS); - rec_button.unset_flags (Gtk::CAN_FOCUS); - join_play_range_button.unset_flags (Gtk::CAN_FOCUS); + 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"); + join_play_range_button.set_name ("transport button"); + midi_panic_button.set_name ("transport button"); + + goto_start_button.set_tweaks (ArdourButton::ShowClick); + goto_end_button.set_tweaks (ArdourButton::ShowClick); + midi_panic_button.set_tweaks (ArdourButton::ShowClick); + last_configure_time= 0; last_peak_grab = 0; @@ -260,6 +264,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ()); + /* tell the user about feedback */ + + ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ()); + /* handle requests to deal with missing files */ ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3)); @@ -293,7 +301,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) keyboard = new ArdourKeyboard(*this); - XMLNode* node = ARDOUR_UI::instance()->keyboard_settings(); if (node) { keyboard->set_state (*node, Stateful::loading_state_version); @@ -328,6 +335,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup)); stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown)); + + _process_thread = new ProcessThread (); + _process_thread->init (); } /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */ @@ -408,6 +418,12 @@ ARDOUR_UI::post_engine () throw failed_constructor (); } + /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */ + XMLNode* n = Config->extra_xml (X_("UI")); + if (n) { + _status_bar_visibility.set_state (*n); + } + check_memory_locking(); /* this is the first point at which all the keybindings are available */ @@ -711,6 +727,11 @@ ARDOUR_UI::startup () add_window_proxy (_global_port_matrix[*i]); } + /* We have to do this here since goto_editor_window() ends up calling show_all() on the + * editor window, and we may want stuff to be hidden. + */ + _status_bar_visibility.update (); + BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME)); } @@ -958,7 +979,7 @@ ARDOUR_UI::every_point_zero_one_seconds () void ARDOUR_UI::update_sample_rate (framecnt_t) { - char buf[32]; + char buf[64]; ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored) @@ -971,40 +992,111 @@ ARDOUR_UI::update_sample_rate (framecnt_t) framecnt_t rate = engine->frame_rate(); if (fmod (rate, 1000.0) != 0.0) { - snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"), + snprintf (buf, sizeof (buf), _("JACK: %.1f kHz / %4.1f ms"), (float) rate/1000.0f, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } else { - snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"), + snprintf (buf, sizeof (buf), _("JACK: %" PRId64 " kHz / %4.1f ms"), rate/1000, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } } - sample_rate_label.set_text (buf); + sample_rate_label.set_markup (buf); +} + +void +ARDOUR_UI::update_format () +{ + if (!_session) { + format_label.set_text (""); + return; + } + + stringstream s; + s << "File: "; + + switch (_session->config.get_native_file_header_format ()) { + case BWF: + s << "BWF"; + break; + case WAVE: + s << "WAV"; + break; + case WAVE64: + s << "WAV64"; + break; + case CAF: + s << "CAF"; + break; + case AIFF: + s << "AIFF"; + break; + case iXML: + s << "iXML"; + break; + case RF64: + s << "RF64"; + break; + } + + s << " "; + + switch (_session->config.get_native_file_data_format ()) { + case FormatFloat: + s << "32-float"; + break; + case FormatInt24: + s << "24-int"; + break; + case FormatInt16: + s << "16-int"; + break; + } + + s << ""; + + format_label.set_markup (s.str ()); } void ARDOUR_UI::update_cpu_load () { - char buf[32]; - snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load()); - cpu_load_label.set_text (buf); + char buf[64]; + + /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar + should also be changed. + */ + + float const c = engine->get_cpu_load (); + snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), c >= 90 ? X_("red") : X_("green"), c); + cpu_load_label.set_markup (buf); } void ARDOUR_UI::update_buffer_load () { - char buf[64]; - uint32_t c, p; + char buf[256]; + uint32_t const playback = _session ? _session->playback_load () : 100; + uint32_t const capture = _session ? _session->capture_load () : 100; + + /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar + should also be changed. + */ + if (_session) { - c = _session->capture_load (); - p = _session->playback_load (); + snprintf ( + buf, sizeof (buf), + _("Buffers: p:%" PRIu32 "%% " + "c:%" PRIu32 "%%"), + playback <= 5 ? X_("red") : X_("green"), + playback, + capture <= 5 ? X_("red") : X_("green"), + capture + ); - snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"), - _session->playback_load(), _session->capture_load()); - buffer_load_label.set_text (buf); + buffer_load_label.set_markup (buf); } else { buffer_load_label.set_text (""); } @@ -1031,7 +1123,7 @@ ARDOUR_UI::update_disk_space() framecnt_t fr = _session->frame_rate(); if (frames == max_framecnt) { - strcpy (buf, _("Disk: 24hrs+")); + snprintf (buf, sizeof (buf), _("Disk: 24hrs+")); } else { rec_enabled_streams = 0; _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams); @@ -1045,15 +1137,27 @@ ARDOUR_UI::update_disk_space() int secs; hrs = frames / (fr * 3600); - frames -= hrs * fr * 3600; - mins = frames / (fr * 60); - frames -= mins * fr * 60; - secs = frames / fr; - snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs); + if (hrs > 24) { + snprintf (buf, sizeof (buf), _("Disk: >24 hrs")); + } else { + frames -= hrs * fr * 3600; + mins = frames / (fr * 60); + frames -= mins * fr * 60; + secs = frames / fr; + + bool const low = (hrs == 0 && mins <= 30); + + snprintf ( + buf, sizeof(buf), + _("Disk: %02dh:%02dm:%02ds"), + low ? X_("red") : X_("green"), + hrs, mins, secs + ); + } } - disk_space_label.set_text (buf); + disk_space_label.set_markup (buf); // An attempt to make the disk space label flash red when space has run out. @@ -1408,9 +1512,9 @@ ARDOUR_UI::session_add_audio_route ( if (routes.size() != how_many) { if (how_many == 1) { - error << _("could not create a new audio track") << endmsg; + error << _("could not create a new audio bus") << endmsg; } else { - error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg; + error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg; } } } @@ -1618,12 +1722,12 @@ ARDOUR_UI::transport_roll () if (!Config->get_seamless_loop()) { _session->request_play_loop (false, true); } - } else if (_session->get_play_range () && !join_play_range_button.get_active()) { + } else if (_session->get_play_range () && !join_play_range_button.active_state()) { /* stop playing a range if we currently are */ _session->request_play_range (0, true); } - if (join_play_range_button.get_active()) { + if (join_play_range_button.active_state()) { _session->request_play_range (&editor->get_selection().time, true); } @@ -1682,7 +1786,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) if (rolling) { _session->request_stop (with_abort, true); } else { - if (join_play_range_button.get_active()) { + if (join_play_range_button.active_state()) { _session->request_play_range (&editor->get_selection().time, true); } @@ -1813,10 +1917,10 @@ void ARDOUR_UI::map_transport_state () { if (!_session) { - auto_loop_button.set_visual_state (0); - play_selection_button.set_visual_state (0); - roll_button.set_visual_state (0); - stop_button.set_visual_state (1); + auto_loop_button.unset_active_state (); + play_selection_button.unset_active_state (); + roll_button.unset_active_state (); + stop_button.set_active_state (Gtkmm2ext::Active); return; } @@ -1830,37 +1934,37 @@ ARDOUR_UI::map_transport_state () if (_session->get_play_range()) { - play_selection_button.set_visual_state (1); - roll_button.set_visual_state (0); - auto_loop_button.set_visual_state (0); + play_selection_button.set_active_state (Gtkmm2ext::Active); + roll_button.unset_active_state (); + auto_loop_button.unset_active_state (); } else if (_session->get_play_loop ()) { - auto_loop_button.set_visual_state (1); - play_selection_button.set_visual_state (0); - roll_button.set_visual_state (0); + auto_loop_button.set_active_state (Gtkmm2ext::Active); + play_selection_button.unset_active_state (); + roll_button.unset_active_state (); } else { - roll_button.set_visual_state (1); - play_selection_button.set_visual_state (0); - auto_loop_button.set_visual_state (0); + roll_button.set_active_state (Gtkmm2ext::Active); + play_selection_button.unset_active_state (); + auto_loop_button.unset_active_state (); } - if (join_play_range_button.get_active()) { + if (join_play_range_button.active_state()) { /* light up both roll and play-selection if they are joined */ - roll_button.set_visual_state (1); - play_selection_button.set_visual_state (1); + roll_button.set_active_state (Gtkmm2ext::Active); + play_selection_button.set_active_state (Gtkmm2ext::Active); } - stop_button.set_visual_state (0); + stop_button.unset_active_state (); } else { - stop_button.set_visual_state (1); - roll_button.set_visual_state (0); - play_selection_button.set_visual_state (0); - auto_loop_button.set_visual_state (0); + stop_button.set_active_state (Gtkmm2ext::Active); + roll_button.unset_active_state (); + play_selection_button.unset_active_state (); + auto_loop_button.unset_active_state (); update_disk_space (); } } @@ -2072,7 +2176,6 @@ ARDOUR_UI::snapshot_session (bool switch_to_it) prompter.set_name ("Prompter"); prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); prompter.set_title (_("Take Snapshot")); - prompter.set_title (_("Take Snapshot")); prompter.set_prompt (_("Name of new snapshot")); if (!switch_to_it) { @@ -2082,7 +2185,7 @@ ARDOUR_UI::snapshot_session (bool switch_to_it) time (&n); localtime_r (&n, &local_time); - strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time); + strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time); prompter.set_initial_text (timebuf); } @@ -2107,6 +2210,12 @@ ARDOUR_UI::snapshot_session (bool switch_to_it) msg.run (); goto again; } + if (snapname.find (':') != string::npos) { + MessageDialog msg (_("To ensure compatibility with various systems\n" + "snapshot names may not contain a ':' character")); + msg.run (); + goto again; + } } vector p; @@ -2137,6 +2246,73 @@ ARDOUR_UI::snapshot_session (bool switch_to_it) } } +/** Ask the user for the name of a new shapshot and then take it. + */ + +void +ARDOUR_UI::rename_session () +{ + if (!_session) { + return; + } + + ArdourPrompter prompter (true); + string name; + + prompter.set_name ("Prompter"); + prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); + prompter.set_title (_("Rename Session")); + prompter.set_prompt (_("New session name")); + + again: + switch (prompter.run()) { + case RESPONSE_ACCEPT: + { + prompter.get_result (name); + + bool do_rename = (name.length() != 0); + + if (do_rename) { + if (name.find ('/') != string::npos) { + MessageDialog msg (_("To ensure compatibility with various systems\n" + "session names may not contain a '/' character")); + msg.run (); + goto again; + } + if (name.find ('\\') != string::npos) { + MessageDialog msg (_("To ensure compatibility with various systems\n" + "session names may not contain a '\\' character")); + msg.run (); + goto again; + } + + switch (_session->rename (name)) { + case -1: { + MessageDialog msg (_("That name is already in use by another directory/folder. Please try again.")); + msg.set_position (WIN_POS_MOUSE); + msg.run (); + goto again; + break; + } + case 0: + break; + default: { + MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point")); + msg.set_position (WIN_POS_MOUSE); + msg.run (); + break; + } + } + } + + break; + } + + default: + break; + } +} + void ARDOUR_UI::save_state (const string & name, bool switch_to_it) { @@ -2148,6 +2324,8 @@ ARDOUR_UI::save_state (const string & name, bool switch_to_it) } } + node->add_child_nocopy (gui_object_state->get_state()); + _session->add_extra_xml (*node); save_state_canfail (name, switch_to_it); @@ -2212,14 +2390,14 @@ ARDOUR_UI::transport_rec_enable_blink (bool onoff) if (r == Session::Enabled || (r == Session::Recording && !h)) { if (onoff) { - rec_button.set_visual_state (2); + rec_button.set_active_state (Active); } else { - rec_button.set_visual_state (0); + rec_button.set_active_state (Mid); } } else if (r == Session::Recording && h) { - rec_button.set_visual_state (1); + rec_button.set_active_state (Mid); } else { - rec_button.set_visual_state (0); + rec_button.unset_active_state (); } } @@ -2451,6 +2629,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri session_name = _startup->session_name (likely_new); + string::size_type suffix = session_name.find (statefile_suffix); + + if (suffix != string::npos) { + session_name = session_name.substr (0, suffix); + } + /* this shouldn't happen, but we catch it just in case it does */ if (session_name.empty()) { @@ -3431,10 +3615,10 @@ ARDOUR_UI::step_edit_status_change (bool yn) // we make insensitive if (yn) { - rec_button.set_visual_state (3); + rec_button.set_active_state (Mid); rec_button.set_sensitive (false); } else { - rec_button.set_visual_state (0); + rec_button.unset_active_state ();; rec_button.set_sensitive (true); } } @@ -3573,12 +3757,6 @@ ARDOUR_UI::TransportControllable::get_value (void) const return val; } -void -ARDOUR_UI::TransportControllable::set_id (const string& str) -{ - _id = str; -} - void ARDOUR_UI::setup_profile () { @@ -3674,7 +3852,7 @@ ARDOUR_UI::missing_file (Session*s, std::string str, DataType type) } int -ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector hits) +ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector hits) { AmbiguousFileDialog dialog (file, hits); @@ -3684,3 +3862,37 @@ ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vectorget_buffers (); +} + +/** Drop our thread-local buffers */ +void +ARDOUR_UI::drop_process_buffers () +{ + _process_thread->drop_buffers (); +} + +void +ARDOUR_UI::feedback_detected () +{ + MessageDialog d ( + _("Something you have just done has generated a feedback path within Ardour's " + "routing. Until this feedback is removed, Ardour's output will be as it was " + "before you made the feedback-generating connection.") + ); + + d.run (); +} + +void +ARDOUR_UI::midi_panic () +{ + if (_session) { + _session->midi_panic(); + } +}