X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=a557f08ca9575b70a27c644b117596dea7aa9f15;hb=a5a0da468616cc7f25cdb86137ae9321cee7aef0;hp=4875b8db89a53bf6e825fd20969c6c266f2c3cf6;hpb=9062d7c731472bd9455bea829653653681ce4f17;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 4875b8db89..a557f08ca9 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2002 Paul Davis + Copyright (C) 1999-2007 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,7 +15,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ #include @@ -28,24 +27,32 @@ #include +#include + #include #include #include +#include #include +#include #include #include +#include +#include #include #include #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -65,13 +72,13 @@ #include "mixer_ui.h" #include "prompter.h" #include "opts.h" -#include "keyboard_target.h" #include "add_route_dialog.h" #include "new_session_dialog.h" #include "about.h" #include "utils.h" #include "gui_thread.h" -#include "color_manager.h" +#include "theme_manager.h" +#include "engine_dialog.h" #include "i18n.h" @@ -82,20 +89,21 @@ using namespace Gtk; using namespace sigc; ARDOUR_UI *ARDOUR_UI::theArdourUI = 0; +UIConfiguration *ARDOUR_UI::ui_config = 0; sigc::signal ARDOUR_UI::Blink; sigc::signal ARDOUR_UI::RapidScreenUpdate; sigc::signal ARDOUR_UI::SuperRapidScreenUpdate; -sigc::signal ARDOUR_UI::Clock; +sigc::signal ARDOUR_UI::Clock; -ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) +ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) - : Gtkmm2ext::UI ("ardour", argcp, argvp, rcfile), - - primary_clock (X_("TransportClockDisplay"), true, false, true), - secondary_clock (X_("SecondaryClockDisplay"), true, false, true), - preroll_clock (X_("PreRollClock"), true, true), - postroll_clock (X_("PostRollClock"), true, true), + : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp), + + primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true), + secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true), + preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true), + postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true), /* adjuster table */ @@ -108,27 +116,54 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) /* big clock */ - big_clock ("BigClockNonRecording", true, false, true), + big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true), /* transport */ - time_master_button (_("time\nmaster")), - + roll_controllable ("transport roll", *this, TransportControllable::Roll), + stop_controllable ("transport stop", *this, TransportControllable::Stop), + goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart), + goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd), + auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop), + play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection), + rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable), + shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl), + shuttle_controller_binding_proxy (shuttle_controllable), + + 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), + shuttle_units_button (_("% ")), punch_in_button (_("Punch In")), punch_out_button (_("Punch Out")), auto_return_button (_("Auto Return")), - auto_play_button (_("Autuo Play")), + 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")), - shown_flag (false) + shown_flag (false), + error_log_button (_("Errors")) { using namespace Gtk::Menu_Helpers; Gtkmm2ext::init(); + +#ifdef TOP_MENUBAR + _auto_display_errors = false; +#endif + + if (getenv ("ARDOUR_DEBUG_UPDATES")) { + gdk_window_set_debug_updates (true); + } about = 0; @@ -136,34 +171,39 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) theArdourUI = this; } - /* load colors */ - - color_manager = new ColorManager(); - - std::string color_file = ARDOUR::find_config_file("ardour.colors"); - - color_manager->load (color_file); + ui_config = new UIConfiguration(); + theme_manager = new ThemeManager(); + engine = 0; editor = 0; mixer = 0; session = 0; _session_is_new = false; big_clock_window = 0; session_selector_window = 0; + new_session_dialog = 0; last_key_press_time = 0; connection_editor = 0; add_route_dialog = 0; route_params = 0; option_editor = 0; location_ui = 0; + key_editor = 0; open_session_selector = 0; have_configure_timeout = false; - have_disk_overrun_displayed = false; - have_disk_underrun_displayed = false; + have_disk_speed_dialog_displayed = false; _will_create_new_session_automatically = false; session_loaded = false; + loading_dialog = 0; last_speed_displayed = -1.0f; + keybindings_path = ARDOUR::find_config_file ("ardour.bindings"); + /* all changes go to the user directory */ + user_keybindings_path = get_user_ardour_path (); + user_keybindings_path += '/'; + user_keybindings_path += "ardour.bindings"; + + can_save_keybindings = false; last_configure_time.tv_sec = 0; last_configure_time.tv_usec = 0; @@ -185,31 +225,73 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog)); - /* have to wait for AudioEngine and Configuration before proceeding */ + /* lets get this party started */ + + try { + ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization); + setup_gtk_ardour_enums (); + Config->set_current_owner (ConfigVariableBase::Interface); + setup_profile (); + + } catch (failed_constructor& err) { + error << _("could not initialize Ardour.") << endmsg; + // pass it on up + throw err; + } + + /* we like keyboards */ + + keyboard = new Keyboard; + + starting.connect (mem_fun(*this, &ARDOUR_UI::startup)); + stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown)); } -void -ARDOUR_UI::set_engine (AudioEngine& e) +int +ARDOUR_UI::create_engine () { - engine = &e; + // this gets called every time by new_session() + + if (engine) { + return 0; + } + + try { + engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name); + + } catch (...) { + + return -1; + } engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped)); engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running)); engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted)); engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate)); - ActionManager::init (); - new_session_dialog = new NewSessionDialog(); + post_engine (); - _tooltips.enable(); + return 0; +} - keyboard = new Keyboard; +void +ARDOUR_UI::post_engine () +{ + /* Things to be done once we create the AudioEngine + */ + + check_memory_locking(); + + ActionManager::init (); + _tooltips.enable(); if (setup_windows ()) { throw failed_constructor (); } - if (GTK_ARDOUR::show_key_actions) { + /* this is the first point at which all the keybindings are available */ + + if (ARDOUR_COMMAND_LINE::show_key_actions) { vector names; vector paths; vector keys; @@ -226,9 +308,6 @@ ARDOUR_UI::set_engine (AudioEngine& e) exit (0); } - /* start with timecode, metering enabled - */ - blink_timeout_tag = -1; /* the global configuration object is now valid */ @@ -240,21 +319,35 @@ ARDOUR_UI::set_engine (AudioEngine& e) AudioFileSource::set_build_peakfiles (true); AudioFileSource::set_build_missing_peakfiles (true); - if (AudioSource::start_peak_thread ()) { - throw failed_constructor(); - } + /* set default clock modes */ + + primary_clock.set_mode (AudioClock::SMPTE); + secondary_clock.set_mode (AudioClock::BBT); /* start the time-of-day-clock */ +#ifndef GTKOSX + /* OS X provides an always visible wallclock, so don't be stupid */ update_wall_clock (); Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000); +#endif update_disk_space (); update_cpu_load (); update_sample_rate (engine->frame_rate()); - starting.connect (mem_fun(*this, &ARDOUR_UI::startup)); - stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown)); + platform_specific (); + + /* now start and maybe save state */ + + if (do_engine_start () == 0) { + if (session && _session_is_new) { + /* we need to retain initial visual + settings for a new session + */ + session->save_state (""); + } + } } ARDOUR_UI::~ARDOUR_UI () @@ -277,7 +370,9 @@ ARDOUR_UI::~ARDOUR_UI () delete add_route_dialog; } - AudioSource::stop_peak_thread (); + if (new_session_dialog) { + delete new_session_dialog; + } } gint @@ -315,10 +410,67 @@ ARDOUR_UI::configure_handler (GdkEventConfigure* conf) Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100); have_configure_timeout = true; } - + return FALSE; } +void +ARDOUR_UI::set_transport_controllable_state (const XMLNode& node) +{ + const XMLProperty* prop; + + if ((prop = node.property ("roll")) != 0) { + roll_controllable.set_id (prop->value()); + } + if ((prop = node.property ("stop")) != 0) { + stop_controllable.set_id (prop->value()); + } + if ((prop = node.property ("goto_start")) != 0) { + goto_start_controllable.set_id (prop->value()); + } + if ((prop = node.property ("goto_end")) != 0) { + goto_end_controllable.set_id (prop->value()); + } + if ((prop = node.property ("auto_loop")) != 0) { + auto_loop_controllable.set_id (prop->value()); + } + if ((prop = node.property ("play_selection")) != 0) { + play_selection_controllable.set_id (prop->value()); + } + if ((prop = node.property ("rec")) != 0) { + rec_controllable.set_id (prop->value()); + } + if ((prop = node.property ("shuttle")) != 0) { + shuttle_controllable.set_id (prop->value()); + } +} + +XMLNode& +ARDOUR_UI::get_transport_controllable_state () +{ + XMLNode* node = new XMLNode(X_("TransportControllables")); + char buf[64]; + + roll_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("roll"), buf); + stop_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("stop"), buf); + goto_start_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("goto_start"), buf); + goto_end_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("goto_end"), buf); + auto_loop_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("auto_loop"), buf); + play_selection_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("play_selection"), buf); + rec_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("rec"), buf); + shuttle_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("shuttle"), buf); + + return *node; +} + void ARDOUR_UI::save_ardour_state () { @@ -332,7 +484,14 @@ ARDOUR_UI::save_ardour_state () XMLNode* node = new XMLNode (keyboard->get_state()); Config->add_extra_xml (*node); + Config->add_extra_xml (get_transport_controllable_state()); + if (new_session_dialog) { + if (new_session_dialog->engine_control.was_used()) { + Config->add_extra_xml (new_session_dialog->engine_control.get_state()); + } + } Config->save_state(); + ui_config->save_state (); XMLNode enode(static_cast(editor)->get_state()); XMLNode mnode(mixer->get_state()); @@ -348,12 +507,222 @@ ARDOUR_UI::save_ardour_state () save_keybindings (); } +gint +ARDOUR_UI::autosave_session () +{ + if (!Config->get_periodic_safety_backups()) + return 1; + + if (session) { + session->maybe_write_autosave(); + } + + return 1; +} + +void +ARDOUR_UI::update_autosave () +{ + ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave)); + + if (session->dirty()) { + if (_autosave_connection.connected()) { + _autosave_connection.disconnect(); + } + + _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session), + Config->get_periodic_safety_backup_interval() * 1000); + + } else { + if (_autosave_connection.connected()) { + _autosave_connection.disconnect(); + } + } +} + +void +ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel) +{ + string title; + if (we_set_params) { + title = _("Ardour could not start JACK"); + } else { + title = _("Ardour could not connect to JACK."); + } + + MessageDialog win (title, + false, + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_NONE); + + if (we_set_params) { + win.set_secondary_text(_("There are several possible reasons:\n\ +\n\ +1) You requested audio parameters that are not supported..\n\ +2) JACK is running as another user.\n\ +\n\ +Please consider the possibilities, and perhaps try different parameters.")); + } else { + win.set_secondary_text(_("There are several possible reasons:\n\ +\n\ +1) JACK is not running.\n\ +2) JACK is running as another user, perhaps root.\n\ +3) There is already another client called \"ardour\".\n\ +\n\ +Please consider the possibilities, and perhaps (re)start JACK.")); + } + + if (toplevel) { + win.set_transient_for (*toplevel); + } + + if (we_set_params) { + win.add_button (Stock::OK, RESPONSE_CLOSE); + } else { + win.add_button (Stock::QUIT, RESPONSE_CLOSE); + } + + win.set_default_response (RESPONSE_CLOSE); + + win.show_all (); + win.set_position (Gtk::WIN_POS_CENTER); + + if (!ARDOUR_COMMAND_LINE::no_splash) { + hide_splash (); + } + + /* we just don't care about the result, but we want to block */ + + win.run (); +} + void ARDOUR_UI::startup () { - // relax + string name, path; + bool isnew; + + new_session_dialog = new NewSessionDialog(); + + /* If no session name is given: we're not loading a session yet, nor creating a new one */ + + if (ARDOUR_COMMAND_LINE::session_name.length()) { + + /* Load session or start the new session dialog */ + + if (Session::find_session (ARDOUR_COMMAND_LINE::session_name, path, name, isnew)) { + + MessageDialog msg (string_compose(_("Could not find command line session \"%1\""), + ARDOUR_COMMAND_LINE::session_name), + true, + Gtk::MESSAGE_ERROR, + Gtk::BUTTONS_OK); + + msg.set_position (Gtk::WIN_POS_MOUSE); + msg.present (); + msg.run (); + + exit (1); + } + + if (!ARDOUR_COMMAND_LINE::new_session) { + + /* Supposed to be loading an existing session, but the session doesn't exist */ + + if (isnew) { + MessageDialog msg (string_compose (_("\n\nNo session named \"%1\" exists.\n" + "To create it from the command line, start ardour as:\n ardour --new %1"), path), + true, + Gtk::MESSAGE_ERROR, + Gtk::BUTTONS_OK); + + msg.set_position (Gtk::WIN_POS_MOUSE); + msg.present (); + msg.run (); + + exit (1); + } + } + } + + hide_splash (); + + bool have_backend = EngineControl::engine_running(); + XMLNode* audio_setup = Config->extra_xml ("AudioSetup"); + + if (audio_setup) { + new_session_dialog->engine_control.set_state (*audio_setup); + } + + if (!get_session_parameters (ARDOUR_COMMAND_LINE::session_name, have_backend, ARDOUR_COMMAND_LINE::new_session)) { + return; + } + + show (); +} + +void +ARDOUR_UI::no_memory_warning () +{ + XMLNode node (X_("no-memory-warning")); + Config->add_instant_xml (node, get_user_ardour_path()); +} + +void +ARDOUR_UI::check_memory_locking () +{ +#ifdef __APPLE__ + /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */ + return; +#else // !__APPLE__ + + XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path()); + + if (engine->is_realtime() && memory_warning_node == 0) { + + struct rlimit limits; + int64_t ram; + long pages, page_size; + + if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) { + ram = 0; + } else { + ram = (int64_t) pages * (int64_t) page_size; + } + + if (getrlimit (RLIMIT_MEMLOCK, &limits)) { + return; + } + + if (limits.rlim_cur != RLIM_INFINITY) { + + if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) { + + + MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. " + "This might cause Ardour to run out of memory before your system " + "runs out of memory. \n\n" + "You can view the memory limit with 'ulimit -l', " + "and it is normally controlled by /etc/security/limits.conf")); + + VBox* vbox = msg.get_vbox(); + HBox hbox; + CheckButton cb (_("Do not show this window again")); + + cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning)); + + hbox.pack_start (cb, true, false); + vbox->pack_start (hbox); + hbox.show_all (); + + msg.run (); + } + } + } +#endif // !__APPLE__ } + void ARDOUR_UI::finish() { @@ -384,7 +753,7 @@ If you still wish to quit, please use the\n\n\ session->set_deletion_in_progress (); } engine->stop (true); - Config->save_state(); + save_ardour_state (); quit (); } @@ -459,7 +828,7 @@ ARDOUR_UI::ask_about_saving_session (const string & what) return -1; } -gint +int ARDOUR_UI::every_second () { update_cpu_load (); @@ -479,6 +848,8 @@ ARDOUR_UI::every_point_one_seconds () gint ARDOUR_UI::every_point_zero_one_seconds () { + // august 2007: actual update frequency: 40Hz, not 100Hz + SuperRapidScreenUpdate(); /* EMIT_SIGNAL */ return TRUE; } @@ -499,11 +870,11 @@ ARDOUR_UI::update_sample_rate (nframes_t ignored) nframes_t rate = engine->frame_rate(); if (fmod (rate, 1000.0) != 0.0) { - snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f msecs"), + snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"), (float) rate/1000.0f, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } else { - snprintf (buf, sizeof (buf), _("%u kHz / %4.1f msecs"), + snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"), rate/1000, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } @@ -516,7 +887,7 @@ void ARDOUR_UI::update_cpu_load () { char buf[32]; - snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), engine->get_cpu_load()); + snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load()); cpu_load_label.set_text (buf); } @@ -595,40 +966,6 @@ ARDOUR_UI::update_wall_clock () return TRUE; } -void -ARDOUR_UI::control_methods_adjusted () - -{ - int which_method; - - which_method = (int) online_control_button->adjustment.get_value(); - switch (which_method) { - case 0: - allow_mmc_and_local (); - break; - case 1: - allow_mmc_only (); - break; - case 2: - allow_local_only (); - break; - default: - fatal << _("programming error: impossible control method") << endmsg; - } -} - - -void -ARDOUR_UI::mmc_device_id_adjusted () - -{ -#if 0 - if (mmc) { - int dev_id = (int) mmc_id_button->adjustment.get_value(); - mmc->set_device_id (dev_id); - } -#endif -} gint ARDOUR_UI::session_menu (GdkEventButton *ev) @@ -805,9 +1142,29 @@ ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info) return S_ISREG (statbuf.st_mode); } +bool +ARDOUR_UI::check_audioengine () +{ + if (engine) { + if (!engine->connected()) { + MessageDialog msg (_("Ardour is not connected to JACK\n" + "You cannot open or close sessions in this condition")); + msg.run (); + return false; + } + return true; + } else { + return false; + } +} + void ARDOUR_UI::open_session () { + if (!check_audioengine()) { + return; + } + /* popup selector window */ if (open_session_selector == 0) { @@ -817,6 +1174,7 @@ ARDOUR_UI::open_session () open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN); open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT); + open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT); FileFilter session_filter; session_filter.add_pattern ("*.ardour"); @@ -875,7 +1233,8 @@ ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t if (how_many == 1) { error << _("could not create a new audio track") << endmsg; } else { - error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg; + error << string_compose (_("could only create %1 of %2 new audio %3"), + tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg; } } @@ -906,6 +1265,7 @@ ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t } catch (...) { + cerr << "About to complain about JACK\n"; MessageDialog msg (*editor, _("There are insufficient JACK ports available\n\ to create a new track or bus.\n\ @@ -946,7 +1306,7 @@ ARDOUR_UI::transport_goto_start () */ if (editor) { - editor->reposition_x_origin (session->current_start_frame()); + editor->reset_x_origin (session->current_start_frame()); } } } @@ -963,7 +1323,7 @@ ARDOUR_UI::transport_goto_zero () */ if (editor) { - editor->reposition_x_origin (0); + editor->reset_x_origin (0); } } } @@ -980,7 +1340,7 @@ ARDOUR_UI::transport_goto_end () */ if (editor) { - editor->reposition_x_origin (frame); + editor->reset_x_origin (frame); } } } @@ -1021,7 +1381,7 @@ ARDOUR_UI::remove_last_capture() } void -ARDOUR_UI::transport_record () +ARDOUR_UI::transport_record (bool roll) { if (session) { switch (session->record_status()) { @@ -1032,10 +1392,20 @@ ARDOUR_UI::transport_record () return; } session->maybe_enable_record (); + if (roll) { + transport_roll (); + } break; case Session::Recording: + if (roll) { + session->request_stop(); + } else { + session->disable_record (false, true); + } + break; + case Session::Enabled: - session->disable_record (true); + session->disable_record (false, true); } } } @@ -1053,11 +1423,11 @@ ARDOUR_UI::transport_roll () if (session->get_play_loop()) { session->request_play_loop (false); - auto_loop_button.set_active (false); - roll_button.set_active (true); + auto_loop_button.set_visual_state (1); + roll_button.set_visual_state (1); } else if (session->get_play_range ()) { session->request_play_range (false); - play_selection_button.set_active (false); + play_selection_button.set_visual_state (0); } else if (rolling) { session->request_locate (session->last_transport_start(), true); } @@ -1195,24 +1565,6 @@ ARDOUR_UI::map_transport_state () } } -void -ARDOUR_UI::allow_local_only () -{ - -} - -void -ARDOUR_UI::allow_mmc_only () -{ - -} - -void -ARDOUR_UI::allow_mmc_and_local () -{ - -} - void ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg) { @@ -1234,17 +1586,60 @@ ARDOUR_UI::engine_running () ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running)); ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true); ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false); -} -void -ARDOUR_UI::engine_halted () -{ - ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted)); + Glib::RefPtr action; + char* action_name = 0; - ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); - ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); - - update_sample_rate (0); + switch (engine->frames_per_cycle()) { + case 32: + action_name = X_("JACKLatency32"); + break; + case 64: + action_name = X_("JACKLatency64"); + break; + case 128: + action_name = X_("JACKLatency128"); + break; + case 512: + action_name = X_("JACKLatency512"); + break; + case 1024: + action_name = X_("JACKLatency1024"); + break; + case 2048: + action_name = X_("JACKLatency2048"); + break; + case 4096: + action_name = X_("JACKLatency4096"); + break; + case 8192: + action_name = X_("JACKLatency8192"); + break; + default: + /* XXX can we do anything useful ? */ + break; + } + + if (action_name) { + + action = ActionManager::get_action (X_("JACK"), action_name); + + if (action) { + Glib::RefPtr ract = Glib::RefPtr::cast_dynamic (action); + ract->set_active (); + } + } +} + +void +ARDOUR_UI::engine_halted () +{ + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted)); + + ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); + + update_sample_rate (0); MessageDialog msg (*editor, _("\ @@ -1262,14 +1657,6 @@ ARDOUR_UI::do_engine_start () engine->start(); } - catch (AudioEngine::PortRegistrationFailure& err) { - engine->stop (); - error << _("Unable to create all required ports") - << endmsg; - unload_session (); - return -1; - } - catch (...) { engine->stop (); error << _("Unable to start the session running") @@ -1281,26 +1668,17 @@ ARDOUR_UI::do_engine_start () return 0; } -gint -ARDOUR_UI::start_engine () +void +ARDOUR_UI::setup_theme () { - if (do_engine_start () == 0) { - if (session && _session_is_new) { - /* we need to retain initial visual - settings for a new session - */ - session->save_state (""); - } - } - - return FALSE; + theme_manager->setup_theme(); } void ARDOUR_UI::update_clocks () { if (!editor || !editor->dragging_playhead()) { - Clock (session->audible_frame()); /* EMIT_SIGNAL */ + Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */ } } @@ -1339,7 +1717,7 @@ ARDOUR_UI::_blink (void *arg) void ARDOUR_UI::blink () { - Blink (blink_on = !blink_on); /* EMIT_SIGNAL */ + Blink (blink_on = !blink_on); /* EMIT_SIGNAL */ } void @@ -1409,22 +1787,25 @@ ARDOUR_UI::name_io_setup (AudioEngine& engine, } } +/** Ask the user for the name of a new shapshot and then take it. + */ void ARDOUR_UI::snapshot_session () { ArdourPrompter prompter (true); string snapname; - string now; + char timebuf[128]; time_t n; + struct tm local_time; time (&n); - now = ctime (&n); - now = now.substr (20, 4) + now.substr (3, 16) + " (" + now.substr (0, 3) + ")"; + localtime_r (&n, &local_time); + strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time); prompter.set_name ("Prompter"); prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); prompter.set_prompt (_("Name of New Snapshot")); - prompter.set_initial_text (now); + prompter.set_initial_text (timebuf); switch (prompter.run()) { case RESPONSE_ACCEPT: @@ -1482,6 +1863,14 @@ ARDOUR_UI::primary_clock_value_changed () } } +void +ARDOUR_UI::big_clock_value_changed () +{ + if (session) { + session->request_locate (big_clock.current_time ()); + } +} + void ARDOUR_UI::secondary_clock_value_changed () { @@ -1531,18 +1920,18 @@ ARDOUR_UI::transport_rec_enable_blink (bool onoff) switch (session->record_status()) { case Session::Enabled: if (onoff) { - rec_button.set_state (1); + rec_button.set_visual_state (2); } else { - rec_button.set_state (0); + rec_button.set_visual_state (0); } break; case Session::Recording: - rec_button.set_state (2); + rec_button.set_visual_state (1); break; default: - rec_button.set_state (0); + rec_button.set_visual_state (0); break; } } @@ -1555,12 +1944,6 @@ ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window) return TRUE; } -void -ARDOUR_UI::start_keyboard_prefix () -{ - keyboard->start_prefix(); -} - void ARDOUR_UI::save_template () @@ -1568,6 +1951,10 @@ ARDOUR_UI::save_template () ArdourPrompter prompter (true); string name; + if (!check_audioengine()) { + return; + } + prompter.set_name (X_("Prompter")); prompter.set_prompt (_("Name for mix template:")); prompter.set_initial_text(session->name() + _("-template")); @@ -1588,88 +1975,247 @@ ARDOUR_UI::save_template () } void -ARDOUR_UI::new_session (bool startup, std::string predetermined_path) +ARDOUR_UI::fontconfig_dialog () { - string session_name; - string session_path; +#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. + */ + + Glib::ustring 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 (*new_session_dialog, + _("Welcome to Ardour.\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"), + true, + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK); + msg.show_all (); + msg.present (); + msg.run (); + } +#endif +} + +bool +ARDOUR_UI::get_session_parameters (Glib::ustring predetermined_path, bool have_engine, bool should_be_new) +{ + bool existing_session = false; + Glib::ustring session_name; + Glib::ustring session_path; + Glib::ustring template_name; + if (!loading_dialog) { + loading_dialog = new MessageDialog (*new_session_dialog, + "", + false, + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_NONE); + } + + int response = Gtk::RESPONSE_NONE; - new_session_dialog->set_modal(true); - new_session_dialog->set_name (predetermined_path); + if (predetermined_path.length()) { + + /* before we start, lets see if the given path looks like + an existing ardour session. if it does, skip the + tabs that we don't need + */ + + if (Glib::file_test (predetermined_path, Glib::FILE_TEST_IS_DIR)) { + session_path = predetermined_path; + } else { + session_path = Glib::path_get_dirname (string (predetermined_path)); + } + + session_name = basename_nosuffix (string (predetermined_path)); + + if (session_name.length() == 0 || session_path.length() == 0) { + error << string_compose (_("Ardour cannot understand \"%1\" as a session name"), predetermined_path) << endmsg; + return false; + } + + new_session_dialog->set_session_name (session_name); + new_session_dialog->set_session_folder (session_path); + + cerr << "Set name to " << session_name << " and dir to " << session_path << endl; + + if (Glib::file_test (predetermined_path, Glib::FILE_TEST_IS_DIR)) { + Glib::ustring predicted_session_file; + + predicted_session_file = predetermined_path; + predicted_session_file += '/'; + predicted_session_file += session_name; + predicted_session_file += Session::statefile_suffix(); + + if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) { + existing_session = true; + } + + } else if (Glib::file_test (predetermined_path, Glib::FILE_TEST_EXISTS)) { + + if (predetermined_path.find (Session::statefile_suffix()) == predetermined_path.length() - 7) { + /* existing .ardour file */ + existing_session = true; + } + } + + new_session_dialog->set_modal (true); + } + + if (existing_session && have_engine) { + /* lets just try to load it */ + + loading_dialog->set_message (_("Starting audio engine")); + loading_dialog->show_all (); + flush_pending (); + + if (create_engine ()) { + backend_audio_error (!have_engine, new_session_dialog); + loading_dialog->hide (); + return false; + } + + if (load_session (session_path, session_name) == 0) { + goto done; + } + } + + /* loading failed, or we need the NSD for something */ + + new_session_dialog->set_position (WIN_POS_CENTER); + new_session_dialog->set_current_page (0); + new_session_dialog->set_existing_session (existing_session); new_session_dialog->reset_recent(); - new_session_dialog->show(); do { - response = new_session_dialog->run (); + new_session_dialog->set_have_engine (have_engine); + new_session_dialog->present (); + response = new_session_dialog->run (); + loading_dialog->hide (); _session_is_new = false; + + /* handle possible negative responses */ if (response == Gtk::RESPONSE_CANCEL || response == Gtk::RESPONSE_DELETE_EVENT) { - + if (!session) { quit(); } new_session_dialog->hide (); - return; - + return false; + } else if (response == Gtk::RESPONSE_NONE) { + /* "Clear" was pressed */ + + goto try_again; + } + + fontconfig_dialog(); + + /* if we're here to help set up audio parameters this is where want to do that. + */ + + if (!have_engine) { + if (new_session_dialog->engine_control.setup_engine ()) { + new_session_dialog->hide (); + return false; + } + + loading_dialog->set_message (_("Starting audio engine")); + loading_dialog->show_all (); + flush_pending (); + } - /* Clear was pressed */ - new_session_dialog->reset(); + if (create_engine ()) { + backend_audio_error (!have_engine, new_session_dialog); + loading_dialog->hide (); + flush_pending (); + /* audio setup page */ + new_session_dialog->set_existing_session (false); + new_session_dialog->set_current_page (2); + response = Gtk::RESPONSE_NONE; + goto try_again; + } - } else if (response == Gtk::RESPONSE_YES) { + loading_dialog->hide (); + have_engine = true; + + /* now handle possible affirmative responses */ - /* YES == OPEN, but there's no enum for that */ + if (response == Gtk::RESPONSE_YES) { + + /* YES == OPEN from the session selector */ session_name = new_session_dialog->session_name(); if (session_name.empty()) { response = Gtk::RESPONSE_NONE; - continue; + goto try_again; } if (session_name[0] == '/' || (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') || (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) { - load_session (Glib::path_get_dirname (session_name), session_name); + if (load_session (Glib::path_get_dirname (session_name), session_name)) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } } else { session_path = new_session_dialog->session_folder(); - load_session (session_path, session_name); + if (load_session (session_path, session_name)) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } } } else if (response == Gtk::RESPONSE_OK) { + /* OK == OPEN button */ + session_name = new_session_dialog->session_name(); - - if (new_session_dialog->get_current_page() == 1) { - - /* XXX this is a bit of a hack.. - i really want the new sesion dialog to return RESPONSE_YES - if we're on page 1 (the load page) - Unfortunately i can't see how atm.. - */ - - if (session_name.empty()) { - response = Gtk::RESPONSE_NONE; - continue; - } + + if (session_name.empty()) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } + + cerr << "nsd now on page " << new_session_dialog->get_current_page() << endl; + switch (new_session_dialog->get_current_page()) { + case 1: /* recent session selector */ + case 2: /* audio engine control */ + if (session_name[0] == '/' || (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') || (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) { - load_session (Glib::path_get_dirname (session_name), session_name); + if (load_session (Glib::path_get_dirname (session_name), session_name)) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } + } else { session_path = new_session_dialog->session_folder(); - load_session (session_path, session_name); + if (load_session (session_path, session_name)) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } } - - } else { + break; - if (session_name.empty()) { - response = Gtk::RESPONSE_NONE; - continue; - } + case 0: /* nominally the "new" session creator, but could be in use for an old session */ + + if (new_session_dialog->get_current_page() == 0 && ARDOUR_COMMAND_LINE::session_name.empty()) { + should_be_new = true; + } + + /* handle what appear to be paths rather than just a name */ if (session_name[0] == '/' || (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') || @@ -1688,8 +2234,17 @@ ARDOUR_UI::new_session (bool startup, std::string predetermined_path) //non-existant path. hopefully this will be fixed at some point. session_path = Glib::build_filename (session_path, session_name); - - if (g_file_test (session_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) { + + if (!should_be_new) { + + if (load_session (session_path, session_name)) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } + + continue; /* leaves while() loop because response != NONE */ + + } else if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) { Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path); @@ -1706,122 +2261,211 @@ ARDOUR_UI::new_session (bool startup, std::string predetermined_path) switch (msg.run()) { case RESPONSE_YES: - load_session (session_path, session_name); + new_session_dialog->hide (); + goto_editor_window (); + flush_pending (); + if (load_session (session_path, session_name)) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } goto done; break; default: response = RESPONSE_NONE; new_session_dialog->reset (); + new_session_dialog->set_existing_session (false); + loading_dialog->hide (); continue; } - } + } _session_is_new = true; - - std::string template_name = new_session_dialog->session_template_name(); if (new_session_dialog->use_session_template()) { - - load_session (session_path, session_name, &template_name); + + template_name = new_session_dialog->session_template_name(); + + new_session_dialog->hide (); + goto_editor_window (); + flush_pending (); + + if (load_session (session_path, session_name, template_name)) { + response = Gtk::RESPONSE_NONE; + goto try_again; + } + } else { - + uint32_t cchns; uint32_t mchns; AutoConnectOption iconnect; AutoConnectOption oconnect; - - if (new_session_dialog->create_control_bus()) { - cchns = (uint32_t) new_session_dialog->control_channel_count(); - } else { + uint32_t nphysin; + uint32_t nphysout; + + if (Profile->get_sae()) { + cchns = 0; - } - - if (new_session_dialog->create_master_bus()) { - mchns = (uint32_t) new_session_dialog->master_channel_count(); - } else { - mchns = 0; - } - - if (new_session_dialog->connect_inputs()) { + mchns = 2; iconnect = AutoConnectPhysical; - } else { - iconnect = AutoConnectOption (0); - } - - /// @todo some minor tweaks. - - if (new_session_dialog->connect_outs_to_master()) { oconnect = AutoConnectMaster; - } else if (new_session_dialog->connect_outs_to_physical()) { - oconnect = AutoConnectPhysical; + nphysin = 0; // use all available + nphysout = 0; // use all available + } else { - oconnect = AutoConnectOption (0); - } - - uint32_t nphysin = (uint32_t) new_session_dialog->input_limit_count(); - uint32_t nphysout = (uint32_t) new_session_dialog->output_limit_count(); - - build_session (session_path, - session_name, - cchns, - mchns, - iconnect, - oconnect, - nphysin, - nphysout, - engine->frame_rate() * 60 * 5); + + /* get settings from advanced section of NSD */ + + if (new_session_dialog->create_control_bus()) { + cchns = (uint32_t) new_session_dialog->control_channel_count(); + } else { + cchns = 0; + } + + if (new_session_dialog->create_master_bus()) { + mchns = (uint32_t) new_session_dialog->master_channel_count(); + } else { + mchns = 0; + } + + if (new_session_dialog->connect_inputs()) { + iconnect = AutoConnectPhysical; + } else { + iconnect = AutoConnectOption (0); + } + + /// @todo some minor tweaks. + + if (new_session_dialog->connect_outs_to_master()) { + oconnect = AutoConnectMaster; + } else if (new_session_dialog->connect_outs_to_physical()) { + oconnect = AutoConnectPhysical; + } else { + oconnect = AutoConnectOption (0); + } + + nphysin = (uint32_t) new_session_dialog->input_limit_count(); + nphysout = (uint32_t) new_session_dialog->output_limit_count(); + } + + if (build_session (session_path, + session_name, + cchns, + mchns, + iconnect, + oconnect, + nphysin, + nphysout, + engine->frame_rate() * 60 * 5)) { + + response = Gtk::RESPONSE_NONE; + goto try_again; + } + + new_session_dialog->hide (); + goto_editor_window (); + flush_pending (); } + break; + + default: + break; } } + + try_again: + if (response == Gtk::RESPONSE_NONE) { + loading_dialog->hide (); + new_session_dialog->set_existing_session (false); + new_session_dialog->reset (); + } } while (response == Gtk::RESPONSE_NONE); done: show(); - new_session_dialog->get_window()->set_cursor(); + loading_dialog->hide (); new_session_dialog->hide(); + return true; } void -ARDOUR_UI::close_session() +ARDOUR_UI::close_session () { - unload_session(); - new_session (); + if (!check_audioengine()) { + return; + } + + unload_session (true); + + get_session_parameters ("", true, false); } int -ARDOUR_UI::load_session (const string & path, const string & snap_name, string* mix_template) +ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template) { Session *new_session; - int x; + int unload_status; + int retval = -1; + session_loaded = false; - x = unload_session (); - if (x < 0) { + if (!check_audioengine()) { return -1; - } else if (x > 0) { - return 0; + } + + unload_status = unload_session (); + + if (unload_status < 0) { + goto out; + } else if (unload_status > 0) { + retval = 0; + goto out; } /* if it already exists, we must have write access */ - if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) { - MessageDialog msg (*editor, _("\ -You do not have write access to this session.\n\ -This prevents the session from being loaded.")); + if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) { + MessageDialog msg (*editor, _("You do not have write access to this session.\n" + "This prevents the session from being loaded.")); msg.run (); - return -1; + goto out; + } + + if (loading_dialog) { + loading_dialog->set_markup (_("Please wait while Ardour loads your session")); + flush_pending (); } + disable_screen_updates (); + try { new_session = new Session (*engine, path, snap_name, mix_template); } catch (...) { + MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name), + true, + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK_CANCEL); + + msg.set_title (_("Loading Error")); + msg.set_secondary_text (_("Click the OK button to try again.")); + msg.set_position (Gtk::WIN_POS_CENTER); + msg.present (); - error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg; - return -1; + int response = msg.run (); + + msg.hide (); + + switch (response) { + case RESPONSE_CANCEL: + exit (1); + default: + break; + } + goto out; } connect_to_session (new_session); @@ -1836,11 +2480,16 @@ This prevents the session from being loaded.")); session->set_clean (); } - return 0; + enable_screen_updates (); + flush_pending (); + retval = 0; + + out: + return retval; } int -ARDOUR_UI::build_session (const string & path, const string & snap_name, +ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, uint32_t control_channels, uint32_t master_channels, AutoConnectOption input_connect, @@ -1852,8 +2501,14 @@ ARDOUR_UI::build_session (const string & path, const string & snap_name, Session *new_session; int x; + if (!check_audioengine()) { + return -1; + } + session_loaded = false; + x = unload_session (); + if (x < 0) { return -1; } else if (x > 0) { @@ -1869,7 +2524,8 @@ ARDOUR_UI::build_session (const string & path, const string & snap_name, catch (...) { - error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg; + MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path)); + msg.run (); return -1; } @@ -2055,9 +2711,17 @@ After cleanup, unused audio files will be moved to a \ editor->prepare_for_cleanup (); + /* do not allow flush until a session is reloaded */ + + Glib::RefPtr act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket")); + if (act) { + act->set_sensitive (false); + } + if (session->cleanup_sources (rep)) { return; } + checker.hide(); display_cleanup_results (rep, _("cleaned files"), @@ -2069,6 +2733,9 @@ Flushing the wastebasket will \n\ release an additional\n\ %4 %5bytes of disk space.\n" )); + + + } void @@ -2093,7 +2760,7 @@ releasing %4 %5bytes of disk space")); } void -ARDOUR_UI::add_route () +ARDOUR_UI::add_route (Gtk::Window* float_window) { int count; @@ -2103,7 +2770,9 @@ ARDOUR_UI::add_route () if (add_route_dialog == 0) { add_route_dialog = new AddRouteDialog; - editor->ensure_float (*add_route_dialog); + if (float_window) { + add_route_dialog->set_transient_for (*float_window); + } } if (add_route_dialog->is_visible()) { @@ -2210,18 +2879,18 @@ ARDOUR_UI::halt_on_xrun_message () void ARDOUR_UI::disk_overrun_handler () { - ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler)); - if (!have_disk_overrun_displayed) { - have_disk_overrun_displayed = true; - MessageDialog msg (*editor, X_("diskrate dialog"), _("\ + if (!have_disk_speed_dialog_displayed) { + have_disk_speed_dialog_displayed = true; + MessageDialog* msg = new MessageDialog (*editor, _("\ The disk system on your computer\n\ was not able to keep up with Ardour.\n\ \n\ Specifically, it failed to write data to disk\n\ quickly enough to keep up with recording.\n")); - msg.run (); - have_disk_overrun_displayed = false; + msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg)); + msg->show_all (); } } @@ -2230,29 +2899,24 @@ ARDOUR_UI::disk_underrun_handler () { ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); - if (!have_disk_underrun_displayed) { - have_disk_underrun_displayed = true; - MessageDialog msg (*editor, - (_("The disk system on your computer\n\ + if (!have_disk_speed_dialog_displayed) { + have_disk_speed_dialog_displayed = true; + MessageDialog* msg = new MessageDialog (*editor, + _("The disk system on your computer\n\ was not able to keep up with Ardour.\n\ \n\ Specifically, it failed to read data from disk\n\ -quickly enough to keep up with playback.\n"))); - msg.run (); - have_disk_underrun_displayed = false; +quickly enough to keep up with playback.\n")); + msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg)); + msg->show_all (); } } void -ARDOUR_UI::disk_underrun_message_gone () -{ - have_disk_underrun_displayed = false; -} - -void -ARDOUR_UI::disk_overrun_message_gone () +ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg) { - have_disk_underrun_displayed = false; + have_disk_speed_dialog_displayed = false; + delete msg; } int @@ -2309,13 +2973,6 @@ ARDOUR_UI::reconnect_to_jack () } } -void -ARDOUR_UI::set_jack_buffer_size (nframes_t nframes) -{ - engine->request_buffer_size (nframes); - update_sample_rate (0); -} - int ARDOUR_UI::cmdline_new_session (string path) { @@ -2330,7 +2987,7 @@ ARDOUR_UI::cmdline_new_session (string path) path = str; } - new_session (false, path); + get_session_parameters (path, false, true); _will_create_new_session_automatically = false; /* done it */ return FALSE; /* don't call it again */ @@ -2348,6 +3005,9 @@ ARDOUR_UI::use_config () case FormatInt24: act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit")); break; + case FormatInt16: + act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit")); + break; } if (act) { @@ -2383,13 +3043,27 @@ ARDOUR_UI::use_config () Glib::RefPtr ract = Glib::RefPtr::cast_dynamic(act); ract->set_active (); } + + XMLNode* node = Config->extra_xml (X_("TransportControllables")); + if (node) { + set_transport_controllable_state (*node); + } } void ARDOUR_UI::update_transport_clocks (nframes_t pos) { - primary_clock.set (pos); - secondary_clock.set (pos); + if (Config->get_primary_clock_delta_edit_cursor()) { + primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1); + } else { + 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); + } else { + secondary_clock.set (pos); + } if (big_clock_window) { big_clock.set (pos); @@ -2399,6 +3073,8 @@ ARDOUR_UI::update_transport_clocks (nframes_t pos) void ARDOUR_UI::record_state_changed () { + ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed)); + if (!session || !big_clock_window) { /* why bother - the clock isn't visible */ return; @@ -2406,10 +3082,10 @@ ARDOUR_UI::record_state_changed () switch (session->record_status()) { case Session::Recording: - big_clock.set_name ("BigClockRecording"); + big_clock.set_widget_name ("BigClockRecording"); break; default: - big_clock.set_name ("BigClockNonRecording"); + big_clock.set_widget_name ("BigClockNonRecording"); break; } } @@ -2423,5 +3099,151 @@ ARDOUR_UI::set_keybindings_path (string path) void ARDOUR_UI::save_keybindings () { - AccelMap::save (keybindings_path); + if (can_save_keybindings) { + AccelMap::save (user_keybindings_path); + } +} + +bool +ARDOUR_UI::first_idle () +{ + if (session) { + session->allow_auto_play (true); + } + can_save_keybindings = true; + return false; +} + +void +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())); + } + + 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) +{ + +} + +void +ARDOUR_UI::TransportControllable::set_value (float val) +{ + if (type == ShuttleControl) { + double fract; + + if (val == 0.5f) { + fract = 0.0; + } else { + if (val < 0.5f) { + fract = -((0.5f - val)/0.5f); + } else { + fract = ((val - 0.5f)/0.5f); + } + } + + ui.set_shuttle_fract (fract); + return; + } + + if (val < 0.5f) { + /* do nothing: these are radio-style actions */ + return; + } + + char *action = 0; + + switch (type) { + case Roll: + action = X_("Roll"); + break; + case Stop: + action = X_("Stop"); + break; + case GotoStart: + action = X_("Goto Start"); + break; + case GotoEnd: + action = X_("Goto End"); + break; + case AutoLoop: + action = X_("Loop"); + break; + case PlaySelection: + action = X_("Play Selection"); + 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 (); + } } + +float +ARDOUR_UI::TransportControllable::get_value (void) const +{ + float val = 0.0f; + + switch (type) { + case Roll: + break; + case Stop: + break; + case GotoStart: + break; + case GotoEnd: + break; + case AutoLoop: + break; + case PlaySelection: + break; + case RecordEnable: + break; + case ShuttleControl: + break; + default: + break; + } + + return val; +} + +void +ARDOUR_UI::TransportControllable::set_id (const string& str) +{ + _id = str; +} + +void +ARDOUR_UI::setup_profile () +{ + if (gdk_screen_width() < 1200) { + Profile->set_small_screen (); + } + + if (getenv ("ARDOUR_SAE")) { + Profile->set_sae (); + Profile->set_single_package (); + } +} +