/*
- Copyright (C) 1999-2007 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
*/
-#define __STDC_FORMAT_MACROS 1
+#ifdef WAF_BUILD
+#include "gtk2ardour-config.h"
+#endif
+
#include <stdint.h>
#include <algorithm>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
+#include <time.h>
#include <cerrno>
#include <fstream>
#include <gtkmm/messagedialog.h>
#include <gtkmm/accelmap.h>
-#include <pbd/error.h>
-#include <pbd/compose.h>
-#include <pbd/pathscanner.h>
-#include <pbd/failed_constructor.h>
-#include <pbd/enumwriter.h>
-#include <pbd/memento_command.h>
-
-#include <gtkmm2ext/gtk_ui.h>
-#include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/click_box.h>
-#include <gtkmm2ext/fastmeter.h>
-#include <gtkmm2ext/stop_signal.h>
-#include <gtkmm2ext/popup.h>
-#include <gtkmm2ext/window_title.h>
-
-#include <midi++/port.h>
-#include <midi++/mmc.h>
-
-#include <ardour/ardour.h>
-#include <ardour/profile.h>
-#include <ardour/session_directory.h>
-#include <ardour/session_route.h>
-#include <ardour/session_utils.h>
-#include <ardour/port.h>
-#include <ardour/audioengine.h>
-#include <ardour/playlist.h>
-#include <ardour/utils.h>
-#include <ardour/audio_diskstream.h>
-#include <ardour/audiofilesource.h>
-#include <ardour/recent_sessions.h>
-#include <ardour/port.h>
-#include <ardour/audio_track.h>
-#include <ardour/midi_track.h>
+#include "pbd/error.h"
+#include "pbd/basename.h"
+#include "pbd/compose.h"
+#include "pbd/failed_constructor.h"
+#include "pbd/enumwriter.h"
+#include "pbd/memento_command.h"
+#include "pbd/openuri.h"
+#include "pbd/file_utils.h"
+
+#include "gtkmm2ext/application.h"
+#include "gtkmm2ext/bindings.h"
+#include "gtkmm2ext/gtk_ui.h"
+#include "gtkmm2ext/utils.h"
+#include "gtkmm2ext/click_box.h"
+#include "gtkmm2ext/fastmeter.h"
+#include "gtkmm2ext/popup.h"
+#include "gtkmm2ext/window_title.h"
+
+#include "midi++/manager.h"
+
+#include "ardour/ardour.h"
+#include "ardour/callback.h"
+#include "ardour/profile.h"
+#include "ardour/plugin_manager.h"
+#include "ardour/session_directory.h"
+#include "ardour/session_route.h"
+#include "ardour/session_state_utils.h"
+#include "ardour/session_utils.h"
+#include "ardour/port.h"
+#include "ardour/audioengine.h"
+#include "ardour/playlist.h"
+#include "ardour/utils.h"
+#include "ardour/audio_diskstream.h"
+#include "ardour/audiofilesource.h"
+#include "ardour/recent_sessions.h"
+#include "ardour/port.h"
+#include "ardour/audio_track.h"
+#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;
+#include "about.h"
#include "actions.h"
+#include "add_route_dialog.h"
+#include "ambiguous_file_dialog.h"
#include "ardour_ui.h"
-#include "public_editor.h"
#include "audio_clock.h"
+#include "bundle_manager.h"
+#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"
+#include "missing_file_dialog.h"
+#include "missing_plugin_dialog.h"
#include "mixer_ui.h"
-#include "prompter.h"
#include "opts.h"
-#include "add_route_dialog.h"
-#include "new_session_dialog.h"
-#include "about.h"
-#include "utils.h"
-#include "gui_thread.h"
+#include "processor_box.h"
+#include "prompter.h"
+#include "public_editor.h"
+#include "route_time_axis.h"
+#include "session_metadata_dialog.h"
+#include "shuttle_control.h"
+#include "speaker_dialog.h"
+#include "splash.h"
+#include "startup.h"
#include "theme_manager.h"
+#include "time_axis_view_item.h"
+#include "utils.h"
+#include "window_proxy.h"
#include "i18n.h"
using namespace PBD;
using namespace Gtkmm2ext;
using namespace Gtk;
-using namespace sigc;
ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
+UIConfiguration *ARDOUR_UI::ui_config = 0;
sigc::signal<void,bool> ARDOUR_UI::Blink;
sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
-sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
-sigc::signal<int,string> ThemeChanged;
+sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
+
+bool could_be_a_valid_path (const string& path);
ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
- : 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),
+ : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
+
+ , gui_object_state (new GUIObjectState)
+ , primary_clock (new AudioClock (X_("primary"), false, X_("transport"), true, true, false, true))
+ , secondary_clock (new AudioClock (X_("secondary"), false, X_("secondary"), true, true, false, true))
- /* adjuster table */
+ /* big clock */
- adjuster_table (3, 3),
+ , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
- /* preroll stuff */
+ /* transport */
- preroll_button (_("pre\nroll")),
- postroll_button (_("post\nroll")),
+ , 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))
- /* big clock */
+ , auto_return_button (ArdourButton::led_default_elements)
+ , auto_play_button (ArdourButton::led_default_elements)
+ , auto_input_button (ArdourButton::led_default_elements)
- big_clock (X_("bigclock"), false, "BigClockNonRecording", false, false, true),
+ , auditioning_alert_button (_("audition"))
+ , solo_alert_button (_("solo"))
+ , feedback_alert_button (_("feedback"))
- /* transport */
+ , error_log_button (_("Errors"))
+
+ , _status_bar_visibility (X_("status-bar"))
+ , _feedback_exists (false)
- 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 (_("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)
{
using namespace Gtk::Menu_Helpers;
Gtkmm2ext::init();
-
+
+
+#ifdef TOP_MENUBAR
+ // _auto_display_errors = false;
+ /*
+ * This was commented out as it wasn't defined
+ * in A3 IIRC. If this is not needed it should
+ * be completely removed.
+ */
+#endif
+
about = 0;
+ splash = 0;
+ _startup = 0;
if (theArdourUI == 0) {
theArdourUI = this;
}
- /* load colors */
-
+ ui_config = new UIConfiguration();
theme_manager = new ThemeManager();
- //std::string color_file = ARDOUR::find_config_file("ardour.colors");
-
- //theme_manager->load (color_file);
+ key_editor = 0;
editor = 0;
mixer = 0;
- session = 0;
+ editor = 0;
+ engine = 0;
_session_is_new = false;
big_clock_window = 0;
+ big_clock_height = 0;
+ big_clock_resize_in_progress = false;
session_selector_window = 0;
last_key_press_time = 0;
- connection_editor = 0;
add_route_dialog = 0;
route_params = 0;
- option_editor = 0;
+ bundle_manager = 0;
+ rc_option_editor = 0;
+ session_option_editor = 0;
location_ui = 0;
open_session_selector = 0;
have_configure_timeout = false;
have_disk_speed_dialog_displayed = false;
session_loaded = false;
- last_speed_displayed = -1.0f;
- keybindings_path = ARDOUR::find_config_file ("ardour.bindings");
- ab_direction = true;
+ ignore_dual_punch = false;
+ original_big_clock_width = -1;
+ original_big_clock_height = -1;
+ original_big_clock_font_size = 0;
+
+ roll_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
+ play_selection_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
+
+ roll_button.set_controllable (roll_controllable);
+ stop_button.set_controllable (stop_controllable);
+ goto_start_button.set_controllable (goto_start_controllable);
+ goto_end_button.set_controllable (goto_end_controllable);
+ auto_loop_button.set_controllable (auto_loop_controllable);
+ play_selection_button.set_controllable (play_selection_controllable);
+ rec_button.set_controllable (rec_controllable);
+
+ roll_button.set_name ("transport button");
+ stop_button.set_name ("transport button");
+ goto_start_button.set_name ("transport button");
+ goto_end_button.set_name ("transport button");
+ auto_loop_button.set_name ("transport button");
+ play_selection_button.set_name ("transport button");
+ rec_button.set_name ("transport recenable button");
+ midi_panic_button.set_name ("transport button");
+
+ 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;
+
+ ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
+ ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
+
+ /* handle dialog requests */
+
+ ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
+
+ /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
+
+ ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
+
+ /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
+
+ 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 ());
+ ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::successful_graph_sort, 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));
+
+ /* and ambiguous files */
+
+ ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
+
+ /* lets get this party started */
+
+ try {
+ if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
+ throw failed_constructor ();
+ }
+
+ setup_gtk_ardour_enums ();
+ setup_profile ();
+
+ GainMeter::setup_slider_pix ();
+ RouteTimeAxisView::setup_slider_pix ();
+ ProcessorEntry::setup_slider_pix ();
+ SessionEvent::create_per_thread_pool ("GUI", 512);
+
+ } catch (failed_constructor& err) {
+ error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
+ // pass it on up
+ throw;
+ }
+
+ /* we like keyboards */
+
+ keyboard = new ArdourKeyboard(*this);
+
+ XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
+ if (node) {
+ keyboard->set_state (*node, Stateful::loading_state_version);
+ }
+
+ /* we don't like certain modifiers */
+ Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
+
+ reset_dpi();
+
+ TimeAxisViewItem::set_constant_heights ();
- can_save_keybindings = false;
+ /* The following must happen after ARDOUR::init() so that Config is set up */
- last_configure_time.tv_sec = 0;
- last_configure_time.tv_usec = 0;
+ location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
+ big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
+ speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
- shuttle_grabbed = false;
- shuttle_fract = 0.0;
- shuttle_max_speed = 8.0f;
+ for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
+ _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
+ string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
+ Config->extra_xml (X_("UI")),
+ string_compose ("toggle-%1-connection-manager", (*i).to_string())
+ );
+ }
+
+ setup_clock ();
+
+ SpeakerDialog* s = new SpeakerDialog ();
+ s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/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));
+
+ _process_thread = new ProcessThread ();
+ _process_thread->init ();
+
+ DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
+}
+
+/** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
+bool
+ARDOUR_UI::run_startup (bool should_be_new, string load_template)
+{
+ delete _startup;
+ _startup = new ArdourStartup ();
+
+ XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
+
+ if (audio_setup && _startup->engine_control()) {
+ _startup->engine_control()->set_state (*audio_setup);
+ }
+
+ _startup->set_new_only (should_be_new);
+ if (!load_template.empty()) {
+ _startup->set_load_template( load_template );
+ }
+ _startup->present ();
+
+ main().run();
+
+ _startup->hide ();
+
+ switch (_startup->response()) {
+ case RESPONSE_OK:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int
+ARDOUR_UI::create_engine ()
+{
+ // this gets called every time by new_session()
+
+ if (engine) {
+ return 0;
+ }
+
+ loading_message (_("Starting audio engine"));
+
+ try {
+ engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
- shuttle_style_menu = 0;
- shuttle_unit_menu = 0;
+ } catch (...) {
- gettimeofday (&last_peak_grab, 0);
- gettimeofday (&last_shuttle_request, 0);
+ return -1;
+ }
- ThemeChanged.connect (mem_fun(*this, &ARDOUR_UI::load_rcfile));
+ engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
+ engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
+ engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
- ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
- ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
+ engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
- /* handle pending state with a dialog */
+ ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
- ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
+ post_engine ();
- /* have to wait for AudioEngine and Configuration before proceeding */
+ return 0;
}
void
-ARDOUR_UI::set_engine (AudioEngine& e)
+ARDOUR_UI::post_engine ()
{
- engine = &e;
+ /* Things to be done once we create the AudioEngine
+ */
+
+ ARDOUR::init_post_engine ();
- 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));
+ /* load up the UI manager */
ActionManager::init ();
- new_session_dialog = new NewSessionDialog();
_tooltips.enable();
- keyboard = new Keyboard;
-
if (setup_windows ()) {
throw failed_constructor ();
}
- if (GTK_ARDOUR::show_key_actions) {
+ /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
+ XMLNode* n = Config->extra_xml (X_("UI"));
+ if (n) {
+ _status_bar_visibility.set_state (*n);
+ }
+
+ check_memory_locking();
+
+ /* this is the first point at which all the keybindings are available */
+
+ if (ARDOUR_COMMAND_LINE::show_key_actions) {
vector<string> names;
vector<string> paths;
+ vector<string> tooltips;
vector<string> keys;
vector<AccelKey> bindings;
- ActionManager::get_all_actions (names, paths, keys, bindings);
+ ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
vector<string>::iterator n;
vector<string>::iterator k;
exit (0);
}
- /* start with timecode, metering enabled
- */
-
blink_timeout_tag = -1;
- /* the global configuration object is now valid */
-
- use_config ();
-
/* this being a GUI and all, we want peakfiles */
AudioFileSource::set_build_peakfiles (true);
/* set default clock modes */
- primary_clock.set_mode (AudioClock::SMPTE);
- secondary_clock.set_mode (AudioClock::BBT);
+ if (Profile->get_sae()) {
+ 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);
+ }
/* start the time-of-day-clock */
-
+
+#ifndef GTKOSX
+ /* OS X provides a nearly-always visible wallclock, so don't be stupid */
update_wall_clock ();
- Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
+ Glib::signal_timeout().connect (sigc::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));
-}
-
-ARDOUR_UI::~ARDOUR_UI ()
-{
- save_ardour_state ();
+ Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
+ boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
+ Config->map_parameters (pc);
- if (keyboard) {
- delete keyboard;
- }
+ /* now start and maybe save state */
- if (editor) {
- delete editor;
+ if (do_engine_start () == 0) {
+ if (_session && _session_is_new) {
+ /* we need to retain initial visual
+ settings for a new session
+ */
+ _session->save_state ("");
+ }
}
+}
- if (mixer) {
- delete mixer;
- }
+ARDOUR_UI::~ARDOUR_UI ()
+{
+ delete keyboard;
+ delete editor;
+ delete mixer;
+ delete add_route_dialog;
+}
- if (add_route_dialog) {
- delete add_route_dialog;
+void
+ARDOUR_UI::pop_back_splash (Gtk::Window& win)
+{
+ if (Splash::instance()) {
+ Splash::instance()->pop_back_for (win);
}
}
gint
ARDOUR_UI::configure_timeout ()
{
- struct timeval now;
- struct timeval diff;
-
- if (last_configure_time.tv_sec == 0 && last_configure_time.tv_usec == 0) {
+ if (last_configure_time == 0) {
/* no configure events yet */
- return TRUE;
+ return true;
}
- gettimeofday (&now, 0);
- timersub (&now, &last_configure_time, &diff);
-
/* force a gap of 0.5 seconds since the last configure event
*/
- if (diff.tv_sec == 0 && diff.tv_usec < 500000) {
- return TRUE;
+ if (get_microseconds() - last_configure_time < 500000) {
+ return true;
} else {
have_configure_timeout = false;
+ cerr << "config event-driven save\n";
save_ardour_state ();
- return FALSE;
+ return false;
}
}
gboolean
-ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
+ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
{
if (have_configure_timeout) {
- gettimeofday (&last_configure_time, 0);
+ last_configure_time = get_microseconds();
} else {
- Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
+ Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
have_configure_timeout = true;
}
-
+
return FALSE;
}
const XMLProperty* prop;
if ((prop = node.property ("roll")) != 0) {
- roll_controllable.set_id (prop->value());
+ roll_controllable->set_id (prop->value());
}
if ((prop = node.property ("stop")) != 0) {
- stop_controllable.set_id (prop->value());
+ 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-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 ("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 ("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 ("play-selection")) != 0) {
+ play_selection_controllable->set_id (prop->value());
}
if ((prop = node.property ("rec")) != 0) {
- rec_controllable.set_id (prop->value());
+ rec_controllable->set_id (prop->value());
}
if ((prop = node.property ("shuttle")) != 0) {
- shuttle_controllable.set_id (prop->value());
+ shuttle_box->controllable()->set_id (prop->value());
}
+
}
XMLNode&
XMLNode* node = new XMLNode(X_("TransportControllables"));
char buf[64];
- roll_controllable.id().print (buf, sizeof (buf));
+ roll_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("roll"), buf);
- stop_controllable.id().print (buf, sizeof (buf));
+ stop_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("stop"), buf);
- goto_start_controllable.id().print (buf, sizeof (buf));
+ goto_start_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("goto_start"), buf);
- goto_end_controllable.id().print (buf, sizeof (buf));
+ goto_end_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("goto_end"), buf);
- auto_loop_controllable.id().print (buf, sizeof (buf));
+ auto_loop_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("auto_loop"), buf);
- play_selection_controllable.id().print (buf, sizeof (buf));
+ play_selection_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("play_selection"), buf);
- rec_controllable.id().print (buf, sizeof (buf));
+ rec_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("rec"), buf);
- shuttle_controllable.id().print (buf, sizeof (buf));
+ shuttle_box->controllable()->id().print (buf, sizeof (buf));
node->add_property (X_("shuttle"), buf);
return *node;
}
-void
-ARDOUR_UI::save_ardour_state ()
-{
- if (!keyboard || !mixer || !editor) {
- return;
- }
-
- /* XXX this is all a bit dubious. add_extra_xml() uses
- a different lifetime model from add_instant_xml().
- */
-
- XMLNode* node = new XMLNode (keyboard->get_state());
- Config->add_extra_xml (*node);
- Config->add_extra_xml (get_transport_controllable_state());
- Config->save_state();
-
- XMLNode enode(static_cast<Stateful*>(editor)->get_state());
- XMLNode mnode(mixer->get_state());
-
- if (session) {
- session->add_instant_xml (enode, session->path());
- session->add_instant_xml (mnode, session->path());
- } else {
- Config->add_instant_xml (enode, get_user_ardour_path());
- Config->add_instant_xml (mnode, get_user_ardour_path());
- }
-
- save_keybindings ();
-}
gint
ARDOUR_UI::autosave_session ()
{
- if (!Config->get_periodic_safety_backups())
+ if (g_main_depth() > 1) {
+ /* inside a recursive main loop,
+ give up because we may not be able to
+ take a lock.
+ */
return 1;
+ }
+
+ if (!Config->get_periodic_safety_backups()) {
+ return 1;
+ }
- if (session) {
- session->maybe_write_autosave();
+ if (_session) {
+ _session->maybe_write_autosave();
}
return 1;
void
ARDOUR_UI::update_autosave ()
{
- ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
- if (session->dirty()) {
+ if (_session && _session->dirty()) {
if (_autosave_connection.connected()) {
_autosave_connection.disconnect();
}
- _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
+ _autosave_connection = Glib::signal_timeout().connect (sigc::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::startup ()
{
- check_memory_locking();
+ Application* app = Application::instance ();
+
+ app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
+ app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
+
+#ifdef PHONE_HOME
+ call_the_mothership (VERSIONSTRING);
+#endif
+
+ app->ready ();
+
+ if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
+ exit (1);
+ }
+
+ use_config ();
+
+ goto_editor_window ();
+
+ /* Add the window proxies here; their addition may cause windows to be opened, and we want them
+ to be opened on top of the editor window that goto_editor_window() just opened.
+ */
+ add_window_proxy (location_ui);
+ add_window_proxy (big_clock_window);
+ 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));
}
void
ARDOUR_UI::no_memory_warning ()
{
XMLNode node (X_("no-memory-warning"));
- Config->add_instant_xml (node, get_user_ardour_path());
+ Config->add_instant_xml (node);
}
void
return;
#else // !__APPLE__
- XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
+ XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
if (engine->is_realtime() && memory_warning_node == 0) {
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"));
-
+ MessageDialog msg (
+ string_compose (
+ _("WARNING: Your system has a limit for maximum amount of locked memory. "
+ "This might cause %1 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"),
+ PROGRAM_NAME).c_str());
+
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));
-
+
+ cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
+
hbox.pack_start (cb, true, false);
vbox->pack_start (hbox);
- hbox.show_all ();
-
+ cb.show();
+ vbox->show();
+ hbox.show ();
+
+ pop_back_splash (msg);
+
editor->ensure_float (msg);
msg.run ();
}
}
+void
+ARDOUR_UI::queue_finish ()
+{
+ Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
+}
+
+bool
+ARDOUR_UI::idle_finish ()
+{
+ finish ();
+ return false; /* do not call again */
+}
+
void
ARDOUR_UI::finish()
{
- if (session && session->dirty()) {
- switch (ask_about_saving_session(_("quit"))) {
- case -1:
- return;
- break;
- case 1:
- /* use the default name */
- if (save_state_canfail ("")) {
- /* failed - don't quit */
- MessageDialog msg (*editor,
- _("\
+ if (_session) {
+ int tries = 0;
+
+ if (_session->transport_rolling() && (++tries < 8)) {
+ _session->request_stop (false, true);
+ usleep (10000);
+ }
+
+ if (_session->dirty()) {
+ vector<string> 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;
+ case 1:
+ /* use the default name */
+ if (save_state_canfail ("")) {
+ /* failed - don't quit */
+ MessageDialog msg (*editor,
+ _("\
Ardour was unable to save your session.\n\n\
If you still wish to quit, please use the\n\n\
\"Just quit\" option."));
- msg.run ();
- return;
+ pop_back_splash(msg);
+ msg.run ();
+ return;
+ }
+ break;
+ case 0:
+ break;
}
- break;
- case 0:
- break;
}
+
+ second_connection.disconnect ();
+ point_one_second_connection.disconnect ();
+ point_oh_five_second_connection.disconnect ();
+ point_zero_one_second_connection.disconnect();
}
- if (session) {
- session->set_deletion_in_progress ();
+ /* Save state before deleting the session, as that causes some
+ windows to be destroyed before their visible state can be
+ saved.
+ */
+ save_ardour_state ();
+
+ if (_session) {
+ // _session->set_deletion_in_progress ();
+ _session->set_clean ();
+ _session->remove_pending_capture_state ();
+ delete _session;
+ _session = 0;
}
+
+ ArdourDialog::close_all_dialogs ();
engine->stop (true);
- Config->save_state();
quit ();
}
int
-ARDOUR_UI::ask_about_saving_session (const string & what)
+ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
{
- ArdourDialog window (_("ardour: save session?"));
+ ArdourDialog window (_("Unsaved Session"));
Gtk::HBox dhbox; // the hbox for the image and text
Gtk::Label prompt_label;
Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
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);
noquit_button.set_name ("EditorGTKButton");
string prompt;
- string type;
- if (session->snap_name() == session->name()) {
- type = _("session");
+ if (_session->snap_name() == _session->name()) {
+ 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"));
prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
- dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
-;
+ dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
dhbox.set_homogeneous (false);
dhbox.pack_start (*dimage, false, false, 5);
dhbox.pack_start (prompt_label, true, false, 5);
window.set_position (Gtk::WIN_POS_MOUSE);
window.set_modal (true);
window.set_resizable (false);
- window.show_all ();
-
- save_the_session = 0;
+ dhbox.show();
+ prompt_label.show();
+ dimage->show();
+ window.show();
window.set_keep_above (true);
window.present ();
return -1;
}
-
+
gint
ARDOUR_UI::every_second ()
{
gint
ARDOUR_UI::every_point_one_seconds ()
{
- update_speed_display ();
+ shuttle_box->update_speed_display ();
RapidScreenUpdate(); /* EMIT_SIGNAL */
return TRUE;
}
gint
ARDOUR_UI::every_point_zero_one_seconds ()
{
+ // august 2007: actual update frequency: 40Hz, not 100Hz
+
SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
return TRUE;
}
void
-ARDOUR_UI::update_sample_rate (nframes_t ignored)
+ARDOUR_UI::update_sample_rate (framecnt_t)
{
- char buf[32];
+ char buf[64];
- ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
if (!engine->connected()) {
} else {
- nframes_t rate = engine->frame_rate();
-
+ 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: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
(float) rate/1000.0f,
(engine->frames_per_cycle() / (float) rate) * 1000.0f);
} else {
- snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
+ snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
rate/1000,
(engine->frames_per_cycle() / (float) rate) * 1000.0f);
}
}
- sample_rate_label.set_text (buf);
-}
-
-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);
-}
-
-void
-ARDOUR_UI::update_buffer_load ()
-{
- char buf[64];
-
- if (session) {
- snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
- session->playback_load(), session->capture_load());
- buffer_load_label.set_text (buf);
- } else {
- buffer_load_label.set_text ("");
- }
-}
-
-void
-ARDOUR_UI::count_recenabled_streams (Route& route)
-{
- Track* track = dynamic_cast<Track*>(&route);
- if (track && track->diskstream()->record_enabled()) {
- rec_enabled_streams += track->n_inputs().n_total();
- }
+ sample_rate_label.set_markup (buf);
}
void
-ARDOUR_UI::update_disk_space()
+ARDOUR_UI::update_format ()
{
- if (session == 0) {
+ if (!_session) {
+ format_label.set_text ("");
return;
}
- nframes_t frames = session->available_capture_duration();
- char buf[64];
+ stringstream s;
+ s << _("File:") << X_(" <span foreground=\"green\">");
- if (frames == max_frames) {
- strcpy (buf, _("Disk: 24hrs+"));
- } else {
- int hrs;
- int mins;
- int secs;
- nframes_t fr = session->frame_rate();
-
+ 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 << X_("</span>");
+
+ format_label.set_markup (s.str ());
+}
+
+void
+ARDOUR_UI::update_cpu_load ()
+{
+ char buf[64];
+
+ /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
+ should also be changed.
+ */
+
+ float const c = engine->get_cpu_load ();
+ snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
+ cpu_load_label.set_markup (buf);
+}
+
+void
+ARDOUR_UI::update_buffer_load ()
+{
+ 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::resize_text_widgets
+ should also be changed.
+ */
+
+ if (_session) {
+ snprintf (
+ buf, sizeof (buf),
+ _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
+ "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
+ playback <= 5 ? X_("red") : X_("green"),
+ playback,
+ capture <= 5 ? X_("red") : X_("green"),
+ capture
+ );
+
+ buffer_load_label.set_markup (buf);
+ } else {
+ buffer_load_label.set_text ("");
+ }
+}
+
+void
+ARDOUR_UI::count_recenabled_streams (Route& route)
+{
+ Track* track = dynamic_cast<Track*>(&route);
+ if (track && track->record_enabled()) {
+ rec_enabled_streams += track->n_inputs().n_total();
+ }
+}
+
+void
+ARDOUR_UI::update_disk_space()
+{
+ if (_session == 0) {
+ return;
+ }
+
+ framecnt_t frames = _session->available_capture_duration();
+ char buf[64];
+ framecnt_t fr = _session->frame_rate();
+
+ if (frames == max_framecnt) {
+ snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
+ } else {
rec_enabled_streams = 0;
- session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
-
+ _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
+
if (rec_enabled_streams) {
frames /= rec_enabled_streams;
}
-
+
+ int hrs;
+ int mins;
+ 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: <span foreground=\"green\">>24 hrs</span>"));
+ } 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: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
+ 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.
+
+ if (frames < fr * 60 * 5) {
+ /* disk_space_box.style ("disk_space_label_empty"); */
+ } else {
+ /* disk_space_box.style ("disk_space_label"); */
+ }
+
+}
gint
ARDOUR_UI::update_wall_clock ()
return TRUE;
}
-gint
-ARDOUR_UI::session_menu (GdkEventButton *ev)
-{
- session_popup_menu->popup (0, 0);
- return TRUE;
-}
-
void
ARDOUR_UI::redisplay_recent_sessions ()
{
- vector<string *> *sessions;
- vector<string *>::iterator i;
+ std::vector<sys::path> session_directories;
RecentSessionsSorter cmp;
-
+
recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
recent_session_model->clear ();
- RecentSessions rs;
+ ARDOUR::RecentSessions rs;
ARDOUR::read_recent_sessions (rs);
if (rs.empty()) {
recent_session_display.set_model (recent_session_model);
return;
}
-
- /* sort them alphabetically */
+ //
+ // sort them alphabetically
sort (rs.begin(), rs.end(), cmp);
- sessions = new vector<string*>;
- for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
- sessions->push_back (new string ((*i).second));
+ for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
+ session_directories.push_back ((*i).second);
}
- for (i = sessions->begin(); i != sessions->end(); ++i) {
+ for (vector<sys::path>::const_iterator i = session_directories.begin();
+ i != session_directories.end(); ++i)
+ {
+ std::vector<sys::path> state_file_paths;
+
+ // now get available states for this session
+
+ get_state_files_in_directory (*i, state_file_paths);
vector<string*>* states;
vector<const gchar*> item;
- string fullpath = *(*i);
-
+ string fullpath = (*i).to_string();
+
/* remove any trailing / */
if (fullpath[fullpath.length()-1] == '/') {
fullpath = fullpath.substr (0, fullpath.length()-1);
}
+ /* check whether session still exists */
+ if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
+ /* session doesn't exist */
+ cerr << "skipping non-existent session " << fullpath << endl;
+ continue;
+ }
+
/* now get available states for this session */
if ((states = Session::possible_states (fullpath)) == 0) {
continue;
}
- TreeModel::Row row = *(recent_session_model->append());
+ std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
+
+ Gtk::TreeModel::Row row = *(recent_session_model->append());
row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
row[recent_session_columns.fullpath] = fullpath;
- if (states->size() > 1) {
+ if (state_file_names.size() > 1) {
- /* add the children */
-
- for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
-
- TreeModel::Row child_row = *(recent_session_model->append (row.children()));
+ // add the children
- child_row[recent_session_columns.visible_name] = **i2;
- child_row[recent_session_columns.fullpath] = fullpath;
+ for (std::vector<std::string>::iterator i2 = state_file_names.begin();
+ i2 != state_file_names.end(); ++i2)
+ {
- delete *i2;
+ Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
+
+ child_row[recent_session_columns.visible_name] = *i2;
+ child_row[recent_session_columns.fullpath] = fullpath;
}
}
-
- delete states;
}
+ recent_session_display.set_tooltip_column(1); // recent_session_columns.fullpath
recent_session_display.set_model (recent_session_model);
- delete sessions;
}
void
ARDOUR_UI::build_session_selector ()
{
- session_selector_window = new ArdourDialog ("session selector");
-
+ session_selector_window = new ArdourDialog (_("Recent Sessions"));
+
Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
-
+
session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
session_selector_window->set_default_response (RESPONSE_ACCEPT);
recent_session_display.set_model (recent_session_model);
recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
recent_session_display.set_headers_visible (false);
- recent_session_display.get_selection()->set_mode (SELECTION_SINGLE);
-
- recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
+ recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
+ recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
scroller->add (recent_session_display);
scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
session_selector_window->set_name ("SessionSelectorWindow");
session_selector_window->set_size_request (200, 400);
session_selector_window->get_vbox()->pack_start (*scroller);
- session_selector_window->show_all_children();
+
+ recent_session_display.show();
+ scroller->show();
+ //session_selector_window->get_vbox()->show();
}
void
-ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
+ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
{
session_selector_window->response (RESPONSE_ACCEPT);
}
void
ARDOUR_UI::open_recent_session ()
{
- /* popup selector window */
+ bool can_return = (_session != 0);
if (session_selector_window == 0) {
build_session_selector ();
redisplay_recent_sessions ();
- ResponseType r = (ResponseType) session_selector_window->run ();
+ while (true) {
- session_selector_window->hide();
+ session_selector_window->set_position (WIN_POS_MOUSE);
- switch (r) {
- case RESPONSE_ACCEPT:
- break;
- default:
- return;
- }
+ ResponseType r = (ResponseType) session_selector_window->run ();
- Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
+ switch (r) {
+ case RESPONSE_ACCEPT:
+ break;
+ default:
+ if (can_return) {
+ session_selector_window->hide();
+ return;
+ } else {
+ exit (1);
+ }
+ }
- if (i == recent_session_model->children().end()) {
- return;
- }
-
- Glib::ustring path = (*i)[recent_session_columns.fullpath];
- Glib::ustring state = (*i)[recent_session_columns.visible_name];
+ if (recent_session_display.get_selection()->count_selected_rows() == 0) {
+ continue;
+ }
- _session_is_new = false;
+ session_selector_window->hide();
- load_session (path, state);
-}
+ Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
-bool
-ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info)
-{
- struct stat statbuf;
+ if (i == recent_session_model->children().end()) {
+ return;
+ }
- if (stat (info.filename.c_str(), &statbuf) != 0) {
- return false;
- }
+ std::string path = (*i)[recent_session_columns.fullpath];
+ std::string state = (*i)[recent_session_columns.visible_name];
- if (!S_ISDIR(statbuf.st_mode)) {
- return false;
- }
+ _session_is_new = false;
- // XXX Portability
-
- string session_file = info.filename;
- session_file += '/';
- session_file += Glib::path_get_basename (info.filename);
- session_file += ".ardour";
-
- if (stat (session_file.c_str(), &statbuf) != 0) {
- return false;
- }
+ if (load_session (path, state) == 0) {
+ break;
+ }
- return S_ISREG (statbuf.st_mode);
+ can_return = false;
+ }
}
bool
{
if (engine) {
if (!engine->connected()) {
- MessageDialog msg (_("Ardour is not connected to JACK\n"
- "You cannot open or close sessions in this condition"));
+ MessageDialog msg (string_compose (
+ _("%1 is not connected to JACK\n"
+ "You cannot open or close sessions in this condition"),
+ PROGRAM_NAME));
+ pop_back_splash (msg);
msg.run ();
return false;
}
{
if (!check_audioengine()) {
return;
-
+
}
/* popup selector window */
/* ardour sessions are folders */
- open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
+ 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);
+
+ if (_session) {
+ string session_parent_dir = Glib::path_get_dirname(_session->path());
+ string::size_type last_dir_sep = session_parent_dir.rfind(G_DIR_SEPARATOR);
+ session_parent_dir = session_parent_dir.substr(0, last_dir_sep);
+ open_session_selector->set_current_folder(session_parent_dir);
+ } else {
+ open_session_selector->set_current_folder(Config->get_default_session_parent_dir());
+ }
+
+ open_session_selector->add_shortcut_folder (Config->get_default_session_parent_dir());
FileFilter session_filter;
session_filter.add_pattern ("*.ardour");
- session_filter.set_name (_("Ardour sessions"));
+ session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
open_session_selector->add_filter (session_filter);
open_session_selector->set_filter (session_filter);
}
void
-ARDOUR_UI::session_add_midi_route (bool disk, uint32_t how_many)
+ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
{
list<boost::shared_ptr<MidiTrack> > tracks;
- if (session == 0) {
+ if (_session == 0) {
warning << _("You cannot add a track without a session already loaded.") << endmsg;
return;
}
- try {
+ try {
if (disk) {
- tracks = session->new_midi_track (ARDOUR::Normal, how_many);
+ tracks = _session->new_midi_track (instrument, ARDOUR::Normal, route_group, how_many, name_template);
if (tracks.size() != how_many) {
if (how_many == 1) {
error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
}
}
+
} /*else {
- if ((route = session->new_midi_route ()) == 0) {
+ if ((route = _session->new_midi_route ()) == 0) {
error << _("could not create new midi bus") << endmsg;
}
}*/
}
catch (...) {
- MessageDialog msg (*editor,
- _("There are insufficient JACK ports available\n\
+ MessageDialog msg (*editor,
+ string_compose (_("There are insufficient JACK ports available\n\
to create a new track or bus.\n\
-You should save Ardour, exit and\n\
-restart JACK with more ports."));
+You should save %1, exit and\n\
+restart JACK with more ports."), PROGRAM_NAME));
msg.run ();
}
}
void
-ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
+ARDOUR_UI::session_add_audio_route (
+ bool track,
+ int32_t input_channels,
+ int32_t output_channels,
+ ARDOUR::TrackMode mode,
+ RouteGroup* route_group,
+ uint32_t how_many,
+ string const & name_template
+ )
{
list<boost::shared_ptr<AudioTrack> > tracks;
- Session::RouteList routes;
+ RouteList routes;
- if (session == 0) {
+ if (_session == 0) {
warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
return;
}
- try {
+ try {
if (track) {
- tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
+ tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
if (tracks.size() != how_many) {
if (how_many == 1) {
error << _("could not create a new audio track") << endmsg;
} else {
- error << string_compose (_("could only create %1 of %2 new audio %3"),
+ error << string_compose (_("could only create %1 of %2 new audio %3"),
tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
}
}
} else {
- routes = session->new_audio_route (input_channels, output_channels, how_many);
+ routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
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;
}
}
}
-
-#if CONTROLOUTS
- if (need_control_room_outs) {
- pan_t pans[2];
-
- pans[0] = 0.5;
- pans[1] = 0.5;
-
- route->set_stereo_control_outs (control_lr_channels);
- route->control_outs()->set_stereo_pan (pans, this);
- }
-#endif /* CONTROLOUTS */
}
catch (...) {
- cerr << "About to complain about JACK\n";
- MessageDialog msg (*editor,
- _("There are insufficient JACK ports available\n\
+ MessageDialog msg (*editor,
+ string_compose (_("There are insufficient JACK ports available\n\
to create a new track or bus.\n\
-You should save Ardour, exit and\n\
-restart JACK with more ports."));
+You should save %1, exit and\n\
+restart JACK with more ports."), PROGRAM_NAME));
+ pop_back_splash (msg);
msg.run ();
}
}
void
-ARDOUR_UI::do_transport_locate (nframes_t new_position)
+ARDOUR_UI::transport_goto_start ()
{
- nframes_t _preroll = 0;
+ if (_session) {
+ _session->goto_start();
- if (session) {
- // XXX CONFIG_CHANGE FIX - requires AnyTime handling
- // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
+ /* force displayed area in editor to start no matter
+ what "follow playhead" setting is.
+ */
- if (new_position > _preroll) {
- new_position -= _preroll;
- } else {
- new_position = 0;
+ if (editor) {
+ editor->center_screen (_session->current_start_frame ());
}
-
- session->request_locate (new_position);
}
}
void
-ARDOUR_UI::transport_goto_start ()
+ARDOUR_UI::transport_goto_zero ()
{
- if (session) {
- session->goto_start();
+ if (_session) {
+ _session->request_locate (0);
-
/* force displayed area in editor to start no matter
what "follow playhead" setting is.
*/
-
+
if (editor) {
- editor->reset_x_origin (session->current_start_frame());
+ editor->reset_x_origin (0);
}
}
}
void
-ARDOUR_UI::transport_goto_zero ()
+ARDOUR_UI::transport_goto_wallclock ()
{
- if (session) {
- session->request_locate (0);
+ if (_session && editor) {
+
+ time_t now;
+ struct tm tmnow;
+ framepos_t frames;
+
+ time (&now);
+ localtime_r (&now, &tmnow);
+
+ frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
+ frames += tmnow.tm_min * (60 * _session->frame_rate());
+ frames += tmnow.tm_sec * _session->frame_rate();
+
+ _session->request_locate (frames, _session->transport_rolling ());
-
/* force displayed area in editor to start no matter
what "follow playhead" setting is.
*/
-
+
if (editor) {
- editor->reset_x_origin (0);
+ editor->center_screen (frames);
}
}
}
void
ARDOUR_UI::transport_goto_end ()
{
- if (session) {
- nframes_t frame = session->current_end_frame();
- session->request_locate (frame);
+ if (_session) {
+ framepos_t const frame = _session->current_end_frame();
+ _session->request_locate (frame);
/* force displayed area in editor to start no matter
what "follow playhead" setting is.
*/
-
+
if (editor) {
- editor->reset_x_origin (frame);
+ editor->center_screen (frame);
}
}
}
void
ARDOUR_UI::transport_stop ()
{
- if (!session) {
+ if (!_session) {
return;
}
- if (session->is_auditioning()) {
- session->cancel_audition ();
+ if (_session->is_auditioning()) {
+ _session->cancel_audition ();
return;
}
-
- if (session->get_play_loop ()) {
- session->request_play_loop (false);
- }
-
- session->request_stop ();
-}
-void
-ARDOUR_UI::transport_stop_and_forget_capture ()
-{
- if (session) {
- session->request_stop (true);
- }
+ _session->request_stop (false, true);
}
void
-ARDOUR_UI::remove_last_capture()
+ARDOUR_UI::transport_record (bool roll)
{
- if (editor) {
- editor->remove_last_capture();
- }
-}
-void
-ARDOUR_UI::transport_record ()
-{
- if (session) {
- switch (session->record_status()) {
+ if (_session) {
+ switch (_session->record_status()) {
case Session::Disabled:
- if (session->ntracks() == 0) {
- MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
+ if (_session->ntracks() == 0) {
+ MessageDialog msg (*editor, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
msg.run ();
return;
}
- session->maybe_enable_record ();
+ _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);
}
}
+ //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
}
void
ARDOUR_UI::transport_roll ()
{
- bool rolling;
+ if (!_session) {
+ return;
+ }
- if (!session) {
+ if (_session->is_auditioning()) {
return;
}
- rolling = session->transport_rolling ();
+#if 0
+ if (_session->config.get_external_sync()) {
+ switch (_session->config.get_sync_source()) {
+ case JACK:
+ break;
+ default:
+ /* transport controlled by the master */
+ return;
+ }
+ }
+#endif
+
+ bool rolling = _session->transport_rolling();
+
+ if (_session->get_play_loop()) {
+ /* XXX it is not possible to just leave seamless loop and keep
+ playing at present (nov 4th 2009)
+ */
+ if (!Config->get_seamless_loop()) {
+ _session->request_play_loop (false, true);
+ }
+ } else if (_session->get_play_range () && !Config->get_always_play_range()) {
+ /* stop playing a range if we currently are */
+ _session->request_play_range (0, true);
+ }
- if (session->get_play_loop()) {
- session->request_play_loop (false);
- 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_visual_state (0);
- } else if (rolling) {
- session->request_locate (session->last_transport_start(), true);
+ if (Config->get_always_play_range()) {
+ _session->request_play_range (&editor->get_selection().time, true);
}
- session->request_transport_speed (1.0f);
+ if (!rolling) {
+ _session->request_transport_speed (1.0f);
+ }
}
void
-ARDOUR_UI::transport_loop()
+ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
{
- if (session) {
- if (session->get_play_loop()) {
- if (session->transport_rolling()) {
- Location * looploc = session->locations()->auto_loop_location();
- if (looploc) {
- session->request_locate (looploc->start(), true);
- }
+
+ if (!_session) {
+ return;
+ }
+
+ if (_session->is_auditioning()) {
+ _session->cancel_audition ();
+ return;
+ }
+
+ if (_session->config.get_external_sync()) {
+ switch (_session->config.get_sync_source()) {
+ case JACK:
+ break;
+ default:
+ /* transport controlled by the master */
+ return;
+ }
+ }
+
+ bool rolling = _session->transport_rolling();
+ bool affect_transport = true;
+
+ if (rolling && 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
+ just keep playing, so stop the transport. the user
+ can restart as they wish.
+ */
+ affect_transport = true;
+ } else {
+ /* disk buffers are normal, so we can keep playing */
+ affect_transport = false;
}
+ _session->request_play_loop (false, true);
+ } else if (_session->get_play_range ()) {
+ affect_transport = false;
+ _session->request_play_range (0, true);
}
- else {
- session->request_play_loop (true);
+ }
+
+ if (affect_transport) {
+ if (rolling) {
+ _session->request_stop (with_abort, true);
+ } else {
+ if (Config->get_always_play_range ()) {
+ _session->request_play_range (&editor->get_selection().time, true);
+ }
+
+ _session->request_transport_speed (1.0f);
}
}
}
void
-ARDOUR_UI::transport_play_selection ()
+ARDOUR_UI::toggle_session_auto_loop ()
{
- if (!session) {
+ Location * looploc = _session->locations()->auto_loop_location();
+
+ if (!_session || !looploc) {
return;
}
- if (!session->get_play_range()) {
- session->request_stop ();
- }
+ if (_session->get_play_loop()) {
- editor->play_selection ();
+ if (_session->transport_rolling()) {
+
+ _session->request_locate (looploc->start(), true);
+ _session->request_play_loop (false);
+
+ } else {
+ _session->request_play_loop (false);
+ }
+ } else {
+ _session->request_play_loop (true);
+ }
+
+ //show the loop markers
+ looploc->set_hidden (false, this);
}
void
-ARDOUR_UI::transport_rewind (int option)
+ARDOUR_UI::transport_play_selection ()
{
- float current_transport_speed;
-
- if (session) {
- current_transport_speed = session->transport_speed();
-
+ if (!_session) {
+ return;
+ }
+
+ editor->play_selection ();
+}
+
+void
+ARDOUR_UI::transport_rewind (int option)
+{
+ float current_transport_speed;
+
+ if (_session) {
+ current_transport_speed = _session->transport_speed();
+
if (current_transport_speed >= 0.0f) {
switch (option) {
case 0:
- session->request_transport_speed (-1.0f);
+ _session->request_transport_speed (-1.0f);
break;
case 1:
- session->request_transport_speed (-4.0f);
+ _session->request_transport_speed (-4.0f);
break;
case -1:
- session->request_transport_speed (-0.5f);
+ _session->request_transport_speed (-0.5f);
break;
}
} else {
/* speed up */
- session->request_transport_speed (current_transport_speed * 1.5f);
+ _session->request_transport_speed (current_transport_speed * 1.5f);
}
}
}
ARDOUR_UI::transport_forward (int option)
{
float current_transport_speed;
-
- if (session) {
- current_transport_speed = session->transport_speed();
-
+
+ if (_session) {
+ current_transport_speed = _session->transport_speed();
+
if (current_transport_speed <= 0.0f) {
switch (option) {
case 0:
- session->request_transport_speed (1.0f);
+ _session->request_transport_speed (1.0f);
break;
case 1:
- session->request_transport_speed (4.0f);
+ _session->request_transport_speed (4.0f);
break;
case -1:
- session->request_transport_speed (0.5f);
+ _session->request_transport_speed (0.5f);
break;
}
} else {
/* speed up */
- session->request_transport_speed (current_transport_speed * 1.5f);
+ _session->request_transport_speed (current_transport_speed * 1.5f);
}
+
}
}
void
-ARDOUR_UI::toggle_record_enable (uint32_t dstream)
+ARDOUR_UI::toggle_record_enable (uint32_t rid)
{
- if (session == 0) {
+ if (_session == 0) {
return;
}
boost::shared_ptr<Route> r;
-
- if ((r = session->route_by_remote_id (dstream)) != 0) {
+
+ if ((r = _session->route_by_remote_id (rid)) != 0) {
Track* t;
if ((t = dynamic_cast<Track*>(r.get())) != 0) {
- t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
+ t->set_record_enabled (!t->record_enabled(), this);
}
}
- if (session == 0) {
+ if (_session == 0) {
return;
}
}
-void
-ARDOUR_UI::queue_transport_change ()
-{
- Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
-}
-
void
ARDOUR_UI::map_transport_state ()
{
- float sp = session->transport_speed();
+ if (!_session) {
+ auto_loop_button.unset_active_state ();
+ play_selection_button.unset_active_state ();
+ roll_button.unset_active_state ();
+ stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ return;
+ }
+
+ shuttle_box->map_transport_state ();
+
+ float sp = _session->transport_speed();
+
+ if (sp != 0.0f) {
+
+ /* we're rolling */
+
+ if (_session->get_play_range()) {
+
+ play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ roll_button.unset_active_state ();
+ auto_loop_button.unset_active_state ();
+
+ } else if (_session->get_play_loop ()) {
+
+ auto_loop_button.set_active (true);
+ play_selection_button.set_active (false);
+ roll_button.set_active (false);
+
+ } else {
+
+ roll_button.set_active (true);
+ play_selection_button.set_active (false);
+ auto_loop_button.set_active (false);
+ }
+
+ if (Config->get_always_play_range()) {
+ /* light up both roll and play-selection if they are joined */
+ roll_button.set_active (true);
+ play_selection_button.set_active (true);
+ }
+
+ stop_button.set_active (false);
- if (sp == 1.0f) {
- transport_rolling ();
- } else if (sp < 0.0f) {
- transport_rewinding ();
- } else if (sp > 0.0f) {
- transport_forwarding ();
} else {
- transport_stopped ();
- }
-}
-void
-ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
-{
- snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
- (int) adj.get_value()].c_str());
+ stop_button.set_active (true);
+ roll_button.set_active (false);
+ play_selection_button.set_active (false);
+ auto_loop_button.set_active (false);
+ update_disk_space ();
+ }
}
void
ARDOUR_UI::engine_stopped ()
{
- ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
}
void
ARDOUR_UI::engine_running ()
{
- ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
Glib::RefPtr<Action> action;
- char* action_name = 0;
+ const char* action_name = 0;
switch (engine->frames_per_cycle()) {
case 32:
if (action_name) {
action = ActionManager::get_action (X_("JACK"), action_name);
-
+
if (action) {
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
ract->set_active ();
}
void
-ARDOUR_UI::engine_halted ()
+ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
{
- ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
+ if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
+ /* we can't rely on the original string continuing to exist when we are called
+ again in the GUI thread, so make a copy and note that we need to
+ free it later.
+ */
+ char *copy = strdup (reason);
+ Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
+ return;
+ }
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
update_sample_rate (0);
- MessageDialog msg (*editor,
- _("\
+ string msgstr;
+
+ /* if the reason is a non-empty string, it means that the backend was shutdown
+ rather than just Ardour.
+ */
+
+ if (strlen (reason)) {
+ msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
+ } else {
+ msgstr = string_compose (_("\
JACK has either been shutdown or it\n\
-disconnected Ardour because Ardour\n\
-was not fast enough. You can save the\n\
-session and/or try to reconnect to JACK ."));
+disconnected %1 because %1\n\
+was not fast enough. Try to restart\n\
+JACK, reconnect and save the session."), PROGRAM_NAME);
+ }
+
+ MessageDialog msg (*editor, msgstr);
+ pop_back_splash (msg);
msg.run ();
+
+ if (free_reason) {
+ free ((char*) reason);
+ }
}
int32_t
ARDOUR_UI::do_engine_start ()
{
- try {
+ try {
engine->start();
}
unload_session ();
return -2;
}
-
- return 0;
-}
-
-void
-ARDOUR_UI::setup_theme ()
-{
- string rcfile;
- char* env;
-
- if ((env = getenv ("ARDOUR2_UI_RC")) != 0 && strlen (env)) {
- rcfile = env;
- } else {
- rcfile = Config->get_ui_rc_file();
- }
-
- rcfile = find_config_file (rcfile);
-
- if (rcfile.empty()) {
- warning << _("Without a UI style file, ardour will look strange.\n Please set ARDOUR2_UI_RC to point to a valid UI style file") << endmsg;
- } else {
- cerr << "Loading ui configuration file " << rcfile << endl;
- }
-
- ThemeChanged (rcfile); //EMIT SIGNAL
- theme_manager->setup_theme();
-}
-
-gint
-ARDOUR_UI::start_engine ()
-{
- 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;
+ return 0;
}
void
ARDOUR_UI::update_clocks ()
{
if (!editor || !editor->dragging_playhead()) {
- Clock (session->audible_frame(), false, editor->edit_cursor_position(false)); /* EMIT_SIGNAL */
+ Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
}
}
void
ARDOUR_UI::start_clocking ()
{
- clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
+ clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
}
void
{
clock_signal_connection.disconnect ();
}
-
-void
-ARDOUR_UI::toggle_clocking ()
-{
-#if 0
- if (clock_button.get_active()) {
- start_clocking ();
- } else {
- stop_clocking ();
- }
-#endif
-}
gint
ARDOUR_UI::_blink (void *arg)
*/
if (blink_timeout_tag < 0) {
- blink_on = false;
+ blink_on = false;
blink_timeout_tag = g_timeout_add (240, _blink, this);
}
}
}
}
+
+/** Ask the user for the name of a new snapshot and then take it.
+ */
+
void
-ARDOUR_UI::name_io_setup (AudioEngine& engine,
- string& buf,
- IO& io,
- bool in)
+ARDOUR_UI::snapshot_session (bool switch_to_it)
{
- if (in) {
- if (io.n_inputs().n_total() == 0) {
- buf = _("none");
- return;
- }
-
- /* XXX we're not handling multiple ports yet. */
+ ArdourPrompter prompter (true);
+ string snapname;
- const char **connections = io.input(0)->get_connections();
-
- if (connections == 0 || connections[0] == '\0') {
- buf = _("off");
- } else {
- buf = connections[0];
- }
+ prompter.set_name ("Prompter");
+ prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
+ prompter.set_title (_("Take Snapshot"));
+ prompter.set_prompt (_("Name of new snapshot"));
- free (connections);
+ if (!switch_to_it) {
+ char timebuf[128];
+ time_t n;
+ struct tm local_time;
- } else {
+ time (&n);
+ localtime_r (&n, &local_time);
+ strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
+ prompter.set_initial_text (timebuf);
+ }
- if (io.n_outputs().n_total() == 0) {
- buf = _("none");
- return;
+ again:
+ switch (prompter.run()) {
+ case RESPONSE_ACCEPT:
+ {
+ prompter.get_result (snapname);
+
+ bool do_save = (snapname.length() != 0);
+
+ if (do_save) {
+ char illegal = Session::session_name_is_legal(snapname);
+ if (illegal) {
+ MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
+ "snapshot names may not contain a '%1' character"), illegal));
+ msg.run ();
+ goto again;
+ }
}
-
- /* XXX we're not handling multiple ports yet. */
- const char **connections = io.output(0)->get_connections();
-
- if (connections == 0 || connections[0] == '\0') {
- buf = _("off");
- } else {
- buf = connections[0];
+ vector<sys::path> p;
+ get_state_files_in_directory (_session->session_directory().root_path(), p);
+ vector<string> n = get_file_names_no_extension (p);
+ if (find (n.begin(), n.end(), snapname) != n.end()) {
+
+ ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
+ Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
+ confirm.get_vbox()->pack_start (m, true, true);
+ confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
+ confirm.show_all ();
+ switch (confirm.run()) {
+ case RESPONSE_CANCEL:
+ do_save = false;
+ }
}
- free (connections);
+ if (do_save) {
+ save_state (snapname, switch_to_it);
+ }
+ break;
+ }
+
+ default:
+ break;
}
}
-/** Ask the user for the name of a new shapshot and then take it.
+/** Ask the user for a new session name and then rename the session to it.
*/
+
void
-ARDOUR_UI::snapshot_session ()
+ARDOUR_UI::rename_session ()
{
- ArdourPrompter prompter (true);
- string snapname;
- char timebuf[128];
- time_t n;
- struct tm local_time;
+ if (!_session) {
+ return;
+ }
- time (&n);
- localtime_r (&n, &local_time);
- strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
+ ArdourPrompter prompter (true);
+ string name;
prompter.set_name ("Prompter");
prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
- prompter.set_prompt (_("Name of New Snapshot"));
- prompter.set_initial_text (timebuf);
-
+ prompter.set_title (_("Rename Session"));
+ prompter.set_prompt (_("New session name"));
+
+ again:
switch (prompter.run()) {
case RESPONSE_ACCEPT:
- prompter.get_result (snapname);
- if (snapname.length()){
- save_state (snapname);
+ {
+ prompter.get_result (name);
+
+ bool do_rename = (name.length() != 0);
+
+ if (do_rename) {
+ char illegal = Session::session_name_is_legal (name);
+
+ if (illegal) {
+ MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
+ "session names may not contain a '%1' character"), illegal));
+ 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)
+ARDOUR_UI::save_state (const string & name, bool switch_to_it)
{
- (void) save_state_canfail (name);
+ XMLNode* node = new XMLNode (X_("UI"));
+
+ for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
+ if (!(*i)->rc_configured()) {
+ node->add_child_nocopy (*((*i)->get_state ()));
+ }
+ }
+
+ node->add_child_nocopy (gui_object_state->get_state());
+
+ _session->add_extra_xml (*node);
+
+ save_state_canfail (name, switch_to_it);
}
-
+
int
-ARDOUR_UI::save_state_canfail (string name)
+ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
{
- if (session) {
+ if (_session) {
int ret;
if (name.length() == 0) {
- name = session->snap_name();
+ name = _session->snap_name();
}
- if ((ret = session->save_state (name)) != 0) {
+ if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
return ret;
}
}
+
save_ardour_state (); /* XXX cannot fail? yeah, right ... */
return 0;
}
void
-ARDOUR_UI::restore_state (string name)
+ARDOUR_UI::primary_clock_value_changed ()
{
- if (session) {
- if (name.length() == 0) {
- name = session->name();
- }
- session->restore_state (name);
+ if (_session) {
+ _session->request_locate (primary_clock->current_time ());
}
}
void
-ARDOUR_UI::primary_clock_value_changed ()
+ARDOUR_UI::big_clock_value_changed ()
{
- if (session) {
- session->request_locate (primary_clock.current_time ());
+ if (_session) {
+ _session->request_locate (big_clock->current_time ());
}
}
void
ARDOUR_UI::secondary_clock_value_changed ()
{
- if (session) {
- session->request_locate (secondary_clock.current_time ());
+ if (_session) {
+ _session->request_locate (secondary_clock->current_time ());
}
}
void
-ARDOUR_UI::rec_enable_button_blink (bool onoff, AudioDiskstream *dstream, Widget *w)
+ARDOUR_UI::transport_rec_enable_blink (bool onoff)
{
- if (session && dstream && dstream->record_enabled()) {
-
- Session::RecordState rs;
-
- rs = session->record_status ();
-
- switch (rs) {
- case Session::Disabled:
- case Session::Enabled:
- if (w->get_state() != STATE_SELECTED) {
- w->set_state (STATE_SELECTED);
- }
- break;
-
- case Session::Recording:
- if (w->get_state() != STATE_ACTIVE) {
- w->set_state (STATE_ACTIVE);
- }
- break;
- }
-
- } else {
- if (w->get_state() != STATE_NORMAL) {
- w->set_state (STATE_NORMAL);
- }
+ if (_session == 0) {
+ return;
}
-}
-void
-ARDOUR_UI::transport_rec_enable_blink (bool onoff)
-{
- if (session == 0) {
+ if (_session->step_editing()) {
return;
}
-
- switch (session->record_status()) {
- case Session::Enabled:
+
+ Session::RecordState const r = _session->record_status ();
+ bool const h = _session->have_rec_enabled_track ();
+
+ if (r == Session::Enabled || (r == Session::Recording && !h)) {
if (onoff) {
- rec_button.set_visual_state (2);
+ rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
} else {
- rec_button.set_visual_state (0);
+ rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
}
- break;
-
- case Session::Recording:
- rec_button.set_visual_state (1);
- break;
-
- default:
- rec_button.set_visual_state (0);
- break;
+ } else if (r == Session::Recording && h) {
+ rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ } else {
+ rec_button.unset_active_state ();
}
}
-gint
-ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
-{
- window->hide();
- Gtk::Main::quit ();
- return TRUE;
-}
-
void
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"));
+ prompter.set_title (_("Save Template"));
+ prompter.set_prompt (_("Name for template:"));
+ prompter.set_initial_text(_session->name() + _("-template"));
prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
switch (prompter.run()) {
case RESPONSE_ACCEPT:
prompter.get_result (name);
-
+
if (name.length()) {
- session->save_template (name);
+ _session->save_template (name);
}
break;
}
}
+void
+ARDOUR_UI::edit_metadata ()
+{
+ SessionMetadataEditor dialog;
+ dialog.set_session (_session);
+ editor->ensure_float (dialog);
+ dialog.run ();
+}
+
+void
+ARDOUR_UI::import_metadata ()
+{
+ SessionMetadataImporter dialog;
+ dialog.set_session (_session);
+ editor->ensure_float (dialog);
+ dialog.run ();
+}
+
bool
-ARDOUR_UI::new_session (std::string predetermined_path)
+ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
{
- string session_name;
- string session_path;
+ std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
- if (!check_audioengine()) {
- return false;
+ MessageDialog msg (str,
+ false,
+ Gtk::MESSAGE_WARNING,
+ Gtk::BUTTONS_YES_NO,
+ true);
+
+
+ msg.set_name (X_("OpenExistingDialog"));
+ msg.set_title (_("Open Existing Session"));
+ msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
+ msg.set_position (Gtk::WIN_POS_MOUSE);
+ pop_back_splash (msg);
+
+ switch (msg.run()) {
+ case RESPONSE_YES:
+ return true;
+ break;
}
+ return false;
+}
- int response = Gtk::RESPONSE_NONE;
+int
+ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
+{
+ BusProfile bus_profile;
- new_session_dialog->set_modal(true);
- new_session_dialog->set_name (predetermined_path);
- new_session_dialog->reset_recent();
- new_session_dialog->show();
- new_session_dialog->set_current_page (0);
+ if (Profile->get_sae()) {
- do {
- response = new_session_dialog->run ();
+ bus_profile.master_out_channels = 2;
+ bus_profile.input_ac = AutoConnectPhysical;
+ bus_profile.output_ac = AutoConnectMaster;
+ bus_profile.requested_physical_in = 0; // use all available
+ bus_profile.requested_physical_out = 0; // use all available
- if (!check_audioengine()) {
- new_session_dialog->hide ();
- return false;
+ } else {
+
+ /* get settings from advanced section of NSD */
+
+ if (_startup->create_master_bus()) {
+ bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
+ } else {
+ bus_profile.master_out_channels = 0;
}
- _session_is_new = false;
+ if (_startup->connect_inputs()) {
+ bus_profile.input_ac = AutoConnectPhysical;
+ } else {
+ bus_profile.input_ac = AutoConnectOption (0);
+ }
- if (response == Gtk::RESPONSE_CANCEL || response == Gtk::RESPONSE_DELETE_EVENT) {
+ bus_profile.output_ac = AutoConnectOption (0);
- if (!session) {
- quit();
+ if (_startup->connect_outputs ()) {
+ if (_startup->connect_outs_to_master()) {
+ bus_profile.output_ac = AutoConnectMaster;
+ } else if (_startup->connect_outs_to_physical()) {
+ bus_profile.output_ac = AutoConnectPhysical;
}
- new_session_dialog->hide ();
- return false;
+ }
- } else if (response == Gtk::RESPONSE_NONE) {
+ bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
+ bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
+ }
- /* Clear was pressed */
- new_session_dialog->reset();
+ if (build_session (session_path, session_name, bus_profile)) {
+ return -1;
+ }
- } else if (response == Gtk::RESPONSE_YES) {
+ return 0;
+}
- /* YES == OPEN, but there's no enum for that */
+void
+ARDOUR_UI::idle_load (const std::string& path)
+{
+ if (_session) {
+ if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
+ /* /path/to/foo => /path/to/foo, foo */
+ load_session (path, basename_nosuffix (path));
+ } else {
+ /* /path/to/foo/foo.ardour => /path/to/foo, foo */
+ load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
+ }
+ } else {
- session_name = new_session_dialog->session_name();
+ ARDOUR_COMMAND_LINE::session_name = path;
- if (session_name.empty()) {
- response = Gtk::RESPONSE_NONE;
- continue;
- }
+ /*
+ * new_session_dialog doens't exist in A3
+ * Try to remove all references to it to
+ * see if it will compile. NOTE: this will
+ * likely cause a runtime issue is my somewhat
+ * uneducated guess.
+ */
- 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);
- } else {
- session_path = new_session_dialog->session_folder();
- load_session (session_path, session_name);
- }
+ //if (new_session_dialog) {
- } else if (response == Gtk::RESPONSE_OK) {
- session_name = new_session_dialog->session_name();
+ /* make it break out of Dialog::run() and
+ start again.
+ */
- if (!new_session_dialog->on_new_session_page ()) {
+ //new_session_dialog->response (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..
- */
+void
+ARDOUR_UI::loading_message (const std::string& msg)
+{
+ if (ARDOUR_COMMAND_LINE::no_splash) {
+ return;
+ }
- if (session_name.empty()) {
- response = Gtk::RESPONSE_NONE;
- continue;
- }
+ show_splash ();
+ if (splash) {
+ splash->message (msg);
+ flush_pending ();
+ }
+}
+
+/** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
+int
+ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
+{
+ string session_name;
+ string session_path;
+ string template_name;
+ int ret = -1;
+ bool likely_new = false;
+
+ if (!load_template.empty()) {
+ should_be_new = true;
+ template_name = load_template;
+ }
+
+ while (ret != 0) {
+
+ if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
+
+ /* if they named a specific statefile, use it, otherwise they are
+ just giving a session folder, and we want to use it as is
+ to find the session.
+ */
+
+ 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);
+ }
+
+ } else {
- 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);
+ bool const apply = run_startup (should_be_new, load_template);
+
+ if (!apply) {
+ if (quit_on_cancel) {
+ exit (1);
} else {
- session_path = new_session_dialog->session_folder();
- load_session (session_path, session_name);
+ return ret;
}
+ }
- } else {
+ /* if we run the startup dialog again, offer more than just "new session" */
- if (session_name.empty()) {
- response = Gtk::RESPONSE_NONE;
- continue;
- }
+ should_be_new = false;
- 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] == '/')) {
+ session_name = _startup->session_name (likely_new);
- session_path = Glib::path_get_dirname (session_name);
- session_name = Glib::path_get_basename (session_name);
+ string::size_type suffix = session_name.find (statefile_suffix);
- } else {
+ if (suffix != string::npos) {
+ session_name = session_name.substr (0, suffix);
+ }
- session_path = new_session_dialog->session_folder();
+ /* this shouldn't happen, but we catch it just in case it does */
- }
+ if (session_name.empty()) {
+ continue;
+ }
- //XXX This is needed because session constructor wants a
- //non-existant path. hopefully this will be fixed at some point.
+ if (_startup->use_session_template()) {
+ template_name = _startup->session_template_name();
+ _session_is_new = true;
+ }
- session_path = Glib::build_filename (session_path, session_name);
+ if (session_name[0] == G_DIR_SEPARATOR ||
+ (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
+ (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
- if (g_file_test (session_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
+ /* absolute path or cwd-relative path specified for session name: infer session folder
+ from what was given.
+ */
- Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
+ session_path = Glib::path_get_dirname (session_name);
+ session_name = Glib::path_get_basename (session_name);
- MessageDialog msg (str,
- false,
- Gtk::MESSAGE_WARNING,
- Gtk::BUTTONS_YES_NO,
- true);
+ } else {
+ session_path = _startup->session_folder();
- msg.set_name (X_("CleanupDialog"));
- msg.set_wmclass (X_("existing_session"), "Ardour");
- msg.set_position (Gtk::WIN_POS_MOUSE);
+ char illegal = Session::session_name_is_legal (session_name);
- switch (msg.run()) {
- case RESPONSE_YES:
- load_session (session_path, session_name);
- goto done;
- break;
- default:
- response = RESPONSE_NONE;
- new_session_dialog->reset ();
- continue;
- }
+ if (illegal) {
+ MessageDialog msg (*_startup,
+ string_compose (_("To ensure compatibility with various systems\n"
+ "session names may not contain a '%1' character"),
+ illegal));
+ msg.run ();
+ ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
+ continue;
}
+ }
+ }
- _session_is_new = true;
+ if (create_engine ()) {
+ break;
+ }
- std::string template_name = new_session_dialog->session_template_name();
+ if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
- if (new_session_dialog->use_session_template()) {
+ if (likely_new) {
- load_session (session_path, session_name, &template_name);
+ std::string existing = Glib::build_filename (session_path, session_name);
- } else {
+ if (!ask_about_loading_existing_session (existing)) {
+ ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
+ continue;
+ }
+ }
+
+ _session_is_new = false;
- 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 {
- 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);
- }
-
- uint32_t nphysin = (uint32_t) new_session_dialog->input_limit_count();
- uint32_t 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;
- new_session_dialog->reset ();
- continue;
- }
+ } else {
+
+ if (!likely_new) {
+ if (_startup) {
+ pop_back_splash (*_startup);
+ } else {
+ hide_splash ();
}
+
+ MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
+ msg.run ();
+ ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
+ continue;
}
+
+ char illegal = Session::session_name_is_legal(session_name);
+ if (illegal) {
+ pop_back_splash (*_startup);
+ MessageDialog msg (*_startup, string_compose(_("To ensure compatibility with various systems\n"
+ "session names may not contain a '%1' character"), illegal));
+ msg.run ();
+ ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
+ continue;
+ }
+
+ _session_is_new = true;
}
- } while (response == Gtk::RESPONSE_NONE);
+ if (likely_new && template_name.empty()) {
+
+ ret = build_session_from_nsd (session_path, session_name);
+
+ } else {
+
+ ret = load_session (session_path, session_name, template_name);
+
+ if (ret == -2) {
+ /* not connected to the AudioEngine, so quit to avoid an infinite loop */
+ exit (1);
+ }
- done:
- show();
- new_session_dialog->get_window()->set_cursor();
- new_session_dialog->hide();
- return true;
+ if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
+ _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
+ exit (1);
+ }
+ }
+ }
+
+ return ret;
}
void
return;
}
- unload_session();
- new_session ();
+ if (unload_session (true)) {
+ return;
+ }
+
+ ARDOUR_COMMAND_LINE::session_name = "";
+
+ if (get_session_parameters (true, false)) {
+ exit (1);
+ }
+
+ goto_editor_window ();
}
+/** @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 string & path, const string & snap_name, string* mix_template)
+ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
{
Session *new_session;
+ int unload_status;
+ int retval = -1;
+
session_loaded = false;
-
+
if (!check_audioengine()) {
- return -1;
+ return -2;
}
- if(!unload_session ()) return -1;
-
- /* if it already exists, we must have write access */
+ unload_status = unload_session ();
- 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."));
- msg.run ();
- return -1;
+ if (unload_status < 0) {
+ goto out;
+ } else if (unload_status > 0) {
+ retval = 0;
+ goto out;
}
+ loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
+
try {
- new_session = new Session (*engine, path, snap_name, mix_template);
+ new_session = new Session (*engine, path, snap_name, 0, mix_template);
+ }
+
+ /* this one is special */
+
+ catch (AudioEngine::PortRegistrationFailure& err) {
+
+ MessageDialog msg (err.what(),
+ true,
+ Gtk::MESSAGE_INFO,
+ Gtk::BUTTONS_CLOSE);
+
+ msg.set_title (_("Port Registration Error"));
+ msg.set_secondary_text (_("Click the Close button to try again."));
+ msg.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash (msg);
+ msg.present ();
+
+ int response = msg.run ();
+
+ msg.hide ();
+
+ switch (response) {
+ case RESPONSE_CANCEL:
+ exit (1);
+ default:
+ break;
+ }
+ goto out;
}
catch (...) {
- error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
- return -1;
+ MessageDialog msg (string_compose(
+ _("Session \"%1 (snapshot %2)\" did not load successfully"),
+ path, snap_name),
+ true,
+ Gtk::MESSAGE_INFO,
+ BUTTONS_OK);
+
+ msg.set_title (_("Loading Error"));
+ msg.set_secondary_text (_("Click the Refresh button to try again."));
+ msg.add_button (Stock::REFRESH, 1);
+ msg.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash (msg);
+ msg.present ();
+
+ int response = msg.run ();
+
+ switch (response) {
+ case 1:
+ break;
+ default:
+ exit (1);
+ }
+
+ msg.hide ();
+
+ goto out;
+ }
+
+ {
+ list<string> const u = new_session->unknown_processors ();
+ if (!u.empty()) {
+ MissingPluginDialog d (_session, u);
+ d.run ();
+ }
}
- connect_to_session (new_session);
+ /* Now the session been created, add the transport controls */
+ new_session->add_controllable(roll_controllable);
+ new_session->add_controllable(stop_controllable);
+ new_session->add_controllable(goto_start_controllable);
+ new_session->add_controllable(goto_end_controllable);
+ new_session->add_controllable(auto_loop_controllable);
+ new_session->add_controllable(play_selection_controllable);
+ new_session->add_controllable(rec_controllable);
- Config->set_current_owner (ConfigVariableBase::Interface);
+ set_session (new_session);
session_loaded = true;
-
+
goto_editor_window ();
- if (session) {
- session->set_clean ();
+ if (_session) {
+ _session->set_clean ();
}
- editor->edit_cursor_position (true);
- return 0;
+ flush_pending ();
+ retval = 0;
+
+ out:
+ return retval;
}
-bool
-ARDOUR_UI::build_session (const string & path, const string & snap_name,
- uint32_t control_channels,
- uint32_t master_channels,
- AutoConnectOption input_connect,
- AutoConnectOption output_connect,
- uint32_t nphysin,
- uint32_t nphysout,
- nframes_t initial_length)
+int
+ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
{
Session *new_session;
+ int x;
if (!check_audioengine()) {
- return false;
+ return -1;
}
session_loaded = false;
- if (!unload_session ()) return false;
-
+ x = unload_session ();
+
+ if (x < 0) {
+ return -1;
+ } else if (x > 0) {
+ return 0;
+ }
+
_session_is_new = true;
try {
- new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
- control_channels, master_channels, nphysin, nphysout, initial_length);
+ new_session = new Session (*engine, path, snap_name, &bus_profile);
}
catch (...) {
MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
+ pop_back_splash (msg);
msg.run ();
- return false;
+ return -1;
+ }
+
+ /* Give the new session the default GUI state, if such things exist */
+
+ XMLNode* n;
+ n = Config->instant_xml (X_("Editor"));
+ if (n) {
+ new_session->add_instant_xml (*n, false);
+ }
+ n = Config->instant_xml (X_("Mixer"));
+ if (n) {
+ new_session->add_instant_xml (*n, false);
+ }
+
+ /* Put the playhead at 0 and scroll fully left */
+ n = new_session->instant_xml (X_("Editor"));
+ if (n) {
+ n->add_property (X_("playhead"), X_("0"));
+ n->add_property (X_("left-frame"), X_("0"));
+ }
+
+ set_session (new_session);
+
+ session_loaded = true;
+
+ new_session->save_state(new_session->name());
+
+ return 0;
+}
+
+void
+ARDOUR_UI::launch_chat ()
+{
+#ifdef __APPLE__
+ open_uri("http://webchat.freenode.net/?channels=ardour-osx");
+#else
+ open_uri("http://webchat.freenode.net/?channels=ardour");
+#endif
+}
+
+void
+ARDOUR_UI::show_about ()
+{
+ if (about == 0) {
+ about = new About;
+ about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
}
- connect_to_session (new_session);
+ about->set_transient_for(*editor);
+ about->show_all ();
+}
- session_loaded = true;
- return true;
+void
+ARDOUR_UI::launch_manual ()
+{
+ PBD::open_uri("http://ardour.org/flossmanual");
}
void
-ARDOUR_UI::show ()
+ARDOUR_UI::launch_reference ()
{
- if (editor) {
- editor->show_window ();
-
- if (!shown_flag) {
- editor->present ();
- }
+ PBD::open_uri("http://ardour.org/refmanual");
+}
- shown_flag = true;
+void
+ARDOUR_UI::hide_about ()
+{
+ if (about) {
+ about->get_window()->set_cursor ();
+ about->hide ();
}
}
void
-ARDOUR_UI::show_splash ()
+ARDOUR_UI::about_signal_response (int /*response*/)
{
- if (about == 0) {
- about = new About();
- about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
- }
- about->present();
- flush_pending ();
+ hide_about();
}
void
-ARDOUR_UI::about_signal_response(int response)
+ARDOUR_UI::show_splash ()
{
- hide_splash();
+ if (splash == 0) {
+ try {
+ splash = new Splash;
+ } catch (...) {
+ cerr << "Splash could not be created\n";
+ return;
+ }
+ }
+
+ splash->present ();
+ splash->pop_front ();
+ splash->queue_draw ();
+ splash->get_window()->process_updates (true);
+ flush_pending ();
}
void
ARDOUR_UI::hide_splash ()
{
- if (about) {
- about->get_window()->set_cursor ();
- about->hide();
+ if (splash) {
+ splash->hide();
}
}
void
-ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
+ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
+ const string& plural_msg, const string& singular_msg)
{
size_t removed;
if (removed == 0) {
MessageDialog msgd (*editor,
- _("No audio files were ready for cleanup"),
+ _("No files were ready for clean-up"),
true,
Gtk::MESSAGE_INFO,
- (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
+ Gtk::BUTTONS_OK);
+ msgd.set_title (_("Clean-up"));
msgd.set_secondary_text (_("If this seems suprising, \n\
check for any existing snapshots.\n\
These may still include regions that\n\
require some unused files to continue to exist."));
-
+
msgd.run ();
return;
- }
+ }
+
+ ArdourDialog results (_("Clean-up"), true, false);
- ArdourDialog results (_("ardour: cleanup"), true, false);
-
struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
- CleanupResultsModelColumns() {
+ CleanupResultsModelColumns() {
add (visible_name);
add (fullpath);
}
- Gtk::TreeModelColumn<Glib::ustring> visible_name;
- Gtk::TreeModelColumn<Glib::ustring> fullpath;
+ Gtk::TreeModelColumn<std::string> visible_name;
+ Gtk::TreeModelColumn<std::string> fullpath;
};
-
+
CleanupResultsModelColumns results_columns;
Glib::RefPtr<Gtk::ListStore> results_model;
Gtk::TreeView results_display;
-
+
results_model = ListStore::create (results_columns);
results_display.set_model (results_model);
results_display.append_column (list_title, results_columns.visible_name);
dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
- const string dead_sound_directory = session->session_directory().dead_sound_path().to_string();
+ const string dead_directory = _session->session_directory().dead_path().to_string();
- if (rep.space < 1048576.0f) {
- if (removed > 1) {
- txt.set_text (string_compose (msg, removed, _("files were"), dead_sound_directory, (float) rep.space / 1024.0f, "kilo"));
- } else {
- txt.set_text (string_compose (msg, removed, _("file was"), dead_sound_directory, (float) rep.space / 1024.0f, "kilo"));
- }
+ /* subst:
+ %1 - number of files removed
+ %2 - location of "dead"
+ %3 - size of files affected
+ %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
+ */
+
+ const char* bprefix;
+ double space_adjusted = 0;
+
+ if (rep.space < 1000) {
+ bprefix = X_("");
+ space_adjusted = rep.space;
+ } else if (rep.space < 1000000) {
+ bprefix = X_("kilo");
+ space_adjusted = truncf((float)rep.space / 1000.0);
+ } else if (rep.space < 1000000 * 1000) {
+ bprefix = X_("mega");
+ space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
} else {
- if (removed > 1) {
- txt.set_text (string_compose (msg, removed, _("files were"), dead_sound_directory, (float) rep.space / 1048576.0f, "mega"));
- } else {
- txt.set_text (string_compose (msg, removed, _("file was"), dead_sound_directory, (float) rep.space / 1048576.0f, "mega"));
- }
+ bprefix = X_("giga");
+ space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
+ }
+
+ if (removed > 1) {
+ txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
+ } else {
+ txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
}
dhbox.pack_start (*dimage, true, false, 5);
row[results_columns.visible_name] = *i;
row[results_columns.fullpath] = *i;
}
-
+
list_scroller.add (results_display);
list_scroller.set_size_request (-1, 150);
list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
results.set_default_response (RESPONSE_CLOSE);
results.set_position (Gtk::WIN_POS_MOUSE);
- results.show_all_children ();
+
+ results_display.show();
+ list_scroller.show();
+ txt.show();
+ dvbox.show();
+ dhbox.show();
+ ddhbox.show();
+ dimage->show();
+
+ //results.get_vbox()->show();
results.set_resizable (false);
results.run ();
void
ARDOUR_UI::cleanup ()
{
- if (session == 0) {
+ if (_session == 0) {
/* shouldn't happen: menu item is insensitive */
return;
}
- MessageDialog checker (_("Are you sure you want to cleanup?"),
+ MessageDialog checker (_("Are you sure you want to clean-up?"),
true,
Gtk::MESSAGE_QUESTION,
- (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
+ 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."));
- checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
-ALL undo/redo information will be lost if you cleanup.\n\
-After cleanup, unused audio files will be moved to a \
-\"dead sounds\" location."));
-
checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
- checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
+ checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
checker.set_default_response (RESPONSE_CANCEL);
checker.set_name (_("CleanupDialog"));
- checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
+ checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
checker.set_position (Gtk::WIN_POS_MOUSE);
switch (checker.run()) {
return;
}
- Session::cleanup_report rep;
+ ARDOUR::CleanupReport rep;
editor->prepare_for_cleanup ();
act->set_sensitive (false);
}
- if (session->cleanup_sources (rep)) {
+ if (_session->cleanup_sources (rep)) {
+ editor->finish_cleanup ();
return;
}
+ editor->finish_cleanup ();
+
checker.hide();
- display_cleanup_results (rep,
- _("cleaned files"),
+ display_cleanup_results (rep,
+ _("Cleaned Files"),
_("\
-The following %1 %2 not in use and \n\
-have been moved to:\n\
-%3. \n\n\
-Flushing the wastebasket will \n\
-release an additional\n\
-%4 %5bytes of disk space.\n"
+The following %1 files were not in use and \n\
+have been moved to:\n\n\
+%2\n\n\
+After a restart of %5,\n\n\
+Session -> Clean-up -> Flush Wastebasket\n\n\
+will release an additional\n\
+%3 %4bytes of disk space.\n"),
+ _("\
+The following file was not in use and \n\
+has been moved to:\n \
+%2\n\n\
+After a restart of %5,\n\n\
+Session -> Clean-up -> Flush Wastebasket\n\n\
+will release an additional\n\
+%3 %4bytes of disk space.\n"
));
-
-
}
void
ARDOUR_UI::flush_trash ()
{
- if (session == 0) {
+ if (_session == 0) {
/* shouldn't happen: menu item is insensitive */
return;
}
- Session::cleanup_report rep;
+ ARDOUR::CleanupReport rep;
- if (session->cleanup_trash_sources (rep)) {
+ if (_session->cleanup_trash_sources (rep)) {
return;
}
- display_cleanup_results (rep,
+ display_cleanup_results (rep,
_("deleted file"),
- _("The following %1 %2 deleted from\n\
-%3,\n\
-releasing %4 %5bytes of disk space"));
+ _("The following %1 files were deleted from\n\
+%2,\n\
+releasing %3 %4bytes of disk space"),
+ _("The following file was deleted from\n\
+%2,\n\
+releasing %3 %4bytes of disk space"));
}
void
{
int count;
- if (!session) {
+ if (!_session) {
return;
}
if (add_route_dialog == 0) {
- add_route_dialog = new AddRouteDialog;
+ add_route_dialog = new AddRouteDialog (_session);
+ add_route_dialog->set_position (WIN_POS_MOUSE);
if (float_window) {
add_route_dialog->set_transient_for (*float_window);
}
return;
}
+ string template_path = add_route_dialog->track_template();
+
+ if (!template_path.empty()) {
+ _session->new_route_from_template (count, template_path);
+ return;
+ }
+
uint32_t input_chan = add_route_dialog->channels ();
uint32_t output_chan;
string name_template = add_route_dialog->name_template ();
- bool track = add_route_dialog->track ();
+ PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
+ RouteGroup* route_group = add_route_dialog->route_group ();
AutoConnectOption oac = Config->get_output_auto_connect();
if (oac & AutoConnectMaster) {
- output_chan = (session->master_out() ? session->master_out()->n_inputs().n_audio() : input_chan);
+ output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
} else {
output_chan = input_chan;
}
/* XXX do something with name template */
- if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
- if (track) {
- session_add_midi_track(count);
- } else {
- MessageDialog msg (*editor,
- _("Sorry, MIDI Busses are not supported at this time."));
- msg.run ();
- //session_add_midi_bus();
- }
- } else {
- if (track) {
- session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
- } else {
- session_add_audio_bus (input_chan, output_chan, count);
- }
+ if (add_route_dialog->midi_tracks_wanted()) {
+ session_add_midi_track (route_group, count, name_template, instrument);
+ } else if (add_route_dialog->audio_tracks_wanted()) {
+ session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
+ } else {
+ session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
}
}
{
XMLNode* node = 0;
- if (session) {
- node = session->instant_xml(X_("Mixer"), session->path());
+ if (_session) {
+ node = _session->instant_xml(X_("Mixer"));
} else {
- node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
+ node = Config->instant_xml(X_("Mixer"));
}
if (!node) {
{
XMLNode* node = 0;
- if (session) {
- node = session->instant_xml(X_("Editor"), session->path());
+ if (_session) {
+ node = _session->instant_xml(X_("Editor"));
} else {
- node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
+ node = Config->instant_xml(X_("Editor"));
+ }
+
+ if (!node) {
+ if (getenv("ARDOUR_INSTANT_XML_PATH")) {
+ node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
+ }
}
if (!node) {
node = new XMLNode (X_("Editor"));
}
+
return node;
}
XMLNode* node = 0;
node = Config->extra_xml(X_("Keyboard"));
-
+
if (!node) {
node = new XMLNode (X_("Keyboard"));
}
+
return node;
}
void
-ARDOUR_UI::halt_on_xrun_message ()
+ARDOUR_UI::create_xrun_marker (framepos_t where)
{
- ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message));
+ editor->mouse_add_new_marker (where, false, true);
+}
+void
+ARDOUR_UI::halt_on_xrun_message ()
+{
MessageDialog msg (*editor,
_("Recording was stopped because your system could not keep up."));
msg.run ();
}
+void
+ARDOUR_UI::xrun_handler (framepos_t where)
+{
+ if (!_session) {
+ return;
+ }
+
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
+
+ if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
+ create_xrun_marker(where);
+ }
+
+ if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
+ halt_on_xrun_message ();
+ }
+}
+
void
ARDOUR_UI::disk_overrun_handler ()
{
- ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
if (!have_disk_speed_dialog_displayed) {
have_disk_speed_dialog_displayed = true;
- MessageDialog* msg = new MessageDialog (*editor, _("\
+ MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
The disk system on your computer\n\
-was not able to keep up with Ardour.\n\
+was not able to keep up with %1.\n\
\n\
Specifically, it failed to write data to disk\n\
-quickly enough to keep up with recording.\n"));
- msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
- msg->show_all ();
+quickly enough to keep up with recording.\n"), PROGRAM_NAME));
+ msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
+ msg->show ();
}
}
void
ARDOUR_UI::disk_underrun_handler ()
{
- ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
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\
+ MessageDialog* msg = new MessageDialog (
+ *editor, string_compose (_("The disk system on your computer\n\
+was not able to keep up with %1.\n\
\n\
Specifically, it failed to read data from disk\n\
-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 ();
- }
+quickly enough to keep up with playback.\n"), PROGRAM_NAME));
+ msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
+ msg->show ();
+ }
}
void
-ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
+ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
{
have_disk_speed_dialog_displayed = false;
delete msg;
}
+void
+ARDOUR_UI::session_dialog (std::string msg)
+{
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
+
+ MessageDialog* d;
+
+ if (editor) {
+ d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
+ } else {
+ d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
+ }
+
+ d->show_all ();
+ d->run ();
+ delete d;
+}
+
int
ARDOUR_UI::pending_state_dialog ()
{
- ArdourDialog dialog ("pending state dialog");
+ HBox* hbox = new HBox();
+ Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
+ ArdourDialog dialog (_("Crash Recovery"), true);
Label message (_("\
This session appears to have been in\n\
middle of recording when ardour or\n\
Ardour can recover any captured audio for\n\
you, or it can ignore it. Please decide\n\
what you would like to do.\n"));
-
- dialog.get_vbox()->pack_start (message);
- dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
+ image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
+ hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
+ hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
+ dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
-
+ dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
+ dialog.set_default_response (RESPONSE_ACCEPT);
dialog.set_position (WIN_POS_CENTER);
- dialog.show_all ();
-
+ message.show();
+ image->show();
+ hbox->show();
+
switch (dialog.run ()) {
case RESPONSE_ACCEPT:
return 1;
return 0;
}
}
-
+
+int
+ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
+{
+ HBox* hbox = new HBox();
+ Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
+ ArdourDialog dialog (_("Sample Rate Mismatch"), true);
+ Label message (string_compose (_("\
+This session was created with a sample rate of %1 Hz\n\
+\n\
+The audioengine is currently running at %2 Hz\n"), desired, actual));
+
+ image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
+ hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
+ hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
+ dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
+ dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
+ dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
+ dialog.set_default_response (RESPONSE_ACCEPT);
+ dialog.set_position (WIN_POS_CENTER);
+ message.show();
+ image->show();
+ hbox->show();
+
+ switch (dialog.run ()) {
+ case RESPONSE_ACCEPT:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+
void
ARDOUR_UI::disconnect_from_jack ()
{
}
}
-int
-ARDOUR_UI::cmdline_new_session (string path)
-{
- if (path[0] != '/') {
- char buf[PATH_MAX+1];
- string str;
-
- getcwd (buf, sizeof (buf));
- str = buf;
- str += '/';
- str += path;
- path = str;
- }
-
- new_session (path);
-
- return FALSE; /* don't call it again */
-}
-
void
ARDOUR_UI::use_config ()
{
- Glib::RefPtr<Action> act;
-
- switch (Config->get_native_file_data_format ()) {
- case FormatFloat:
- act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
- break;
- case FormatInt24:
- act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
- break;
- }
-
- if (act) {
- Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
- ract->set_active ();
- }
-
- switch (Config->get_native_file_header_format ()) {
- case BWF:
- act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
- break;
- case WAVE:
- act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
- break;
- case WAVE64:
- act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
- break;
- case iXML:
- act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
- break;
- case RF64:
- act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
- break;
- case CAF:
- act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
- break;
- case AIFF:
- act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
- break;
- }
-
- if (act) {
- Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::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)
+ARDOUR_UI::update_transport_clocks (framepos_t pos)
{
if (Config->get_primary_clock_delta_edit_cursor()) {
- primary_clock.set (pos, false, editor->edit_cursor_position(false), 'p');
+ primary_clock->set (pos, false, editor->get_preferred_edit_position());
} else {
- primary_clock.set (pos, 0, true);
+ primary_clock->set (pos);
}
if (Config->get_secondary_clock_delta_edit_cursor()) {
- secondary_clock.set (pos, false, editor->edit_cursor_position(false), 's');
+ secondary_clock->set (pos, false, editor->get_preferred_edit_position());
} else {
- secondary_clock.set (pos);
+ secondary_clock->set (pos);
}
- if (big_clock_window) {
- big_clock.set (pos);
+ if (big_clock_window->get()) {
+ big_clock->set (pos);
}
}
+
void
-ARDOUR_UI::record_state_changed ()
+ARDOUR_UI::step_edit_status_change (bool yn)
{
- ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
-
- if (!session || !big_clock_window) {
- /* why bother - the clock isn't visible */
- return;
- }
+ // XXX should really store pre-step edit status of things
+ // we make insensitive
- switch (session->record_status()) {
- case Session::Recording:
- big_clock.set_widget_name ("BigClockRecording");
- break;
- default:
- big_clock.set_widget_name ("BigClockNonRecording");
- break;
+ if (yn) {
+ rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
+ rec_button.set_sensitive (false);
+ } else {
+ rec_button.unset_active_state ();;
+ rec_button.set_sensitive (true);
}
}
void
-ARDOUR_UI::set_keybindings_path (string path)
+ARDOUR_UI::record_state_changed ()
{
- keybindings_path = path;
-}
+ ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
-void
-ARDOUR_UI::save_keybindings ()
-{
- if (can_save_keybindings) {
- AccelMap::save (keybindings_path);
- }
+ if (!_session || !big_clock_window->get()) {
+ /* why bother - the clock isn't visible */
+ return;
+ }
+
+ if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
+ big_clock->set_active (true);
+ } else {
+ big_clock->set_active (false);
+ }
}
bool
ARDOUR_UI::first_idle ()
{
- if (session) {
- session->allow_auto_play (true);
+ if (_session) {
+ _session->allow_auto_play (true);
}
- can_save_keybindings = true;
+
+ if (editor) {
+ editor->first_idle();
+ }
+
+ Keyboard::set_can_save_keybindings (true);
return false;
}
XMLNode* node = new XMLNode(X_("ClockModes"));
for (vector<AudioClock*>::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 ();
+ _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)
+ARDOUR_UI::TransportControllable::set_value (double 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) {
+ if (val < 0.5) {
/* do nothing: these are radio-style actions */
return;
}
- char *action = 0;
+ const char *action = 0;
switch (type) {
case Roll:
}
}
-float
+double
ARDOUR_UI::TransportControllable::get_value (void) const
{
- float val = 0.0f;
-
+ float val = 0.0;
+
switch (type) {
case Roll:
break;
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 ();
+ }
}
void
-ARDOUR_UI::disable_all_plugins ()
+ARDOUR_UI::toggle_translations ()
{
- if (!session) {
- return;
- }
+ using namespace Glib;
+
+ RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
+ if (act) {
+ RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
+ if (ract) {
+
+ string i18n_killer = ARDOUR::translation_kill_path();
- // session->begin_reversible_command (_("Disable all plugins"));
+ bool already_enabled = !ARDOUR::translations_are_disabled ();
- boost::shared_ptr<Session::RouteList> routes = session->get_routes ();
+ if (ract->get_active ()) {
+/* we don't care about errors */
+ int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
+ close (fd);
+ } else {
+/* we don't care about errors */
+ unlink (i18n_killer.c_str());
+ }
- for (Session::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- // XMLNode& before = (*i)->get_redirect_state ();
- // session->add_command (new MementoCommand<Route>(**i, &before, 0));
- (*i)->disable_plugins ();
- // XMLNode& after = (*i)->get_redirect_state ();
- // session->add_command (new MementoCommand<Route>(**i, 0, &after));
-
+ if (already_enabled != ract->get_active()) {
+ MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
+ false,
+ Gtk::MESSAGE_WARNING,
+ Gtk::BUTTONS_OK);
+ win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
+ win.set_position (Gtk::WIN_POS_CENTER);
+ win.present ();
+ win.run ();
+ }
+ }
}
+}
- // session->commit_reversible_command ();
+/** Add a window proxy to our list, so that its state will be saved.
+ * This call also causes the window to be created and opened if its
+ * state was saved as `visible'.
+ */
+void
+ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
+{
+ _window_proxies.push_back (p);
+ p->maybe_show ();
}
+/** Remove a window proxy from our list. Must be called if a WindowProxy
+ * is deleted, to prevent hanging pointers.
+ */
void
-ARDOUR_UI::ab_all_plugins ()
+ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
{
- if (!session) {
- return;
+ _window_proxies.remove (p);
+}
+
+int
+ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
+{
+ MissingFileDialog dialog (s, str, type);
+
+ dialog.show ();
+ dialog.present ();
+
+ int result = dialog.run ();
+ dialog.hide ();
+
+ switch (result) {
+ case RESPONSE_OK:
+ break;
+ default:
+ return 1; // quit entire session load
}
- boost::shared_ptr<Session::RouteList> routes = session->get_routes ();
+ result = dialog.get_action ();
+
+ return result;
+}
+
+int
+ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
+{
+ AmbiguousFileDialog dialog (file, hits);
+
+ dialog.show ();
+ dialog.present ();
+
+ dialog.run ();
+ return dialog.get_which ();
+}
+
+/** Allocate our thread-local buffers */
+void
+ARDOUR_UI::get_process_buffers ()
+{
+ _process_thread->get_buffers ();
+}
+
+/** Drop our thread-local buffers */
+void
+ARDOUR_UI::drop_process_buffers ()
+{
+ _process_thread->drop_buffers ();
+}
+
+void
+ARDOUR_UI::feedback_detected ()
+{
+ _feedback_exists = true;
+}
+
+void
+ARDOUR_UI::successful_graph_sort ()
+{
+ _feedback_exists = false;
+}
- for (Session::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- (*i)->ab_plugins (ab_direction);
+void
+ARDOUR_UI::midi_panic ()
+{
+ if (_session) {
+ _session->midi_panic();
}
-
- ab_direction = !ab_direction;
}