/*
- 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
#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/failed_constructor.h>
-#include <pbd/enumwriter.h>
-#include <pbd/memento_command.h>
-#include <pbd/file_utils.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 <ardour/filesystem_paths.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/file_utils.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++/manager.h"
+
+#include "ardour/ardour.h"
+#include "ardour/profile.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"
+
+typedef uint64_t microseconds_t;
#include "actions.h"
#include "ardour_ui.h"
#include "prompter.h"
#include "opts.h"
#include "add_route_dialog.h"
-#include "new_session_dialog.h"
#include "about.h"
+#include "splash.h"
#include "utils.h"
#include "gui_thread.h"
#include "theme_manager.h"
-
+#include "bundle_manager.h"
+#include "session_metadata_dialog.h"
+#include "gain_meter.h"
+#include "route_time_axis.h"
+#include "startup.h"
+#include "engine_dialog.h"
+#include "processor_box.h"
#include "i18n.h"
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),
-
- /* adjuster table */
+ : Gtkmm2ext::UI (X_("gui"), argcp, argvp),
- adjuster_table (3, 3),
+ primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
+ secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
+ preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
+ postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
/* preroll stuff */
/* big clock */
- big_clock (X_("bigclock"), false, "BigClockNonRecording", false, false, true),
+ big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, true),
/* transport */
- 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),
+ 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)),
+ shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
shuttle_controller_binding_proxy (shuttle_controllable),
roll_button (roll_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")),
auditioning_alert_button (_("AUDITION")),
solo_alert_button (_("SOLO")),
- shown_flag (false)
+ shown_flag (false),
+ error_log_button (_("Errors"))
+
{
using namespace Gtk::Menu_Helpers;
Gtkmm2ext::init();
-
+
+
+#ifdef TOP_MENUBAR
+ // _auto_display_errors = false;
+ /*
+ * 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;
ui_config = new UIConfiguration();
theme_manager = new ThemeManager();
-
+
editor = 0;
mixer = 0;
session = 0;
+ editor = 0;
+ engine = 0;
_session_is_new = false;
big_clock_window = 0;
session_selector_window = 0;
last_key_press_time = 0;
- connection_editor = 0;
+ _will_create_new_session_automatically = false;
add_route_dialog = 0;
route_params = 0;
- option_editor = 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;
- ab_direction = true;
-
- sys::path key_bindings_file;
-
- find_file_in_search_path (ardour_search_path() + system_config_search_path(),
- "ardour.bindings", key_bindings_file);
-
- keybindings_path = key_bindings_file.to_string();
+ ignore_dual_punch = false;
+ _mixer_on_top = false;
- can_save_keybindings = false;
+ roll_button.unset_flags (Gtk::CAN_FOCUS);
+ stop_button.unset_flags (Gtk::CAN_FOCUS);
+ goto_start_button.unset_flags (Gtk::CAN_FOCUS);
+ goto_end_button.unset_flags (Gtk::CAN_FOCUS);
+ auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
+ play_selection_button.unset_flags (Gtk::CAN_FOCUS);
+ rec_button.unset_flags (Gtk::CAN_FOCUS);
- last_configure_time.tv_sec = 0;
- last_configure_time.tv_usec = 0;
+ last_configure_time= 0;
shuttle_grabbed = false;
shuttle_fract = 0.0;
shuttle_style_menu = 0;
shuttle_unit_menu = 0;
- gettimeofday (&last_peak_grab, 0);
- gettimeofday (&last_shuttle_request, 0);
+ // We do not have jack linked in yet so;
+
+ last_shuttle_request = last_peak_grab = 0; // get_microseconds();
ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
+ /* handle dialog requests */
+
+ ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
+
/* handle pending state with a dialog */
ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
- /* have to wait for AudioEngine and Configuration before proceeding */
+ /* handle sr mismatch with a dialog */
+
+ ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
+
+ /* 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 ();
+ SendProcessorEntry::setup_slider_pix ();
+ SessionEvent::create_per_thread_pool ("GUI", 512);
+
+ } catch (failed_constructor& err) {
+ error << _("could not initialize Ardour.") << endmsg;
+ // pass it on up
+ throw;
+ }
+
+ /* we like keyboards */
+
+ keyboard = new ArdourKeyboard;
+
+ XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
+ if (node) {
+ keyboard->set_state (*node, Stateful::loading_state_version);
+ }
+
+ reset_dpi();
+
+ starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
+ stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
+
+ platform_setup ();
}
-void
-ARDOUR_UI::set_engine (AudioEngine& e)
+/** @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)
+{
+ if (_startup == 0) {
+ _startup = new ArdourStartup ();
+ }
+
+ _startup->set_new_only (should_be_new);
+ _startup->present ();
+
+ main().run();
+
+ _startup->hide ();
+
+ switch (_startup->response()) {
+ case RESPONSE_OK:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int
+ARDOUR_UI::create_engine ()
{
- engine = &e;
+ // 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);
+
+ } catch (...) {
+
+ return -1;
+ }
engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
- ActionManager::init ();
- new_session_dialog = new NewSessionDialog();
+ post_engine ();
- _tooltips.enable();
+ return 0;
+}
+
+void
+ARDOUR_UI::post_engine ()
+{
+ /* Things to be done once we create the AudioEngine
+ */
- keyboard = new Keyboard;
+ MIDI::Manager::instance()->set_api_data (engine->jack());
+ setup_midi ();
+
+ ARDOUR::init_post_engine ();
+
+ ActionManager::init ();
+ _tooltips.enable();
if (setup_windows ()) {
throw failed_constructor ();
}
+
+ check_memory_locking();
- if (GTK_ARDOUR::show_key_actions) {
+ /* this is the first point at which all the keybindings are available */
+
+ if (ARDOUR_COMMAND_LINE::show_key_actions) {
vector<string> names;
vector<string> paths;
vector<string> keys;
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 an always visible wallclock, so don't be stupid */
update_wall_clock ();
Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
+#endif
update_disk_space ();
update_cpu_load ();
update_sample_rate (engine->frame_rate());
- starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
- stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
+ Config->ParameterChanged.connect (mem_fun (*this, &ARDOUR_UI::parameter_changed));
+ Config->map_parameters (mem_fun (*this, &ARDOUR_UI::parameter_changed));
+
+ /* now start and maybe save state */
+
+ if (do_engine_start () == 0) {
+ if (session && _session_is_new) {
+ /* we need to retain initial visual
+ settings for a new session
+ */
+ session->save_state ("");
+ }
+ }
}
ARDOUR_UI::~ARDOUR_UI ()
{
save_ardour_state ();
- if (keyboard) {
- delete keyboard;
- }
-
- if (editor) {
- delete editor;
- }
-
- if (mixer) {
- delete mixer;
- }
+ delete keyboard;
+ delete editor;
+ delete mixer;
+ delete add_route_dialog;
+}
- if (add_route_dialog) {
- delete add_route_dialog;
+void
+ARDOUR_UI::pop_back_splash ()
+{
+ if (Splash::instance()) {
+ // Splash::instance()->pop_back();
+ Splash::instance()->hide ();
}
}
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;
}
- 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) {
+ if (get_microseconds() - last_configure_time < 500000) {
return TRUE;
} else {
have_configure_timeout = 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);
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_controllable->set_id (prop->value());
}
}
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_controllable->id().print (buf, sizeof (buf));
node->add_property (X_("shuttle"), buf);
return *node;
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());
+ if (_startup && _startup->engine_control() && _startup->engine_control()->was_used()) {
+ Config->add_extra_xml (_startup->engine_control()->get_state());
+ }
Config->save_state();
+ ui_config->save_state ();
XMLNode enode(static_cast<Stateful*>(editor)->get_state());
XMLNode mnode(mixer->get_state());
Config->add_instant_xml (mnode);
}
- save_keybindings ();
+ Keyboard::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 (session) {
- session->maybe_write_autosave();
+ if (!Config->get_periodic_safety_backups()) {
+ return 1;
}
+ if (session) {
+ session->maybe_write_autosave();
+ }
+
return 1;
}
{
ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
- if (session->dirty()) {
+ if (session && session->dirty()) {
if (_autosave_connection.connected()) {
_autosave_connection.disconnect();
}
} else {
if (_autosave_connection.connected()) {
_autosave_connection.disconnect();
- }
+ }
+ }
+}
+
+void
+ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
+{
+ string title;
+ if (we_set_params) {
+ title = _("Ardour could not start JACK");
+ } else {
+ title = _("Ardour could not connect to JACK.");
+ }
+
+ MessageDialog win (title,
+ false,
+ Gtk::MESSAGE_INFO,
+ Gtk::BUTTONS_NONE);
+
+ if (we_set_params) {
+ win.set_secondary_text(_("There are several possible reasons:\n\
+\n\
+1) You requested audio parameters that are not supported..\n\
+2) JACK is running as another user.\n\
+\n\
+Please consider the possibilities, and perhaps try different parameters."));
+ } else {
+ win.set_secondary_text(_("There are several possible reasons:\n\
+\n\
+1) JACK is not running.\n\
+2) JACK is running as another user, perhaps root.\n\
+3) There is already another client called \"ardour\".\n\
+\n\
+Please consider the possibilities, and perhaps (re)start JACK."));
+ }
+
+ if (toplevel) {
+ win.set_transient_for (*toplevel);
}
+
+ if (we_set_params) {
+ win.add_button (Stock::OK, RESPONSE_CLOSE);
+ } else {
+ win.add_button (Stock::QUIT, RESPONSE_CLOSE);
+ }
+
+ win.set_default_response (RESPONSE_CLOSE);
+
+ win.show_all ();
+ win.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash ();
+
+ /* we just don't care about the result, but we want to block */
+
+ win.run ();
}
void
ARDOUR_UI::startup ()
{
- check_memory_locking();
+ XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
+
+ if (audio_setup && _startup && _startup->engine_control()) {
+ _startup->engine_control()->set_state (*audio_setup);
+ }
+
+ if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session)) {
+ exit (1);
+ }
+
+ use_config ();
+
+ goto_editor_window ();
+
+ BootMessage (_("Ardour is ready for use"));
+ show ();
}
void
if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
return;
}
-
+
if (limits.rlim_cur != RLIM_INFINITY) {
if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
-
+
MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
"This might cause Ardour to run out of memory before your system "
"runs out of memory. \n\n"
"You can view the memory limit with 'ulimit -l', "
"and it is normally controlled by /etc/security/limits.conf"));
-
+
VBox* vbox = msg.get_vbox();
HBox hbox;
CheckButton cb (_("Do not show this window again"));
-
+
cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
-
+
hbox.pack_start (cb, true, false);
vbox->pack_start (hbox);
cb.show();
vbox->show();
hbox.show ();
-
+
+ pop_back_splash ();
+
editor->ensure_float (msg);
msg.run ();
}
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) {
+
+ if (session->transport_rolling()) {
+ session->request_stop ();
+ usleep (250000);
+ }
+
+ if (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,
+ _("\
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.run ();
+ return;
+ }
+ break;
+ case 0:
+ break;
}
- break;
- case 0:
- break;
}
- }
- if (session) {
- session->set_deletion_in_progress ();
+ second_connection.disconnect ();
+ point_one_second_connection.disconnect ();
+ point_oh_five_second_connection.disconnect ();
+ point_zero_one_second_connection.disconnect();
+
+ // session->set_deletion_in_progress ();
+ session->remove_pending_capture_state ();
+ delete session;
+ session = 0;
}
+
+ ArdourDialog::close_all_dialogs ();
engine->stop (true);
- Config->save_state();
- ARDOUR_UI::config()->save_state();
+ save_ardour_state ();
quit ();
}
} else {
type = _("snapshot");
}
- 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?"),
+ 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);
prompt_label.show();
dimage->show();
window.show();
-
- save_the_session = 0;
-
window.set_keep_above (true);
window.present ();
return -1;
}
-
+
gint
ARDOUR_UI::every_second ()
{
gint
ARDOUR_UI::every_point_zero_one_seconds ()
{
+ // august 2007: actual update frequency: 40Hz, not 100Hz
+
SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
return TRUE;
}
} else {
nframes_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), _("%.1f kHz / %4.1f ms"),
(float) rate/1000.0f,
(engine->frames_per_cycle() / (float) rate) * 1000.0f);
} else {
- snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
+ snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
rate/1000,
(engine->frames_per_cycle() / (float) rate) * 1000.0f);
}
ARDOUR_UI::update_buffer_load ()
{
char buf[64];
+ uint32_t c, p;
if (session) {
- snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
+ c = session->capture_load ();
+ p = session->playback_load ();
+
+ push_buffer_stats (c, p);
+
+ snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
session->playback_load(), session->capture_load());
buffer_load_label.set_text (buf);
} else {
nframes_t frames = session->available_capture_duration();
char buf[64];
+ nframes_t fr = session->frame_rate();
if (frames == max_frames) {
strcpy (buf, _("Disk: 24hrs+"));
} else {
- int hrs;
- int mins;
- int secs;
- nframes_t fr = session->frame_rate();
-
rec_enabled_streams = 0;
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);
}
disk_space_label.set_text (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 ()
}
gint
-ARDOUR_UI::session_menu (GdkEventButton *ev)
+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)
+ {
+
+ Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
- delete *i2;
+ child_row[recent_session_columns.visible_name] = *i2;
+ child_row[recent_session_columns.fullpath] = fullpath;
}
}
-
- delete states;
}
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.get_selection()->set_mode (SELECTION_BROWSE);
recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
scroller->add (recent_session_display);
}
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;
- }
+ Glib::ustring path = (*i)[recent_session_columns.fullpath];
+ Glib::ustring 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->connected()) {
MessageDialog msg (_("Ardour is not connected to JACK\n"
"You cannot open or close sessions in this condition"));
+ pop_back_splash ();
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);
FileFilter session_filter;
session_filter.add_pattern ("*.ardour");
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)
{
list<boost::shared_ptr<MidiTrack> > tracks;
return;
}
- try {
+ try {
if (disk) {
- tracks = session->new_midi_track (ARDOUR::Normal, how_many);
+ tracks = session->new_midi_track (ARDOUR::Normal, route_group, how_many);
if (tracks.size() != how_many) {
if (how_many == 1) {
}
catch (...) {
- MessageDialog msg (*editor,
+ MessageDialog msg (*editor,
_("There are insufficient JACK ports available\n\
to create a new track or bus.\n\
You should save Ardour, exit and\n\
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, bool aux, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
{
list<boost::shared_ptr<AudioTrack> > tracks;
- Session::RouteList routes;
+ RouteList routes;
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);
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 (aux, input_channels, output_channels, route_group, how_many);
if (routes.size() != how_many) {
if (how_many == 1) {
}
}
}
-
+
#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);
}
}
catch (...) {
- cerr << "About to complain about JACK\n";
- MessageDialog msg (*editor,
+ MessageDialog msg (*editor,
_("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."));
+ pop_back_splash ();
msg.run ();
}
}
if (session) {
session->goto_start();
-
/* 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->center_screen (session->current_start_frame ());
}
}
}
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 (0);
}
}
}
+void
+ARDOUR_UI::transport_goto_wallclock ()
+{
+ if (session && editor) {
+
+ time_t now;
+ struct tm tmnow;
+ nframes64_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);
+
+ /* force displayed area in editor to start no matter
+ what "follow playhead" setting is.
+ */
+
+ if (editor) {
+ editor->center_screen (frames);
+ }
+ }
+}
+
void
ARDOUR_UI::transport_goto_end ()
{
if (session) {
- nframes_t frame = session->current_end_frame();
+ nframes_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);
}
}
}
session->cancel_audition ();
return;
}
-
- if (session->get_play_loop ()) {
- session->request_play_loop (false);
- }
-
+
session->request_stop ();
}
}
void
-ARDOUR_UI::transport_record ()
+ARDOUR_UI::transport_record (bool roll)
{
+
if (session) {
switch (session->record_status()) {
case Session::Disabled:
return;
}
session->maybe_enable_record ();
+ if (roll) {
+ transport_roll ();
+ }
break;
case Session::Recording:
+ if (roll) {
+ session->request_stop();
+ } else {
+ session->disable_record (false, true);
+ }
+ break;
+
case Session::Enabled:
session->disable_record (false, true);
}
}
+ //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
}
-void
+void
ARDOUR_UI::transport_roll ()
{
- bool rolling;
-
if (!session) {
return;
}
- rolling = session->transport_rolling ();
+ if (session->is_auditioning()) {
+ 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();
if (session->get_play_loop()) {
- session->request_play_loop (false);
- auto_loop_button.set_visual_state (1);
- roll_button.set_visual_state (1);
+ session->request_play_loop (false, true);
} 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);
+ session->request_play_range (false, true);
+ }
+
+ if (!rolling) {
+ session->request_transport_speed (1.0f);
+ }
+
+ map_transport_state ();
+}
+
+void
+ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
+{
+
+ 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);
+ }
+ }
+
+ if (affect_transport) {
+ if (rolling) {
+ session->request_stop (with_abort, true);
+ } else {
+ session->request_transport_speed (1.0f);
+ }
}
- session->request_transport_speed (1.0f);
+ map_transport_state ();
}
void
-ARDOUR_UI::transport_loop()
+ARDOUR_UI::toggle_session_auto_loop ()
{
if (session) {
if (session->get_play_loop()) {
if (looploc) {
session->request_locate (looploc->start(), true);
}
+ } else {
+ session->request_play_loop (false);
+ }
+ } else {
+ Location * looploc = session->locations()->auto_loop_location();
+ if (looploc) {
+ session->request_play_loop (true);
}
- }
- else {
- session->request_play_loop (true);
}
}
}
return;
}
- if (!session->get_play_range()) {
- session->request_stop ();
- }
-
editor->play_selection ();
}
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:
ARDOUR_UI::transport_forward (int option)
{
float current_transport_speed;
-
+
if (session) {
current_transport_speed = session->transport_speed();
-
+
if (current_transport_speed <= 0.0f) {
switch (option) {
case 0:
/* speed up */
session->request_transport_speed (current_transport_speed * 1.5f);
}
+
}
}
}
boost::shared_ptr<Route> r;
-
+
if ((r = session->route_by_remote_id (dstream)) != 0) {
Track* t;
}
}
-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 ()
{
+ ENSURE_GUI_THREAD(mem_fun (*this, &ARDOUR_UI::map_transport_state));
+
+ if (!session) {
+ auto_loop_button.set_visual_state (0);
+ play_selection_button.set_visual_state (0);
+ roll_button.set_visual_state (0);
+ stop_button.set_visual_state (1);
+ return;
+ }
+
float sp = session->transport_speed();
if (sp == 1.0f) {
- transport_rolling ();
- } else if (sp < 0.0f) {
- transport_rewinding ();
- } else if (sp > 0.0f) {
- transport_forwarding ();
+ shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
+ shuttle_box.queue_draw ();
+ } else if (sp == 0.0f) {
+ shuttle_fract = 0;
+ shuttle_box.queue_draw ();
+ update_disk_space ();
+ }
+
+ if (sp != 0.0) {
+
+ if (session->get_play_range()) {
+
+ play_selection_button.set_visual_state (1);
+ roll_button.set_visual_state (0);
+ auto_loop_button.set_visual_state (0);
+
+ } else if (session->get_play_loop ()) {
+
+ auto_loop_button.set_visual_state (1);
+ play_selection_button.set_visual_state (0);
+ roll_button.set_visual_state (0);
+
+ } else {
+
+ roll_button.set_visual_state (1);
+ play_selection_button.set_visual_state (0);
+ auto_loop_button.set_visual_state (0);
+ }
+
+ stop_button.set_visual_state (0);
+
} else {
- transport_stopped ();
+
+ stop_button.set_visual_state (1);
+ roll_button.set_visual_state (0);
+ play_selection_button.set_visual_state (0);
+ auto_loop_button.set_visual_state (0);
}
-}
-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());
}
void
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 ();
update_sample_rate (0);
- MessageDialog msg (*editor,
+ MessageDialog msg (*editor,
_("\
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 ."));
+was not fast enough. Try to restart\n\
+JACK, reconnect and save the session."));
+ pop_back_splash ();
msg.run ();
}
int32_t
ARDOUR_UI::do_engine_start ()
{
- try {
+ try {
engine->start();
}
unload_session ();
return -2;
}
-
+
return 0;
}
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;
-}
-
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 */
}
}
{
clock_signal_connection.disconnect ();
}
-
+
void
ARDOUR_UI::toggle_clocking ()
{
*/
if (blink_timeout_tag < 0) {
- blink_on = false;
+ blink_on = false;
blink_timeout_tag = g_timeout_add (240, _blink, this);
}
}
}
}
-void
-ARDOUR_UI::name_io_setup (AudioEngine& engine,
- string& buf,
- IO& io,
- bool in)
-{
- if (in) {
- if (io.n_inputs().n_total() == 0) {
- buf = _("none");
- return;
- }
-
- /* XXX we're not handling multiple ports yet. */
-
- const char **connections = io.input(0)->get_connections();
-
- if (connections == 0 || connections[0] == '\0') {
- buf = _("off");
- } else {
- buf = connections[0];
- }
-
- free (connections);
-
- } else {
-
- if (io.n_outputs().n_total() == 0) {
- buf = _("none");
- return;
- }
-
- /* 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];
- }
-
- free (connections);
- }
-}
/** Ask the user for the name of a new shapshot and then take it.
*/
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"));
prompter.set_initial_text (timebuf);
-
+
switch (prompter.run()) {
case RESPONSE_ACCEPT:
+ {
prompter.get_result (snapname);
- if (snapname.length()){
+
+ bool do_save = (snapname.length() != 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;
+ }
+ }
+
+ if (do_save) {
save_state (snapname);
}
break;
+ }
default:
break;
{
(void) save_state_canfail (name);
}
-
+
int
ARDOUR_UI::save_state_canfail (string name)
{
}
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);
+ 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 ());
+ session->request_locate (big_clock.current_time ());
}
}
}
void
-ARDOUR_UI::rec_enable_button_blink (bool onoff, AudioDiskstream *dstream, Widget *w)
-{
- 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);
- }
- }
-}
-
-void
-ARDOUR_UI::transport_rec_enable_blink (bool onoff)
+ARDOUR_UI::transport_rec_enable_blink (bool onoff)
{
if (session == 0) {
return;
}
-
- switch (session->record_status()) {
- case Session::Enabled:
+
+ Session::RecordState const r = session->record_status ();
+ bool const h = session->have_rec_enabled_diskstream ();
+
+ if (r == Session::Enabled || (r == Session::Recording && !h)) {
if (onoff) {
rec_button.set_visual_state (2);
} else {
rec_button.set_visual_state (0);
}
- break;
-
- case Session::Recording:
+ } else if (r == Session::Recording && h) {
rec_button.set_visual_state (1);
- break;
-
- default:
+ } else {
rec_button.set_visual_state (0);
- break;
}
}
-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_title (_("Save Mix Template"));
prompter.set_prompt (_("Name for mix 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);
}
}
}
-bool
-ARDOUR_UI::new_session (std::string predetermined_path)
+void
+ARDOUR_UI::edit_metadata ()
{
- string session_name;
- string session_path;
+ SessionMetadataEditor dialog;
+ dialog.set_session (session);
+ editor->ensure_float (dialog);
+ dialog.run ();
+}
- if (!check_audioengine()) {
+void
+ARDOUR_UI::import_metadata ()
+{
+ SessionMetadataImporter dialog;
+ dialog.set_session (session);
+ editor->ensure_float (dialog);
+ dialog.run ();
+}
+
+void
+ARDOUR_UI::fontconfig_dialog ()
+{
+#ifdef GTKOSX
+ /* X11 users will always have fontconfig info around, but new GTK-OSX users
+ may not and it can take a while to build it. Warn them.
+ */
+
+ Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
+
+ if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
+ MessageDialog msg (*_startup,
+ _("Welcome to Ardour.\n\n"
+ "The program will take a bit longer to start up\n"
+ "while the system fonts are checked.\n\n"
+ "This will only be done once, and you will\n"
+ "not see this message again\n"),
+ true,
+ Gtk::MESSAGE_INFO,
+ Gtk::BUTTONS_OK);
+ pop_back_splash ();
+ msg.show_all ();
+ msg.present ();
+ msg.run ();
+ }
+#endif
+}
+
+void
+ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
+{
+ existing_session = false;
+
+ if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
+ session_path = cmdline_path;
+ existing_session = true;
+ } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
+ session_path = Glib::path_get_dirname (string (cmdline_path));
+ existing_session = true;
+ } else {
+ /* it doesn't exist, assume the best */
+ session_path = Glib::path_get_dirname (string (cmdline_path));
+ }
+
+ session_name = basename_nosuffix (string (cmdline_path));
+}
+
+int
+ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
+{
+ /* when this is called, the backend audio system must be running */
+
+ /* the main idea here is to deal with the fact that a cmdline argument for the session
+ can be interpreted in different ways - it could be a directory or a file, and before
+ we load, we need to know both the session directory and the snapshot (statefile) within it
+ that we are supposed to use.
+ */
+
+ if (session_name.length() == 0 || session_path.length() == 0) {
return false;
}
- int response = Gtk::RESPONSE_NONE;
+ if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
- 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);
+ Glib::ustring predicted_session_file;
- do {
- response = new_session_dialog->run ();
+ predicted_session_file = session_path;
+ predicted_session_file += '/';
+ predicted_session_file += session_name;
+ predicted_session_file += ARDOUR::statefile_suffix;
- if (!check_audioengine()) {
- new_session_dialog->hide ();
- return false;
+ if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
+ existing_session = true;
}
- _session_is_new = false;
+ } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
- if (response == Gtk::RESPONSE_CANCEL || response == Gtk::RESPONSE_DELETE_EVENT) {
+ if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
+ /* existing .ardour file */
+ existing_session = true;
+ }
- if (!session) {
- quit();
- }
- new_session_dialog->hide ();
- return false;
+ } else {
+ existing_session = false;
+ }
+
+ /* lets just try to load it */
+
+ if (create_engine ()) {
+ backend_audio_error (false, _startup);
+ return -1;
+ }
+
+ return load_session (session_path, session_name);
+}
- } else if (response == Gtk::RESPONSE_NONE) {
+bool
+ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
+{
+ Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
- /* Clear was pressed */
- new_session_dialog->reset();
+ MessageDialog msg (str,
+ false,
+ Gtk::MESSAGE_WARNING,
+ Gtk::BUTTONS_YES_NO,
+ true);
- } else if (response == Gtk::RESPONSE_YES) {
- /* YES == OPEN, but there's no enum for that */
+ msg.set_name (X_("OpenExistingDialog"));
+ msg.set_title (_("Open Existing Session"));
+ msg.set_wmclass (X_("existing_session"), "Ardour");
+ msg.set_position (Gtk::WIN_POS_MOUSE);
+ pop_back_splash ();
- session_name = new_session_dialog->session_name();
+ switch (msg.run()) {
+ case RESPONSE_YES:
+ return true;
+ break;
+ }
+ return false;
+}
- if (session_name.empty()) {
- response = Gtk::RESPONSE_NONE;
- continue;
- }
+int
+ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
+{
- 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);
+ uint32_t cchns;
+ uint32_t mchns;
+ AutoConnectOption iconnect;
+ AutoConnectOption oconnect;
+ uint32_t nphysin;
+ uint32_t nphysout;
+
+ if (Profile->get_sae()) {
+
+ cchns = 0;
+ mchns = 2;
+ iconnect = AutoConnectPhysical;
+ oconnect = AutoConnectMaster;
+ nphysin = 0; // use all available
+ nphysout = 0; // use all available
+
+ } else {
+
+ /* get settings from advanced section of NSD */
+
+ if (_startup->create_control_bus()) {
+ cchns = (uint32_t) _startup->control_channel_count();
+ } else {
+ cchns = 0;
+ }
+
+ if (_startup->create_master_bus()) {
+ mchns = (uint32_t) _startup->master_channel_count();
+ } else {
+ mchns = 0;
+ }
+
+ if (_startup->connect_inputs()) {
+ iconnect = AutoConnectPhysical;
+ } else {
+ iconnect = AutoConnectOption (0);
+ }
+
+ /// @todo some minor tweaks.
+
+ oconnect = AutoConnectOption (0);
+
+ if (_startup->connect_outputs ()) {
+ if (_startup->connect_outs_to_master()) {
+ oconnect = AutoConnectMaster;
+ } else if (_startup->connect_outs_to_physical()) {
+ oconnect = AutoConnectPhysical;
}
+ }
- } else if (response == Gtk::RESPONSE_OK) {
+ nphysin = (uint32_t) _startup->input_limit_count();
+ nphysout = (uint32_t) _startup->output_limit_count();
+ }
- session_name = new_session_dialog->session_name();
+ if (build_session (session_path,
+ session_name,
+ cchns,
+ mchns,
+ iconnect,
+ oconnect,
+ nphysin,
+ nphysout,
+ engine->frame_rate() * 60 * 5)) {
- if (!new_session_dialog->on_new_session_page ()) {
+ return -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..
- */
+ return 0;
+}
- if (session_name.empty()) {
- response = Gtk::RESPONSE_NONE;
- continue;
- }
+void
+ARDOUR_UI::idle_load (const Glib::ustring& 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 {
- 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);
- }
+ ARDOUR_COMMAND_LINE::session_name = path;
- } else {
+ /*
+ * 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.empty()) {
- response = Gtk::RESPONSE_NONE;
- continue;
- }
+ //if (new_session_dialog) {
- 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_path = Glib::path_get_dirname (session_name);
- session_name = Glib::path_get_basename (session_name);
+ /* make it break out of Dialog::run() and
+ start again.
+ */
- } else {
+ //new_session_dialog->response (1);
+ //}
+ }
+}
- session_path = new_session_dialog->session_folder();
+void
+ARDOUR_UI::end_loading_messages ()
+{
+ // hide_splash ();
+}
- }
+void
+ARDOUR_UI::loading_message (const std::string& /*msg*/)
+{
+ // show_splash ();
+ // splash->message (msg);
+ flush_pending ();
+}
- //XXX This is needed because session constructor wants a
- //non-existant path. hopefully this will be fixed at some point.
+/** @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)
+{
+ Glib::ustring session_name;
+ Glib::ustring session_path;
+ Glib::ustring template_name;
+ int ret = -1;
+ bool likely_new = false;
- session_path = Glib::build_filename (session_path, session_name);
+ while (ret != 0) {
- if (g_file_test (session_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
+ if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
- Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
+ /* 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.
+ */
- MessageDialog msg (str,
- false,
- Gtk::MESSAGE_WARNING,
- Gtk::BUTTONS_YES_NO,
- true);
+ if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
+ session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
+ } else {
+ session_path = ARDOUR_COMMAND_LINE::session_name;
+ }
+ session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
- msg.set_name (X_("CleanupDialog"));
- msg.set_wmclass (X_("existing_session"), "Ardour");
- msg.set_position (Gtk::WIN_POS_MOUSE);
+ } else {
- switch (msg.run()) {
- case RESPONSE_YES:
- load_session (session_path, session_name);
- goto done;
- break;
- default:
- response = RESPONSE_NONE;
- new_session_dialog->reset ();
- continue;
- }
+ bool const apply = run_startup (should_be_new);
+ if (!apply) {
+ if (quit_on_cancel) {
+ exit (1);
+ } else {
+ return ret;
}
+ }
+
+ /* if we run the startup dialog again, offer more than just "new session" */
+
+ should_be_new = false;
+
+ session_name = _startup->session_name (likely_new);
+
+ /* this shouldn't happen, but we catch it just in case it does */
+ if (session_name.empty()) {
+ break;
+ }
+ if (_startup->use_session_template()) {
+ template_name = _startup->session_template_name();
_session_is_new = true;
+ }
- std::string template_name = new_session_dialog->session_template_name();
+ 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] == '/')) {
- if (new_session_dialog->use_session_template()) {
+ session_path = Glib::path_get_dirname (session_name);
+ session_name = Glib::path_get_basename (session_name);
- load_session (session_path, session_name, &template_name);
+ } else {
- } else {
+ session_path = _startup->session_folder();
+ }
+ }
+
+ if (create_engine ()) {
+ break;
+ }
+
+ if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
+
+ if (likely_new) {
- 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;
- }
+ Glib::ustring existing = Glib::build_filename (session_path, session_name);
+
+ if (!ask_about_loading_existing_session (existing)) {
+ ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
+ continue;
}
}
+
+ _session_is_new = false;
+
+ } else {
+
+ if (!likely_new) {
+ MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
+ 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 {
- done:
- show();
- new_session_dialog->get_window()->set_cursor();
- new_session_dialog->hide();
- return true;
+ ret = load_session (session_path, session_name, template_name);
+ 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 ();
+ unload_session (true);
+
+ ARDOUR_COMMAND_LINE::session_name = "";
+ get_session_parameters (true, false);
}
int
-ARDOUR_UI::load_session (const string & path, const string & snap_name, string* mix_template)
+ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
{
Session *new_session;
+ int unload_status;
+ int retval = -1;
+
session_loaded = false;
-
+
if (!check_audioengine()) {
return -1;
}
- 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 (_("Please wait while Ardour loads your session"));
+
try {
new_session = new Session (*engine, path, snap_name, 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.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,
+ Gtk::BUTTONS_CLOSE);
+
+ msg.set_title (_("Loading Error"));
+ msg.set_secondary_text (_("Click the Close button to try again."));
+ msg.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash ();
+ msg.present ();
+
+ int response = msg.run ();
+
+ msg.hide ();
+
+ switch (response) {
+ case RESPONSE_CANCEL:
+ exit (1);
+ default:
+ break;
+ }
+ goto out;
}
connect_to_session (new_session);
- Config->set_current_owner (ConfigVariableBase::Interface);
-
session_loaded = true;
-
+
goto_editor_window ();
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,
+int
+ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
uint32_t control_channels,
- uint32_t master_channels,
+ uint32_t master_channels,
AutoConnectOption input_connect,
AutoConnectOption output_connect,
uint32_t nphysin,
nframes_t initial_length)
{
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 {
catch (...) {
MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
+ pop_back_splash ();
msg.run ();
- return false;
+ return -1;
}
connect_to_session (new_session);
session_loaded = true;
- return true;
+
+ new_session->save_state(new_session->name());
+
+ return 0;
}
void
{
if (editor) {
editor->show_window ();
-
+
if (!shown_flag) {
editor->present ();
}
}
void
-ARDOUR_UI::show_splash ()
+ARDOUR_UI::show_about ()
{
if (about == 0) {
- about = new About();
+ about = new About;
about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
}
- about->present();
- flush_pending ();
+
+ about->show_all ();
}
void
-ARDOUR_UI::about_signal_response(int response)
+ARDOUR_UI::hide_about ()
{
- hide_splash();
+ if (about) {
+ about->get_window()->set_cursor ();
+ about->hide ();
+ }
+}
+
+void
+ARDOUR_UI::about_signal_response (int /*response*/)
+{
+ hide_about();
+}
+
+void
+ARDOUR_UI::show_splash ()
+{
+ if (splash == 0) {
+ try {
+ splash = new Splash;
+ } catch (...) {
+ return;
+ }
+ }
+
+ splash->show ();
+ splash->present ();
+ 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 audio files were ready for cleanup"),
true,
Gtk::MESSAGE_INFO,
(Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
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 (_("ardour: cleanup"), true, false);
-
+
struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
- CleanupResultsModelColumns() {
+ CleanupResultsModelColumns() {
add (visible_name);
add (fullpath);
}
Gtk::TreeModelColumn<Glib::ustring> 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);
const string dead_sound_directory = session->session_directory().dead_sound_path().to_string();
+
+
+
+ /* subst:
+ %1 - number of files removed
+ %2 - location of "dead_sounds"
+ %3 - size of files affected
+ %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
+ */
+
+ const char* bprefix;
+
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"));
- }
+ bprefix = X_("kilo");
+ } else if (rep.space < 1048576.0f * 1000) {
+ bprefix = X_("mega");
} 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");
+ }
+
+ if (removed > 1) {
+ txt.set_text (string_compose (plural_msg, removed, dead_sound_directory, (float) rep.space / 1024.0f, bprefix));
+ } else {
+ txt.set_text (string_compose (singular_msg, removed, dead_sound_directory, (float) rep.space / 1024.0f, bprefix));
}
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);
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.set_default_response (RESPONSE_CANCEL);
return;
}
- Session::cleanup_report rep;
+ ARDOUR::CleanupReport rep;
editor->prepare_for_cleanup ();
}
if (session->cleanup_sources (rep)) {
+ editor->finish_cleanup ();
return;
}
+ editor->finish_cleanup ();
+
checker.hide();
- display_cleanup_results (rep,
+ display_cleanup_results (rep,
_("cleaned files"),
_("\
-The following %1 %2 not in use and \n\
+The following %1 files were not in use and \n\
have been moved to:\n\
-%3. \n\n\
+%2. \n\n\
+Flushing the wastebasket will \n\
+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\
Flushing the wastebasket will \n\
release an additional\n\
-%4 %5bytes of disk space.\n"
+%3 %4bytes of disk space.\n"
));
-
-
}
void
return;
}
- Session::cleanup_report rep;
+ ARDOUR::CleanupReport 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
}
if (add_route_dialog == 0) {
- add_route_dialog = new AddRouteDialog;
+ add_route_dialog = new AddRouteDialog (*session);
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 ();
+ bool aux = !track && add_route_dialog->aux();
+ RouteGroup* route_group = add_route_dialog->route_group ();
AutoConnectOption oac = Config->get_output_auto_connect();
if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
if (track) {
- session_add_midi_track(count);
+ session_add_midi_track (route_group, count);
} else {
MessageDialog msg (*editor,
_("Sorry, MIDI Busses are not supported at this time."));
msg.run ();
//session_add_midi_bus();
}
- } else {
+ } else {
if (track) {
- session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
+ session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
} else {
- session_add_audio_bus (input_chan, output_chan, count);
+ session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
}
}
}
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"));
}
}
void
-ARDOUR_UI::halt_on_xrun_message ()
+ARDOUR_UI::create_xrun_marker(nframes_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(nframes_t where)
+{
+ if (!session) {
+ return;
+ }
+
+ ENSURE_GUI_THREAD (bind(mem_fun(*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::push_buffer_stats (uint32_t capture, uint32_t playback)
+{
+ time_t now;
+ time (&now);
+
+ while (disk_buffer_stats.size() > 60) {
+ disk_buffer_stats.pop_front ();
+ }
+
+ disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
+}
+
+void
+ARDOUR_UI::write_buffer_stats ()
+{
+
+ std::ofstream fout;
+ struct tm tm;
+ char buf[64];
+ char path[PATH_MAX+1]; int fd;
+
+ strcpy (path, "ardourBufferingXXXXXX");
+
+ if ((fd = mkstemp (path )) < 0) {
+ cerr << X_("cannot find temporary name for ardour buffer stats") << endl;
+ return;
+ }
+
+ fout.open (path);
+ close (fd);
+
+ if (!fout) {
+ cerr << string_compose (X_("cannot open file %1 for ardour buffer stats"), path) << endl;
+ return;
+ }
+
+ for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
+ localtime_r (&(*i).when, &tm);
+ strftime (buf, sizeof (buf), "%T", &tm);
+ fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
+ }
+
+ disk_buffer_stats.clear ();
+
+ fout.close ();
+
+ cerr << "Ardour buffering statistics can be found in: " << path << endl;
+}
+
void
ARDOUR_UI::disk_overrun_handler ()
{
ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
+ write_buffer_stats ();
+
if (!have_disk_speed_dialog_displayed) {
have_disk_speed_dialog_displayed = true;
MessageDialog* msg = new MessageDialog (*editor, _("\
{
ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
+ write_buffer_stats ();
+
if (!have_disk_speed_dialog_displayed) {
have_disk_speed_dialog_displayed = true;
MessageDialog* msg = new MessageDialog (*editor,
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 ();
- }
+ }
}
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 (bind (mem_fun(*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);
message.show();
- //dialog.get_vbox()->show();
-
+ image->show();
+ hbox->show();
+
switch (dialog.run ()) {
case RESPONSE_ACCEPT:
return 1;
return 0;
}
}
-
+
+int
+ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_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) {
ARDOUR_UI::update_transport_clocks (nframes_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(), 1);
} else {
primary_clock.set (pos, 0, true);
}
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(), 2);
} else {
secondary_clock.set (pos);
}
return;
}
- switch (session->record_status()) {
- case Session::Recording:
+ Session::RecordState const r = session->record_status ();
+ bool const h = session->have_rec_enabled_diskstream ();
+
+ if (r == Session::Recording && h) {
big_clock.set_widget_name ("BigClockRecording");
- break;
- default:
+ } else {
big_clock.set_widget_name ("BigClockNonRecording");
- break;
}
}
-void
-ARDOUR_UI::set_keybindings_path (string path)
-{
- keybindings_path = path;
-}
-
-void
-ARDOUR_UI::save_keybindings ()
-{
- if (can_save_keybindings) {
- AccelMap::save (keybindings_path);
- }
-}
-
bool
ARDOUR_UI::first_idle ()
{
if (session) {
session->allow_auto_play (true);
}
- can_save_keybindings = true;
+
+ if (editor) {
+ editor->first_idle();
+ }
+
+ Keyboard::set_can_save_keybindings (true);
return false;
}
}
-
+
ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
: Controllable (name), ui (u), type(tp)
{
-
+
}
void
fract = ((val - 0.5f)/0.5f);
}
}
-
+
ui.set_shuttle_fract (fract);
return;
}
return;
}
- char *action = 0;
+ const char *action = 0;
switch (type) {
case Roll:
ARDOUR_UI::TransportControllable::get_value (void) const
{
float val = 0.0f;
-
+
switch (type) {
case Roll:
break;
if (gdk_screen_width() < 1200) {
Profile->set_small_screen ();
}
-}
-
-void
-ARDOUR_UI::disable_all_plugins ()
-{
- if (!session) {
- return;
- }
- // session->begin_reversible_command (_("Disable all plugins"));
- boost::shared_ptr<Session::RouteList> routes = session->get_routes ();
-
- 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 (getenv ("ARDOUR_SAE")) {
+ Profile->set_sae ();
+ Profile->set_single_package ();
}
-
- // session->commit_reversible_command ();
}
-void
-ARDOUR_UI::ab_all_plugins ()
-{
- if (!session) {
- return;
- }
-
- boost::shared_ptr<Session::RouteList> routes = session->get_routes ();
-
- for (Session::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
- (*i)->ab_plugins (ab_direction);
- }
-
- ab_direction = !ab_direction;
-}