X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=9c534c406a2c748cdf05548a57ceb36d1d6a9ef8;hb=46e25db073834ca66c410808c96e3b4180df860f;hp=449ce2f37618d5887ca4dc2c849f9df8d419badd;hpb=f89c285bcc6c99fce417da9ebfc9434e2e60314f;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 449ce2f376..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" @@ -131,52 +133,38 @@ bool could_be_a_valid_path (const string& path); ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) - : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp), + : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp) - primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true), - secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true), - preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true), - postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true), - - /* preroll stuff */ - - preroll_button (_("pre\nroll")), - postroll_button (_("post\nroll")), + , 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)) /* big clock */ - big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false), + , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false)) /* transport */ - 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)), - - 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), - - punch_in_button (_("Punch In")), - punch_out_button (_("Punch Out")), - auto_return_button (_("Auto Return")), - auto_play_button (_("Auto Play")), - auto_input_button (_("Auto Input")), - click_button (_("Click")), - time_master_button (_("time\nmaster")), - - auditioning_alert_button (_("AUDITION")), - solo_alert_button (_("SOLO")), - - error_log_button (_("Errors")) + , 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_return_button (ArdourButton::led_default_elements) + , auto_play_button (ArdourButton::led_default_elements) + , auto_input_button (ArdourButton::led_default_elements) + + , 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; @@ -204,6 +192,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) ui_config = new UIConfiguration(); theme_manager = new ThemeManager(); + key_editor = 0; + editor = 0; mixer = 0; editor = 0; @@ -217,6 +207,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) _will_create_new_session_automatically = false; add_route_dialog = 0; route_params = 0; + bundle_manager = 0; rc_option_editor = 0; session_option_editor = 0; location_ui = 0; @@ -229,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; @@ -256,9 +261,13 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2)); /* handle requests to quit (coming from JACK session) */ - + 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)); @@ -292,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); @@ -306,11 +314,11 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) TimeAxisViewItem::set_constant_heights (); /* The following must happen after ARDOUR::init() so that Config is set up */ - + location_ui = new ActionWindowProxy (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations")); big_clock_window = new ActionWindowProxy (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock")); speaker_config_window = new ActionWindowProxy (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config")); - + for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) { _global_port_matrix[*i] = new ActionWindowProxy ( string_compose ("GlobalPortMatrix-%1", (*i).to_string()), @@ -324,11 +332,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) SpeakerDialog* s = new SpeakerDialog (); s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("/Common/toggle-speaker-config"))); speaker_config_window->set (s); - + starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup)); stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown)); - platform_setup (); + _process_thread = new ProcessThread (); + _process_thread->init (); } /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */ @@ -339,7 +348,7 @@ ARDOUR_UI::run_startup (bool should_be_new, string load_template) _startup = new ArdourStartup (); XMLNode* audio_setup = Config->extra_xml ("AudioSetup"); - + if (audio_setup && _startup->engine_control()) { _startup->engine_control()->set_state (*audio_setup); } @@ -408,6 +417,12 @@ ARDOUR_UI::post_engine () if (setup_windows ()) { 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(); @@ -441,11 +456,11 @@ ARDOUR_UI::post_engine () /* set default clock modes */ if (Profile->get_sae()) { - primary_clock.set_mode (AudioClock::BBT); - secondary_clock.set_mode (AudioClock::MinSec); + primary_clock->set_mode (AudioClock::BBT); + secondary_clock->set_mode (AudioClock::MinSec); } else { - primary_clock.set_mode (AudioClock::Timecode); - secondary_clock.set_mode (AudioClock::BBT); + primary_clock->set_mode (AudioClock::Timecode); + secondary_clock->set_mode (AudioClock::BBT); } /* start the time-of-day-clock */ @@ -711,7 +726,12 @@ ARDOUR_UI::startup () for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) { 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)); } @@ -809,7 +829,11 @@ ARDOUR_UI::finish() } if (_session->dirty()) { - switch (ask_about_saving_session(_("quit"))) { + vector actions; + actions.push_back (_("Don't quit")); + actions.push_back (_("Just quit")); + actions.push_back (_("Save and quit")); + switch (ask_about_saving_session(actions)) { case -1: return; break; @@ -858,7 +882,7 @@ If you still wish to quit, please use the\n\n\ } int -ARDOUR_UI::ask_about_saving_session (const string & what) +ARDOUR_UI::ask_about_saving_session (const vector& actions) { ArdourDialog window (_("Unsaved Session")); Gtk::HBox dhbox; // the hbox for the image and text @@ -867,12 +891,11 @@ ARDOUR_UI::ask_about_saving_session (const string & what) string msg; - msg = string_compose(_("Don't %1"), what); - window.add_button (msg, RESPONSE_REJECT); - msg = string_compose(_("Just %1"), what); - window.add_button (msg, RESPONSE_APPLY); - msg = string_compose(_("Save and %1"), what); - window.add_button (msg, RESPONSE_ACCEPT); + assert (actions.size() >= 3); + + window.add_button (actions[0], RESPONSE_REJECT); + window.add_button (actions[1], RESPONSE_APPLY); + window.add_button (actions[2], RESPONSE_ACCEPT); window.set_default_response (RESPONSE_ACCEPT); @@ -880,15 +903,14 @@ ARDOUR_UI::ask_about_saving_session (const string & what) noquit_button.set_name ("EditorGTKButton"); string prompt; - string type; if (_session->snap_name() == _session->name()) { - type = _("session"); + 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?"), + _session->snap_name()); } else { - type = _("snapshot"); + 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?"), + _session->snap_name()); } - prompt = string_compose(_("The %1 \"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"), - type, _session->snap_name()); prompt_label.set_text (prompt); prompt_label.set_name (X_("PrompterLabel")); @@ -957,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) @@ -970,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 (""); } @@ -1030,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); @@ -1044,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. @@ -1407,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; } } } @@ -1585,7 +1690,7 @@ ARDOUR_UI::transport_record (bool roll) //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl; } -void +void ARDOUR_UI::transport_roll () { if (!_session) { @@ -1617,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); } @@ -1634,7 +1739,7 @@ ARDOUR_UI::transport_roll () void ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) { - + if (!_session) { return; } @@ -1661,7 +1766,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) /* drop out of loop/range playback but leave transport rolling */ if (_session->get_play_loop()) { if (Config->get_seamless_loop()) { - /* the disk buffers contain copies of the loop - we can't + /* the disk buffers contain copies of the loop - we can't just keep playing, so stop the transport. the user can restart as they wish. */ @@ -1674,17 +1779,17 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) } else if (_session->get_play_range ()) { affect_transport = false; _session->request_play_range (0, true); - } - } + } + } if (affect_transport) { 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); } - + _session->request_transport_speed (1.0f); } } @@ -1696,25 +1801,25 @@ ARDOUR_UI::toggle_session_auto_loop () if (!_session) { return; } - + if (_session->get_play_loop()) { if (_session->transport_rolling()) { - + Location * looploc = _session->locations()->auto_loop_location(); - + if (looploc) { _session->request_locate (looploc->start(), true); _session->request_play_loop (false); } - + } else { _session->request_play_loop (false); } } else { - + Location * looploc = _session->locations()->auto_loop_location(); - + if (looploc) { _session->request_play_loop (true); } @@ -1812,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; } @@ -1829,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 (); } } @@ -2071,17 +2176,16 @@ 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) { char timebuf[128]; time_t n; struct tm local_time; - + 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); } @@ -2106,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; @@ -2136,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) { @@ -2147,8 +2324,10 @@ 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); } @@ -2166,7 +2345,7 @@ ARDOUR_UI::save_state_canfail (string name, bool switch_to_it) return ret; } } - cerr << "SS canfail\n"; + save_ardour_state (); /* XXX cannot fail? yeah, right ... */ return 0; } @@ -2175,7 +2354,7 @@ void ARDOUR_UI::primary_clock_value_changed () { if (_session) { - _session->request_locate (primary_clock.current_time ()); + _session->request_locate (primary_clock->current_time ()); } } @@ -2183,7 +2362,7 @@ void ARDOUR_UI::big_clock_value_changed () { if (_session) { - _session->request_locate (big_clock.current_time ()); + _session->request_locate (big_clock->current_time ()); } } @@ -2191,7 +2370,7 @@ void ARDOUR_UI::secondary_clock_value_changed () { if (_session) { - _session->request_locate (secondary_clock.current_time ()); + _session->request_locate (secondary_clock->current_time ()); } } @@ -2211,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 (); } } @@ -2270,102 +2449,6 @@ ARDOUR_UI::import_metadata () dialog.run (); } -void -ARDOUR_UI::fontconfig_dialog () -{ -#ifdef GTKOSX - /* X11 users will always have fontconfig info around, but new GTK-OSX users - may not and it can take a while to build it. Warn them. - */ - - std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig"); - - if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) { - MessageDialog msg (*_startup, - string_compose (_("Welcome to %1.\n\n" - "The program will take a bit longer to start up\n" - "while the system fonts are checked.\n\n" - "This will only be done once, and you will\n" - "not see this message again\n"), PROGRAM_NAME), - true, - Gtk::MESSAGE_INFO, - Gtk::BUTTONS_OK); - pop_back_splash (); - msg.show_all (); - msg.present (); - msg.run (); - } -#endif -} - -void -ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session) -{ - existing_session = false; - - if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) { - session_path = cmdline_path; - existing_session = true; - } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) { - session_path = Glib::path_get_dirname (string (cmdline_path)); - existing_session = true; - } else { - /* it doesn't exist, assume the best */ - session_path = Glib::path_get_dirname (string (cmdline_path)); - } - - session_name = basename_nosuffix (string (cmdline_path)); -} - -int -ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session) -{ - /* when this is called, the backend audio system must be running */ - - /* the main idea here is to deal with the fact that a cmdline argument for the session - can be interpreted in different ways - it could be a directory or a file, and before - we load, we need to know both the session directory and the snapshot (statefile) within it - that we are supposed to use. - */ - - if (session_name.length() == 0 || session_path.length() == 0) { - return false; - } - - if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) { - - std::string predicted_session_file; - - predicted_session_file = session_path; - predicted_session_file += '/'; - predicted_session_file += session_name; - predicted_session_file += ARDOUR::statefile_suffix; - - if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) { - existing_session = true; - } - - } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) { - - if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) { - /* existing .ardour file */ - existing_session = true; - } - - } else { - existing_session = false; - } - - /* lets just try to load it */ - - if (create_engine ()) { - backend_audio_error (false, _startup); - return -1; - } - - return load_session (session_path, session_name); -} - bool ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path) { @@ -2503,7 +2586,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri int ret = -1; bool likely_new = false; - if (! load_template.empty()) { + if (!load_template.empty()) { should_be_new = true; template_name = load_template; } @@ -2517,14 +2600,17 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri to find the session. */ - if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) { + string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix); + + if (suffix != string::npos) { session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name); + session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix); + session_name = Glib::path_get_basename (session_name); } else { session_path = ARDOUR_COMMAND_LINE::session_name; + session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name); } - session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name); - } else { bool const apply = run_startup (should_be_new, load_template); @@ -2543,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()) { @@ -2649,7 +2741,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri /* not connected to the AudioEngine, so quit to avoid an infinite loop */ exit (1); } - + if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) { _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false); exit (1); @@ -2680,7 +2772,9 @@ ARDOUR_UI::close_session() goto_editor_window (); } -/** @return -2 if the load failed because we are not connected to the AudioEngine */ +/** @param snap_name Snapshot name (without .ardour suffix). + * @return -2 if the load failed because we are not connected to the AudioEngine. + */ int ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template) { @@ -3080,7 +3174,7 @@ ARDOUR_UI::cleanup () (Gtk::ButtonsType)(Gtk::BUTTONS_NONE)); checker.set_title (_("Clean-up")); - + checker.set_secondary_text(_("Clean-up is a destructive operation.\n\ ALL undo/redo information will be lost if you clean-up.\n\ Clean-up will move all unused files to a \"dead\" location.")); @@ -3271,7 +3365,7 @@ ARDOUR_UI::editor_settings () const } else { node = Config->instant_xml(X_("Editor")); } - + if (!node) { if (getenv("ARDOUR_INSTANT_XML_PATH")) { node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH")); @@ -3497,19 +3591,19 @@ void ARDOUR_UI::update_transport_clocks (framepos_t pos) { if (Config->get_primary_clock_delta_edit_cursor()) { - primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1); + primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1); } else { - primary_clock.set (pos, 0, true); + primary_clock->set (pos, 0, true); } if (Config->get_secondary_clock_delta_edit_cursor()) { - secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2); + secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2); } else { - secondary_clock.set (pos); + secondary_clock->set (pos); } if (big_clock_window->get()) { - big_clock.set (pos); + big_clock->set (pos); } } @@ -3521,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); } } @@ -3543,9 +3637,9 @@ ARDOUR_UI::record_state_changed () bool const h = _session->have_rec_enabled_track (); if (r == Session::Recording && h) { - big_clock.set_widget_name ("BigClockRecording"); + big_clock->set_widget_name ("BigClockRecording"); } else { - big_clock.set_widget_name ("BigClockNonRecording"); + big_clock->set_widget_name ("BigClockNonRecording"); } } @@ -3570,15 +3664,19 @@ ARDOUR_UI::store_clock_modes () XMLNode* node = new XMLNode(X_("ClockModes")); for (vector::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) { - node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode())); + XMLNode* child = new XMLNode (X_("Clock")); + + child->add_property (X_("name"), (*x)->name()); + child->add_property (X_("mode"), enum_2_string ((*x)->mode())); + child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes"))); + + node->add_child_nocopy (*child); } _session->add_extra_xml (*node); _session->set_dirty (); } - - ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp) : Controllable (name), ui (u), type(tp) { @@ -3659,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 () { @@ -3760,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); @@ -3770,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(); + } +}