From 914ba475de48f72e57bb6ac8a81888ad71cea7fa Mon Sep 17 00:00:00 2001 From: nick_m Date: Wed, 18 Sep 2013 02:02:31 +1000 Subject: [PATCH 01/42] actually load new state after creating a session. --- libs/ardour/session.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 746732f76e..b2b98e7b8c 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -276,6 +276,10 @@ Session::Session (AudioEngine &eng, throw failed_constructor (); } + if (load_state (_current_snapshot_name)) { + throw failed_constructor (); + } + } else { if (load_state (_current_snapshot_name)) { From 20fa19e69e176aa3c0a1ed8e6688acec0799daad Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 17 Sep 2013 22:25:21 -0400 Subject: [PATCH 02/42] more excision of "JACK" from labels, menu items, etc. NOTE: users will lose the sample rate/latency display in the status bar display. Not yet sure what to do about this --- gtk2_ardour/ardour_ui.cc | 67 +++++++-------------------------- gtk2_ardour/ardour_ui.h | 2 - gtk2_ardour/ardour_ui_ed.cc | 56 +-------------------------- gtk2_ardour/keyeditor.cc | 2 - gtk2_ardour/main.cc | 11 +----- gtk2_ardour/mixer_strip.cc | 4 +- gtk2_ardour/processor_box.cc | 2 +- gtk2_ardour/rc_option_editor.cc | 6 +-- 8 files changed, 21 insertions(+), 129 deletions(-) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index eccd37fec2..74e2768b41 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -399,61 +399,19 @@ ARDOUR_UI::engine_stopped () void ARDOUR_UI::engine_running () { + cerr << "ENGINE RUNNING\n"; + if (first_time_engine_run) { post_engine(); first_time_engine_run = false; + } else { + cerr << "AGAIN...\n"; } - ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true); - ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false); - - Glib::RefPtr action; - const char* action_name = 0; - - switch (AudioEngine::instance()->samples_per_cycle()) { - case 32: - action_name = X_("JACKLatency32"); - break; - case 64: - action_name = X_("JACKLatency64"); - break; - case 128: - action_name = X_("JACKLatency128"); - break; - case 512: - action_name = X_("JACKLatency512"); - break; - case 1024: - action_name = X_("JACKLatency1024"); - break; - case 2048: - action_name = X_("JACKLatency2048"); - break; - case 4096: - action_name = X_("JACKLatency4096"); - break; - case 8192: - action_name = X_("JACKLatency8192"); - break; - default: - /* XXX can we do anything useful ? */ - break; - } - - if (action_name) { - - action = ActionManager::get_action (X_("JACK"), action_name); - - if (action) { - Glib::RefPtr ract = Glib::RefPtr::cast_dynamic (action); - ract->set_active (); - } - - update_disk_space (); - update_cpu_load (); - update_sample_rate (AudioEngine::instance()->sample_rate()); - update_timecode_format (); - } + update_disk_space (); + update_cpu_load (); + update_sample_rate (AudioEngine::instance()->sample_rate()); + update_timecode_format (); } void @@ -481,13 +439,13 @@ ARDOUR_UI::engine_halted (const char* reason, bool free_reason) */ if (strlen (reason)) { - msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason); + msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason); } else { msgstr = string_compose (_("\ -JACK has either been shutdown or it\n\ +`The audio backend has either been shutdown or it\n\ disconnected %1 because %1\n\ was not fast enough. Try to restart\n\ -JACK, reconnect and save the session."), PROGRAM_NAME); +the audio backend and save the session."), PROGRAM_NAME); } MessageDialog msg (*editor, msgstr); @@ -1126,6 +1084,8 @@ ARDOUR_UI::update_sample_rate (framecnt_t) { char buf[64]; + cerr << "USR\n"; + ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored) if (!AudioEngine::instance()->connected()) { @@ -1152,6 +1112,7 @@ ARDOUR_UI::update_sample_rate (framecnt_t) } } } + cerr << "SRL = " << buf << endl; sample_rate_label.set_markup (buf); } diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index c84a279320..ea03c8590f 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -670,8 +670,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr int pending_state_dialog (); int sr_mismatch_dialog (ARDOUR::framecnt_t, ARDOUR::framecnt_t); - void set_engine_buffer_size (ARDOUR::pframes_t); - Gtk::MenuItem* jack_disconnect_item; Gtk::MenuItem* jack_reconnect_item; Gtk::Menu* jack_bufsize_menu; diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index b64498fb33..96bbd8c4e3 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -396,60 +396,6 @@ ARDOUR_UI::install_actions () ActionManager::add_action_group (midi_actions); } -void -ARDOUR_UI::set_engine_buffer_size (pframes_t nframes) -{ - Glib::RefPtr action; - const char* action_name = 0; - - switch (nframes) { - case 32: - action_name = X_("EngineLatency32"); - break; - case 64: - action_name = X_("EngineLatency64"); - break; - case 128: - action_name = X_("EngineLatency128"); - break; - case 256: - action_name = X_("EngineLatency256"); - break; - case 512: - action_name = X_("EngineLatency512"); - break; - case 1024: - action_name = X_("EngineLatency1024"); - break; - case 2048: - action_name = X_("EngineLatency2048"); - break; - case 4096: - action_name = X_("EngineLatency4096"); - break; - case 8192: - action_name = X_("EngineLatency8192"); - break; - default: - /* XXX can we do anything useful ? */ - break; - } - - if (action_name) { - - action = ActionManager::get_action (X_("JACK"), action_name); - - if (action) { - Glib::RefPtr ract = Glib::RefPtr::cast_dynamic (action); - - if (ract && ract->get_active()) { - AudioEngine::instance()->request_buffer_size (nframes); - update_sample_rate (0); - } - } - } -} - void ARDOUR_UI::build_menu_bar () { @@ -528,7 +474,7 @@ ARDOUR_UI::build_menu_bar () _status_bar_visibility.add (&disk_space_label, X_("Disk"), _("Disk Space"), disk_space); _status_bar_visibility.add (&cpu_load_label, X_("DSP"), _("DSP"), true); _status_bar_visibility.add (&buffer_load_label, X_("Buffers"), _("Buffers"), true); - _status_bar_visibility.add (&sample_rate_label, X_("JACK"), _("JACK Sampling Rate and Latency"), true); + _status_bar_visibility.add (&sample_rate_label, X_("Audio"), _("Audio"), true); _status_bar_visibility.add (&timecode_format_label, X_("TCFormat"), _("Timecode Format"), true); _status_bar_visibility.add (&format_label, X_("Format"), _("File Format"), true); diff --git a/gtk2_ardour/keyeditor.cc b/gtk2_ardour/keyeditor.cc index 07042a1cdf..f23e246958 100644 --- a/gtk2_ardour/keyeditor.cc +++ b/gtk2_ardour/keyeditor.cc @@ -250,8 +250,6 @@ KeyEditor::populate () //kinda kludgy way to avoid displaying menu items as mappable if ( parts[1] == _("Main_menu") ) continue; - if ( parts[1] == _("JACK") ) - continue; if ( parts[1] == _("redirectmenu") ) continue; if ( parts[1] == _("Editor_menus") ) diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc index c8f8d76a98..a7497f96fb 100644 --- a/gtk2_ardour/main.cc +++ b/gtk2_ardour/main.cc @@ -36,8 +36,6 @@ #include "pbd/boost_debug.h" #endif -#include - #include "ardour/revision.h" #include "ardour/version.h" #include "ardour/ardour.h" @@ -80,17 +78,10 @@ static const char* localedir = LOCALEDIR; void gui_jack_error () { - MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME), + MessageDialog win (string_compose (_("%1 could not connect to the audio backend."), PROGRAM_NAME), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE); - win.set_secondary_text(string_compose (_("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 \"%1\".\n\ -\n\ -Please consider the possibilities, and perhaps (re)start JACK."), PROGRAM_NAME)); win.add_button (Stock::QUIT, RESPONSE_CLOSE); win.set_default_response (RESPONSE_CLOSE); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index d77023d201..50594378de 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -698,7 +698,7 @@ MixerStrip::output_press (GdkEventButton *ev) { using namespace Menu_Helpers; if (!_session->engine().connected()) { - MessageDialog msg (_("Not connected to JACK - no I/O changes are possible")); + MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible")); msg.run (); return true; } @@ -826,7 +826,7 @@ MixerStrip::input_press (GdkEventButton *ev) citems.clear(); if (!_session->engine().connected()) { - MessageDialog msg (_("Not connected to JACK - no I/O changes are possible")); + MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible")); msg.run (); return true; } diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index d475e28605..17f548c0e3 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -2151,7 +2151,7 @@ ProcessorBox::get_editor_window (boost::shared_ptr processor, bool us } else if ((port_insert = boost::dynamic_pointer_cast (processor)) != 0) { if (!_session->engine().connected()) { - MessageDialog msg ( _("Not connected to JACK - no I/O changes are possible")); + MessageDialog msg ( _("Not connected to audio engine - no I/O changes are possible")); msg.run (); return 0; } diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index ed9ffda4ef..f9336cee31 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -1146,7 +1146,7 @@ RCOptionEditor::RCOptionEditor () tsf = new BoolOption ( "seamless-loop", - _("Do seamless looping (not possible when slaved to MTC, JACK etc)"), + _("Do seamless looping (not possible when slaved to MTC, LTC etc)"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop), sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop) ); @@ -1464,12 +1464,10 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model) ); -#ifndef __APPLE__ - /* no JACK monitoring on CoreAudio */ if (AudioEngine::instance()->port_engine().can_monitor_input()) { mm->add (HardwareMonitoring, _("via Audio Driver")); } -#endif + mm->add (SoftwareMonitoring, _("ardour")); mm->add (ExternalMonitoring, _("audio hardware")); From 57d24608e7e92f1f97332fc87921218c4f9fc8ec Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 19 Sep 2013 15:03:20 -0400 Subject: [PATCH 03/42] show a different audio/MIDI option screen if JACK is already running. try to fix problem with using AudioBackend::() functions before anything has been set. --- gtk2_ardour/ardour_ui.cc | 10 +- gtk2_ardour/engine_dialog.cc | 759 +++++++++++++++--------- gtk2_ardour/engine_dialog.h | 21 +- libs/backends/jack/jack_audiobackend.cc | 1 + 4 files changed, 507 insertions(+), 284 deletions(-) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 74e2768b41..f22b48bd3a 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -399,14 +399,10 @@ ARDOUR_UI::engine_stopped () void ARDOUR_UI::engine_running () { - cerr << "ENGINE RUNNING\n"; - if (first_time_engine_run) { post_engine(); first_time_engine_run = false; - } else { - cerr << "AGAIN...\n"; - } + } update_disk_space (); update_cpu_load (); @@ -1084,8 +1080,6 @@ ARDOUR_UI::update_sample_rate (framecnt_t) { char buf[64]; - cerr << "USR\n"; - ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored) if (!AudioEngine::instance()->connected()) { @@ -1112,8 +1106,6 @@ ARDOUR_UI::update_sample_rate (framecnt_t) } } } - cerr << "SRL = " << buf << endl; - sample_rate_label.set_markup (buf); } diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index 65fa7227a7..135e2869ee 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -78,20 +78,146 @@ EngineControl::EngineControl () , aj_button (_("Start MIDI ALSA/JACK bridge")) , ignore_changes (0) , _desired_sample_rate (0) + , no_push (true) { - if (!ARDOUR::AudioEngine::instance()->setup_required()) { - _have_control = false; - } else { - _have_control = true; - } + using namespace Notebook_Helpers; + vector strings; + Label* label; + AttachOptions xopt = AttachOptions (FILL|EXPAND); + int row; set_name (X_("AudioMIDISetup")); - build_notebook (); + /* the backend combo is the one thing that is ALWAYS visible + */ + + vector backends = ARDOUR::AudioEngine::instance()->available_backends(); + for (vector::const_iterator b = backends.begin(); b != backends.end(); ++b) { + strings.push_back ((*b)->name); + } + + set_popdown_strings (backend_combo, strings); + backend_combo.set_active_text (strings.front()); + backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed)); + + /* setup basic packing characteristics for the table used on the main + * tab of the notebook + */ + + basic_packer.set_spacings (6); + basic_packer.set_border_width (12); + basic_packer.set_homogeneous (true); + + /* pack it in */ + + basic_hbox.pack_start (basic_packer, false, false); + + /* latency tab */ + + /* latency measurement tab */ + + lm_title.set_markup (string_compose ("%1", _("Latency Measurement Tool"))); + + row = 0; + lm_table.set_row_spacings (12); + + lm_table.attach (lm_title, 0, 2, row, row+1, xopt, (AttachOptions) 0); + row++; + + Gtk::Label* preamble; + + preamble = manage (new Label); + preamble->set_width_chars (60); + preamble->set_line_wrap (true); + preamble->set_markup (_("Turn down the volume on your hardware to a very low level.")); + + lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + row++; + + preamble = manage (new Label); + preamble->set_width_chars (60); + preamble->set_line_wrap (true); + preamble->set_markup (_("Select two channels below and connect them using a cable or (less ideally) a speaker and microphone.")); + + lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + row++; + + label = manage (new Label (_("Output channel"))); + lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0); + + Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5)); + misc_align->add (lm_output_channel_combo); + lm_table.attach (*misc_align, 1, 2, row, row+1, xopt, (AttachOptions) 0); + ++row; + + label = manage (new Label (_("Input channel"))); + lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0); + + misc_align = manage (new Alignment (0.0, 0.5)); + misc_align->add (lm_input_channel_combo); + lm_table.attach (*misc_align, 1, 2, row, row+1, FILL, (AttachOptions) 0); + ++row; + + xopt = AttachOptions(0); + + lm_measure_button.add (lm_start_stop_label); + + lm_measure_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::latency_button_toggled)); + lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked)); + lm_use_button.set_sensitive (false); + + preamble = manage (new Label); + preamble->set_width_chars (60); + preamble->set_line_wrap (true); + preamble->set_markup (_("Once the channels are connected, click the \"Measure latency\" button.")); + lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + row++; + + lm_table.attach (lm_measure_button, 0, 2, row, row+1, xopt, (AttachOptions) 0); + ++row; + lm_table.attach (lm_results, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + ++row; + + + preamble = manage (new Label); + preamble->set_width_chars (60); + preamble->set_line_wrap (true); + preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button.")); + lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + row++; + + lm_table.attach (lm_use_button, 0, 2, row, row+1, xopt, (AttachOptions) 0); + ++row; + + lm_results.set_markup ("No measurement results yet"); + + lm_vbox.set_border_width (12); + lm_vbox.pack_start (lm_table, false, false); + + /* pack it all up */ + + notebook.pages().push_back (TabElem (basic_vbox, _("Audio"))); + notebook.pages().push_back (TabElem (midi_vbox, _("MIDI"))); + notebook.pages().push_back (TabElem (lm_vbox, _("Latency"))); + notebook.set_border_width (12); + + notebook.set_tab_pos (POS_RIGHT); + notebook.show_all (); + + notebook.set_name ("SettingsNotebook"); + + /* packup the notebook */ get_vbox()->set_border_width (12); get_vbox()->pack_start (notebook); + /* need a special function to print "all available channels" when the + * channel counts hit zero. + */ + + input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels)); + output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels)); + control_app_button.signal_clicked().connect (mem_fun (*this, &EngineControl::control_app_button_clicked)); manage_control_app_sensitivity (); @@ -103,12 +229,31 @@ EngineControl::EngineControl () XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup"); - /* push a change as if we altered the backend */ + ARDOUR::AudioEngine::instance()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_running, this), gui_context()); + ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context()); + ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context()); + backend_changed (); if (audio_setup) { set_state (*audio_setup); - } + } + + /* Connect to signals */ + + driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed)); + sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed)); + buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed)); + device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed)); + + input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); + output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); + input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); + output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); + + notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page)); + + no_push = false; } void @@ -139,36 +284,58 @@ EngineControl::on_response (int response_id) void EngineControl::build_notebook () { + Label* label; + AttachOptions xopt = AttachOptions (FILL|EXPAND); + + /* clear the table */ + + Gtkmm2ext::container_clear (basic_vbox); + Gtkmm2ext::container_clear (basic_packer); + + label = manage (left_aligned_label (_("Audio System:"))); + basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0); + basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0); + + if (_have_control) { + build_full_control_notebook (); + } else { + build_no_control_notebook (); + } + + basic_vbox.pack_start (basic_hbox, false, false); + + if (_have_control) { + Gtk::HBox* hpacker = manage (new HBox); + hpacker->set_border_width (12); + hpacker->pack_start (control_app_button, false, false); + hpacker->show (); + control_app_button.show(); + basic_vbox.pack_start (*hpacker); + } + + basic_vbox.show_all (); +} + +void +EngineControl::build_full_control_notebook () +{ + boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); + assert (backend); + using namespace Notebook_Helpers; Label* label; vector strings; - int row = 0; - - vector backends = ARDOUR::AudioEngine::instance()->available_backends(); - for (vector::const_iterator b = backends.begin(); b != backends.end(); ++b) { - strings.push_back ((*b)->name); - } - - set_popdown_strings (backend_combo, strings); - backend_combo.set_active_text (strings.front()); - - basic_packer.set_spacings (6); - basic_packer.set_border_width (12); - basic_packer.set_homogeneous (true); - - row = 0; - AttachOptions xopt = AttachOptions (FILL|EXPAND); + int row = 1; // row zero == backend combo - label = manage (left_aligned_label (_("Audio System:"))); - basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0); - basic_packer.attach (backend_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0); - row++; + /* start packing it up */ - label = manage (left_aligned_label (_("Driver:"))); - basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0); - basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0); - row++; + if (backend->requires_driver_selection()) { + label = manage (left_aligned_label (_("Driver:"))); + basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0); + basic_packer.attach (driver_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0); + row++; + } label = manage (left_aligned_label (_("Device:"))); basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0); @@ -236,126 +403,46 @@ EngineControl::build_notebook () basic_packer.attach (*label, 2, 3, row, row+1, xopt, (AttachOptions) 0); ++row; - basic_hbox.pack_start (basic_packer, false, false); - basic_vbox.pack_start (basic_hbox, false, false); +} - Gtk::HBox* hpacker = manage (new HBox); - hpacker->set_border_width (12); - hpacker->pack_start (control_app_button, false, false); - hpacker->show (); - control_app_button.show(); - basic_vbox.pack_start (*hpacker); +void +EngineControl::build_no_control_notebook () +{ + boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); + assert (backend); - /* latency measurement tab */ - - lm_title.set_markup (string_compose ("%1", _("Latency Measurement Tool"))); - - row = 0; - lm_table.set_row_spacings (12); + using namespace Notebook_Helpers; + Label* label; + vector strings; + AttachOptions xopt = AttachOptions (FILL|EXPAND); + int row = 1; // row zero == backend combo + const string msg = string_compose (_("The %1 audio backend was configured and started externally.\nThis limits your control over it."), backend->name()); - lm_table.attach (lm_title, 0, 2, row, row+1, xopt, (AttachOptions) 0); + label = manage (new Label); + label->set_markup (string_compose ("%1", msg)); + basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0); row++; - Gtk::Label* preamble; + if (backend->can_change_sample_rate_when_running()) { + label = manage (left_aligned_label (_("Sample rate:"))); + basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0); + basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0); + row++; + } - preamble = manage (new Label); - preamble->set_width_chars (60); - preamble->set_line_wrap (true); - preamble->set_markup (_("Turn down the volume on your hardware to a very low level.")); + if (backend->can_change_buffer_size_when_running()) { + label = manage (left_aligned_label (_("Buffer size:"))); + basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0); + basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0); + buffer_size_duration_label.set_alignment (0.0); /* left-align */ + basic_packer.attach (buffer_size_duration_label, 2, 3, row, row+1, xopt, (AttachOptions) 0); + row++; + } - lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + connect_disconnect_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::connect_disconnect_click)); + + basic_packer.attach (connect_disconnect_button, 0, 2, row, row+1, FILL, AttachOptions (0)); row++; - - preamble = manage (new Label); - preamble->set_width_chars (60); - preamble->set_line_wrap (true); - preamble->set_markup (_("Select two channels below and connect them using a cable or (less ideally) a speaker and microphone.")); - - lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); - row++; - - label = manage (new Label (_("Output channel"))); - lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0); - - Gtk::Alignment* misc_align = manage (new Alignment (0.0, 0.5)); - misc_align->add (lm_output_channel_combo); - lm_table.attach (*misc_align, 1, 2, row, row+1, xopt, (AttachOptions) 0); - ++row; - - label = manage (new Label (_("Input channel"))); - lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0); - - misc_align = manage (new Alignment (0.0, 0.5)); - misc_align->add (lm_input_channel_combo); - lm_table.attach (*misc_align, 1, 2, row, row+1, FILL, (AttachOptions) 0); - ++row; - - xopt = AttachOptions(0); - - lm_measure_button.add (lm_start_stop_label); - - lm_measure_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::latency_button_toggled)); - lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked)); - lm_use_button.set_sensitive (false); - - - preamble = manage (new Label); - preamble->set_width_chars (60); - preamble->set_line_wrap (true); - preamble->set_markup (_("Once the channels are connected, click the \"Measure latency\" button.")); - lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); - row++; - - lm_table.attach (lm_measure_button, 0, 2, row, row+1, xopt, (AttachOptions) 0); - ++row; - lm_table.attach (lm_results, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); - ++row; - - - preamble = manage (new Label); - preamble->set_width_chars (60); - preamble->set_line_wrap (true); - preamble->set_markup (_("When satisfied with the results, click the \"Use results\" button.")); - lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); - row++; - - lm_table.attach (lm_use_button, 0, 2, row, row+1, xopt, (AttachOptions) 0); - ++row; - - lm_results.set_markup ("No measurement results yet"); - - lm_vbox.set_border_width (12); - lm_vbox.pack_start (lm_table, false, false); - - /* pack it all up */ - - notebook.pages().push_back (TabElem (basic_vbox, _("Audio"))); - notebook.pages().push_back (TabElem (midi_vbox, _("MIDI"))); - notebook.pages().push_back (TabElem (lm_vbox, _("Latency"))); - notebook.set_border_width (12); - - notebook.set_tab_pos (POS_RIGHT); - notebook.show_all (); - - notebook.set_name ("SettingsNotebook"); - - /* Connect to signals */ - - backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed)); - driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed)); - sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::sample_rate_changed)); - buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::buffer_size_changed)); - device_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::device_changed)); - - input_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); - output_latency.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); - input_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); - output_channels.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::parameter_changed)); - - input_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &input_channels)); - output_channels.signal_output().connect (sigc::bind (sigc::ptr_fun (&EngineControl::print_channel_count), &output_channels)); - - notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page)); } EngineControl::~EngineControl () @@ -470,6 +557,11 @@ EngineControl::refresh_midi_display () } } +void +EngineControl::update_sensitivity () +{ +} + void EngineControl::backend_changed () { @@ -485,16 +577,29 @@ EngineControl::backend_changed () return; } + _have_control = ARDOUR::AudioEngine::instance()->setup_required (); + + build_notebook (); setup_midi_tab_for_backend (); if (backend->requires_driver_selection()) { vector drivers = backend->enumerate_drivers(); - driver_combo.set_sensitive (true); - set_popdown_strings (driver_combo, drivers); - driver_combo.set_active_text (drivers.front()); - driver_changed (); + + if (!drivers.empty()) { + { + PBD::Unwinder protect_ignore_changes (ignore_changes, ignore_changes + 1); + set_popdown_strings (driver_combo, drivers); + driver_combo.set_active_text (drivers.front()); + } + + driver_changed (); + } + } else { driver_combo.set_sensitive (false); + /* this will change the device text which will cause a call to + * device changed which will set up parameters + */ list_devices (); } @@ -540,33 +645,33 @@ EngineControl::list_devices () available_devices.push_back (i->name); } - ignore_changes++; - set_popdown_strings (device_combo, available_devices); - ignore_changes--; - if (!available_devices.empty()) { - sample_rate_combo.set_sensitive (true); - buffer_size_combo.set_sensitive (true); - input_latency.set_sensitive (true); - output_latency.set_sensitive (true); - input_channels.set_sensitive (true); - output_channels.set_sensitive (true); + + update_sensitivity (); - /* changing the text in the combo will trigger device_changed() - which should populate the parameter controls - */ - - device_combo.set_active_text (available_devices.front()); + { + PBD::Unwinder protect_ignore_changes (ignore_changes, ignore_changes + 1); + set_popdown_strings (device_combo, available_devices); + device_combo.set_active_text (available_devices.front()); + } + + device_changed (); + + ok_button->set_sensitive (true); + apply_button->set_sensitive (true); + } else { - sample_rate_combo.set_sensitive (true); - buffer_size_combo.set_sensitive (true); - input_latency.set_sensitive (true); - output_latency.set_sensitive (true); - input_channels.set_sensitive (true); - output_channels.set_sensitive (true); + sample_rate_combo.set_sensitive (false); + buffer_size_combo.set_sensitive (false); + input_latency.set_sensitive (false); + output_latency.set_sensitive (false); + input_channels.set_sensitive (false); + output_channels.set_sensitive (false); + ok_button->set_sensitive (false); + apply_button->set_sensitive (false); } } - + void EngineControl::driver_changed () { @@ -595,58 +700,94 @@ EngineControl::device_changed () string device_name = device_combo.get_active_text (); vector s; - /* don't allow programmatic change to sample_rate_combo to cause a - recursive call to this method. - */ - - ignore_changes++; + { + PBD::Unwinder protect_ignore_changes (ignore_changes, ignore_changes + 1); - /* sample rates */ - - string desired; + /* don't allow programmatic change to combos to cause a + recursive call to this method. + */ + + /* sample rates */ + + string desired; + + vector sr; - vector sr = backend->available_sample_rates (device_name); - for (vector::const_iterator x = sr.begin(); x != sr.end(); ++x) { - s.push_back (rate_as_string (*x)); - if (*x == _desired_sample_rate) { - desired = s.back(); - } - } - - if (!s.empty()) { - set_popdown_strings (sample_rate_combo, s); - - if (desired.empty()) { - sample_rate_combo.set_active_text (s.front()); + if (_have_control) { + sr = backend->available_sample_rates (device_name); } else { - sample_rate_combo.set_active_text (desired); + + sr.push_back (8000.0f); + sr.push_back (16000.0f); + sr.push_back (32000.0f); + sr.push_back (44100.0f); + sr.push_back (48000.0f); + sr.push_back (88200.0f); + sr.push_back (96000.0f); + sr.push_back (192000.0f); + sr.push_back (384000.0f); } - } else { - /* hmm ... how to tell the user about the fact that we have no - * available sample rates. + + for (vector::const_iterator x = sr.begin(); x != sr.end(); ++x) { + s.push_back (rate_as_string (*x)); + if (*x == _desired_sample_rate) { + desired = s.back(); + } + } + + if (!s.empty()) { + sample_rate_combo.set_sensitive (true); + set_popdown_strings (sample_rate_combo, s); + + if (desired.empty()) { + sample_rate_combo.set_active_text (s.front()); + } else { + sample_rate_combo.set_active_text (desired); + } + + } else { + sample_rate_combo.set_sensitive (false); + } + + /* buffer sizes */ + + vector bs; + + if (_have_control) { + bs = backend->available_buffer_sizes(device_name); + } else if (backend->can_change_buffer_size_when_running()) { + bs.push_back (8); + bs.push_back (16); + bs.push_back (32); + bs.push_back (64); + bs.push_back (128); + bs.push_back (256); + bs.push_back (512); + bs.push_back (1024); + bs.push_back (2048); + bs.push_back (4096); + bs.push_back (8192); + } + s.clear (); + for (vector::const_iterator x = bs.begin(); x != bs.end(); ++x) { + s.push_back (bufsize_as_string (*x)); + } + + if (!s.empty()) { + buffer_size_combo.set_sensitive (true); + set_popdown_strings (buffer_size_combo, s); + + buffer_size_combo.set_active_text (s.front()); + show_buffer_duration (); + } else { + buffer_size_combo.set_sensitive (false); + } + + /* XXX theoretically need to set min + max channel counts here */ + + manage_control_app_sensitivity (); } - - - vector bs = backend->available_buffer_sizes(device_name); - s.clear (); - for (vector::const_iterator x = bs.begin(); x != bs.end(); ++x) { - s.push_back (bufsize_as_string (*x)); - } - - if (!s.empty()) { - set_popdown_strings (buffer_size_combo, s); - buffer_size_combo.set_active_text (s.front()); - show_buffer_duration (); - } else { - /* hmm ... how to tell the user about the fact that we have no - * available buffer sizes. - */ - } - - manage_control_app_sensitivity (); - - ignore_changes--; /* pick up any saved state for this device */ @@ -774,6 +915,10 @@ EngineControl::get_saved_state_for_currently_displayed_backend_and_device () EngineControl::State* EngineControl::save_state () { + if (!_have_control) { + return 0; + } + bool existing = true; State* state = get_saved_state_for_currently_displayed_backend_and_device (); @@ -808,10 +953,15 @@ EngineControl::store_state (State& state) void EngineControl::maybe_display_saved_state () { + if (!_have_control) { + return; + } + State* state = get_saved_state_for_currently_displayed_backend_and_device (); if (state) { - ignore_changes++; + PBD::Unwinder protect_ignore_changes (ignore_changes, ignore_changes + 1); + if (!_desired_sample_rate) { sample_rate_combo.set_active_text (rate_as_string (state->sample_rate)); } @@ -822,7 +972,6 @@ EngineControl::maybe_display_saved_state () show_buffer_duration (); input_latency.set_value (state->input_latency); output_latency.set_value (state->output_latency); - ignore_changes--; } } @@ -952,6 +1101,7 @@ EngineControl::set_state (const XMLNode& root) /* now see if there was an active state and switch the setup to it */ for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) { + if ((*i).active) { ignore_changes++; backend_combo.set_active_text ((*i).backend); @@ -971,6 +1121,10 @@ EngineControl::set_state (const XMLNode& root) int EngineControl::push_state_to_backend (bool start) { + if (no_push) { + return 0; + } + boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); if (!backend) { @@ -992,47 +1146,60 @@ EngineControl::push_state_to_backend (bool start) uint32_t ichan = get_input_channels (); if (_have_control) { - - /* we can control the backend */ - if (backend->requires_driver_selection()) { - if (get_driver() != backend->driver_name()) { - change_driver = true; + if (started_at_least_once) { + + /* we can control the backend */ + + if (backend->requires_driver_selection()) { + if (get_driver() != backend->driver_name()) { + change_driver = true; + } } - } + + if (get_device_name() != backend->device_name()) { + change_device = true; + } + + if (get_rate() != backend->sample_rate()) { + change_rate = true; + } + + if (get_buffer_size() != backend->buffer_size()) { + change_bufsize = true; + } + + /* zero-requested channels means "all available" */ - if (get_device_name() != backend->device_name()) { + if (ichan == 0) { + ichan = backend->input_channels(); + } + + if (ochan == 0) { + ochan = backend->output_channels(); + } + + if (ichan != backend->input_channels()) { + change_channels = true; + } + + if (ochan != backend->output_channels()) { + change_channels = true; + } + + if (get_input_latency() != backend->systemic_input_latency() || + get_output_latency() != backend->systemic_output_latency()) { + change_latency = true; + } + } else { + /* backend never started, so we have to force a group + of settings. + */ + change_driver = true; change_device = true; - } - - if (get_rate() != backend->sample_rate()) { change_rate = true; - } - - if (get_buffer_size() != backend->buffer_size()) { change_bufsize = true; - } - - /* zero-requested channels means "all available" */ - - if (ichan == 0) { - ichan = backend->input_channels(); - } - - if (ochan == 0) { - ochan = backend->output_channels(); - } - - if (ichan != backend->input_channels()) { change_channels = true; - } - - if (ochan != backend->output_channels()) { - change_channels = true; - } - - if (get_input_latency() != backend->systemic_input_latency() || - get_output_latency() != backend->systemic_output_latency()) { change_latency = true; } @@ -1175,26 +1342,28 @@ EngineControl::post_push () * necessary */ - State* state = get_saved_state_for_currently_displayed_backend_and_device (); - - if (!state) { - state = save_state (); - assert (state); + if (_have_control) { + State* state = get_saved_state_for_currently_displayed_backend_and_device (); + + if (!state) { + state = save_state (); + assert (state); + } + + /* all off */ + + for (StateList::iterator i = states.begin(); i != states.end(); ++i) { + (*i).active = false; + } + + /* mark this one active (to be used next time the dialog is + * shown) + */ + + state->active = true; + + manage_control_app_sensitivity (); } - - /* all off */ - - for (StateList::iterator i = states.begin(); i != states.end(); ++i) { - (*i).active = false; - } - - /* mark this one active (to be used next time the dialog is - * shown) - */ - - state->active = true; - - manage_control_app_sensitivity (); /* schedule a redisplay of MIDI ports */ @@ -1482,3 +1651,51 @@ EngineControl::on_delete_event (GdkEventAny* ev) return ArdourDialog::on_delete_event (ev); } +void +EngineControl::engine_running () +{ + boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); + assert (backend); + + buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size())); + sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate())); + + if (backend->can_change_buffer_size_when_running()) { + buffer_size_combo.set_sensitive (true); + } else { + buffer_size_combo.set_sensitive (false); + } + + if (backend->can_change_sample_rate_when_running()) { + sample_rate_combo.set_sensitive (true); + } else { + sample_rate_combo.set_sensitive (false); + } + + connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name())); + + started_at_least_once = true; +} + +void +EngineControl::engine_stopped () +{ + boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); + assert (backend); + + buffer_size_combo.set_sensitive (false); + connect_disconnect_button.set_label (string_compose (_("Connect to %1"), backend->name())); + + sample_rate_combo.set_sensitive (true); + buffer_size_combo.set_sensitive (true); +} + +void +EngineControl::connect_disconnect_click() +{ + if (ARDOUR::AudioEngine::instance()->running()) { + ARDOUR_UI::instance()->disconnect_from_engine (); + } else { + ARDOUR_UI::instance()->reconnect_to_engine (); + } +} diff --git a/gtk2_ardour/engine_dialog.h b/gtk2_ardour/engine_dialog.h index fcbdfe4cb8..59924e0f0a 100644 --- a/gtk2_ardour/engine_dialog.h +++ b/gtk2_ardour/engine_dialog.h @@ -75,8 +75,11 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList { Gtk::Adjustment ports_adjustment; Gtk::SpinButton ports_spinner; + Gtk::Label have_control_text; Gtk::Button control_app_button; + Gtk::Button connect_disconnect_button; + /* latency measurement */ Gtk::ComboBoxText lm_output_channel_combo; @@ -106,9 +109,9 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList { uint32_t ignore_changes; uint32_t _desired_sample_rate; - - static bool engine_running (); - + bool no_push; + bool started_at_least_once; + void driver_changed (); void backend_changed (); void sample_rate_changed (); @@ -174,6 +177,8 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList { static bool print_channel_count (Gtk::SpinButton*); void build_notebook (); + void build_full_control_notebook (); + void build_no_control_notebook (); void on_response (int); void control_app_button_clicked (); @@ -181,6 +186,7 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList { void manage_control_app_sensitivity (); int push_state_to_backend (bool start); void post_push (); + void update_sensitivity (); /* latency measurement */ void latency_button_toggled (); @@ -190,9 +196,16 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList { void disable_latency_tab (); void start_latency_detection (); void end_latency_detection (); - + void on_switch_page (GtkNotebookPage*, guint page_num); bool on_delete_event (GdkEventAny*); + + void engine_running (); + void engine_stopped (); + PBD::ScopedConnection running_connection; + PBD::ScopedConnection stopped_connection; + + void connect_disconnect_click (); }; #endif /* __gtk2_ardour_engine_dialog_h__ */ diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index 1e7cb9d8d5..d4e2f310d3 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -960,6 +960,7 @@ JACKAudioBackend::disconnected (const char* why) engine.halted_callback (why); /* EMIT SIGNAL */ } } + float JACKAudioBackend::cpu_load() const { From 3f56abe099cd6978fbf2e1778debd74e771c95cd Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 19 Sep 2013 16:17:47 -0400 Subject: [PATCH 04/42] missing initialization --- gtk2_ardour/engine_dialog.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index 135e2869ee..fa0ebe0240 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -79,6 +79,7 @@ EngineControl::EngineControl () , ignore_changes (0) , _desired_sample_rate (0) , no_push (true) + , started_at_least_once (false) { using namespace Notebook_Helpers; vector strings; From d2ca0665bf63188b2004338d5238122f3714b89a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 19 Sep 2013 16:48:05 -0400 Subject: [PATCH 05/42] reallow changing bufsize AND sample rate when we are in control, because this is cool --- gtk2_ardour/engine_dialog.cc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index fa0ebe0240..b10cc626b6 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -1661,17 +1661,8 @@ EngineControl::engine_running () buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size())); sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate())); - if (backend->can_change_buffer_size_when_running()) { - buffer_size_combo.set_sensitive (true); - } else { - buffer_size_combo.set_sensitive (false); - } - - if (backend->can_change_sample_rate_when_running()) { - sample_rate_combo.set_sensitive (true); - } else { - sample_rate_combo.set_sensitive (false); - } + buffer_size_combo.set_sensitive (true); + sample_rate_combo.set_sensitive (true); connect_disconnect_button.set_label (string_compose (_("Disconnect from %1"), backend->name())); From 960a47330a5d3e534e6275f42efc07585a2075e1 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 19 Sep 2013 17:34:23 -0400 Subject: [PATCH 06/42] switch from JACK_Slave to Engine_Slave --- gtk2_ardour/ardour_ui.cc | 4 +-- gtk2_ardour/ardour_ui_options.cc | 4 +-- gtk2_ardour/audio_clock.cc | 2 +- gtk2_ardour/editor_ops.cc | 2 +- gtk2_ardour/session_option_editor.cc | 2 +- gtk2_ardour/video_monitor.cc | 2 +- libs/ardour/ardour/rc_configuration_vars.h | 2 +- libs/ardour/ardour/session.h | 2 +- libs/ardour/ardour/slave.h | 6 ++-- libs/ardour/ardour/types.h | 2 +- .../ardour/{jack_slave.cc => engine_slave.cc} | 10 +++---- libs/ardour/enums.cc | 2 +- libs/ardour/globals.cc | 6 +++- libs/ardour/session.cc | 4 +-- libs/ardour/session_time.cc | 2 +- libs/ardour/session_transport.cc | 30 +++++++++---------- libs/ardour/utils.cc | 9 ++++-- libs/ardour/wscript | 2 +- 18 files changed, 50 insertions(+), 43 deletions(-) rename libs/ardour/{jack_slave.cc => engine_slave.cc} (88%) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index f22b48bd3a..f599442bc4 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1809,7 +1809,7 @@ ARDOUR_UI::transport_roll () #if 0 if (_session->config.get_external_sync()) { switch (Config->get_sync_source()) { - case JACK: + case Engine: break; default: /* transport controlled by the master */ @@ -1859,7 +1859,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) if (_session->config.get_external_sync()) { switch (Config->get_sync_source()) { - case JACK: + case Engine: break; default: /* transport controlled by the master */ diff --git a/gtk2_ardour/ardour_ui_options.cc b/gtk2_ardour/ardour_ui_options.cc index 6b2c9da6fa..618169d2e8 100644 --- a/gtk2_ardour/ardour_ui_options.cc +++ b/gtk2_ardour/ardour_ui_options.cc @@ -60,7 +60,7 @@ ARDOUR_UI::toggle_external_sync() { if (_session) { if (_session->config.get_video_pullup() != 0.0f) { - if (Config->get_sync_source() == JACK) { + if (Config->get_sync_source() == Engine) { MessageDialog msg ( _("It is not possible to use JACK as the the sync source\n\ when the pull up/down setting is non-zero.")); @@ -465,7 +465,7 @@ ARDOUR_UI::synchronize_sync_source_and_video_pullup () act->set_sensitive (true); } else { /* can't sync to JACK if video pullup != 0.0 */ - if (Config->get_sync_source() == JACK) { + if (Config->get_sync_source() == Engine) { act->set_sensitive (false); } else { act->set_sensitive (true); diff --git a/gtk2_ardour/audio_clock.cc b/gtk2_ardour/audio_clock.cc index c658160e14..6680e95b15 100644 --- a/gtk2_ardour/audio_clock.cc +++ b/gtk2_ardour/audio_clock.cc @@ -996,7 +996,7 @@ AudioClock::set_slave_info () Slave* slave = _session->slave(); switch (sync_src) { - case JACK: + case Engine: _left_layout->set_markup (string_compose ("" TXTSPAN "%2", INFO_FONT_SIZE, sync_source_to_string(sync_src, true))); _right_layout->set_text (""); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 93a53dd1d3..6ada12220a 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -2108,7 +2108,7 @@ Editor::transition_to_rolling (bool fwd) if (_session->config.get_external_sync()) { switch (Config->get_sync_source()) { - case JACK: + case Engine: break; default: /* transport controlled by the master */ diff --git a/gtk2_ardour/session_option_editor.cc b/gtk2_ardour/session_option_editor.cc index 1815db1056..60f575fb16 100644 --- a/gtk2_ardour/session_option_editor.cc +++ b/gtk2_ardour/session_option_editor.cc @@ -334,7 +334,7 @@ SessionOptionEditor::parameter_changed (std::string const & p) { OptionEditor::parameter_changed (p); if (p == "external-sync") { - if (Config->get_sync_source() == JACK) { + if (Config->get_sync_source() == Engine) { _vpu->set_sensitive(!_session_config->get_external_sync()); } else { _vpu->set_sensitive(true); diff --git a/gtk2_ardour/video_monitor.cc b/gtk2_ardour/video_monitor.cc index 2c265365fa..b1e3c87d22 100644 --- a/gtk2_ardour/video_monitor.cc +++ b/gtk2_ardour/video_monitor.cc @@ -554,7 +554,7 @@ VideoMonitor::xjadeo_sync_setup () bool my_manual_seek = true; if (_session->config.get_external_sync()) { - if (ARDOUR::Config->get_sync_source() == ARDOUR::JACK) + if (ARDOUR::Config->get_sync_source() == ARDOUR::Engine) my_manual_seek = false; } diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index e05efbd510..3c11304fdb 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -51,7 +51,7 @@ CONFIG_VARIABLE (int, mtc_qf_speed_tolerance, "mtc-qf-speed-tolerance", 5) CONFIG_VARIABLE (bool, timecode_sync_frame_rate, "timecode-sync-frame-rate", true) CONFIG_VARIABLE (bool, timecode_source_is_synced, "timecode-source-is-synced", true) CONFIG_VARIABLE (bool, timecode_source_2997, "timecode-source-2997", false) -CONFIG_VARIABLE (SyncSource, sync_source, "sync-source", JACK) +CONFIG_VARIABLE (SyncSource, sync_source, "sync-source", Engine) CONFIG_VARIABLE (std::string, ltc_source_port, "ltc-source-port", "system:capture_1") CONFIG_VARIABLE (bool, send_ltc, "send-ltc", false) CONFIG_VARIABLE (bool, ltc_send_continuously, "ltc-send-continuously", true) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 7337e2d1ea..ae5339796c 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -509,7 +509,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi static PBD::Signal1 EndTimeChanged; void request_sync_source (Slave*); - bool synced_to_jack() const { return config.get_external_sync() && Config->get_sync_source() == JACK; } + bool synced_to_engine() const { return config.get_external_sync() && Config->get_sync_source() == Engine; } double transport_speed() const { return _transport_speed; } bool transport_stopped() const { return _transport_speed == 0.0f; } diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index c60acb1df7..a0b7b878e4 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -486,11 +486,11 @@ class MIDIClock_Slave : public Slave { bool _starting; }; -class JACK_Slave : public Slave +class Engine_Slave : public Slave { public: - JACK_Slave (AudioEngine&); - ~JACK_Slave (); + Engine_Slave (AudioEngine&); + ~Engine_Slave (); bool speed_and_position (double& speed, framepos_t& pos); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index f2319d7669..658c64788e 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -489,7 +489,7 @@ namespace ARDOUR { }; enum SyncSource { - JACK, + Engine, MTC, MIDIClock, LTC diff --git a/libs/ardour/jack_slave.cc b/libs/ardour/engine_slave.cc similarity index 88% rename from libs/ardour/jack_slave.cc rename to libs/ardour/engine_slave.cc index 4b2f3b1860..eb55c9ba54 100644 --- a/libs/ardour/jack_slave.cc +++ b/libs/ardour/engine_slave.cc @@ -26,7 +26,7 @@ using namespace std; using namespace ARDOUR; -JACK_Slave::JACK_Slave (AudioEngine& e) +Engine_Slave::Engine_Slave (AudioEngine& e) : engine (e) { double x; @@ -35,24 +35,24 @@ JACK_Slave::JACK_Slave (AudioEngine& e) speed_and_position (x, p); } -JACK_Slave::~JACK_Slave () +Engine_Slave::~Engine_Slave () { } bool -JACK_Slave::locked() const +Engine_Slave::locked() const { return true; } bool -JACK_Slave::ok() const +Engine_Slave::ok() const { return true; } bool -JACK_Slave::speed_and_position (double& sp, framepos_t& position) +Engine_Slave::speed_and_position (double& sp, framepos_t& position) { switch (engine.transport_state()) { case TransportStopped: diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index bab0e8ed15..8fec499c35 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -335,7 +335,7 @@ setup_enum_writer () REGISTER (_PluginType); REGISTER_ENUM (MTC); - REGISTER_ENUM (JACK); + REGISTER_ENUM (Engine); REGISTER_ENUM (MIDIClock); REGISTER_ENUM (LTC); REGISTER (_SyncSource); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index aac7709f90..459f6f0e51 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -530,7 +530,11 @@ ARDOUR::get_available_sync_options () { vector ret; - ret.push_back (JACK); + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + if (backend && backend->name() == "JACK") { + ret.push_back (Engine); + } + ret.push_back (MTC); ret.push_back (MIDIClock); ret.push_back (LTC); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 746732f76e..4be52a7584 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -393,7 +393,7 @@ Session::immediately_post_engine () _engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this)); - if (synced_to_jack()) { + if (synced_to_engine()) { _engine.transport_stop (); } @@ -1406,7 +1406,7 @@ Session::audible_frame () const offset = current_block_size; } - if (synced_to_jack()) { + if (synced_to_engine()) { tf = _engine.transport_frame(); } else { tf = _transport_frame; diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc index 0f2186c09b..e35910f2df 100644 --- a/libs/ardour/session_time.cc +++ b/libs/ardour/session_time.cc @@ -182,7 +182,7 @@ Session::timecode_time (Timecode::Time &t) int Session::backend_sync_callback (TransportState state, framepos_t pos) { - bool slave = synced_to_jack(); + bool slave = synced_to_engine(); switch (state) { case TransportStopped: diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index ab6d68fd67..38ad521235 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -86,7 +86,7 @@ Session::request_sync_source (Slave* new_slave) seamless = Config->get_seamless_loop (); - if (dynamic_cast(new_slave)) { + if (dynamic_cast(new_slave)) { /* JACK cannot support seamless looping at present */ Config->set_seamless_loop (false); } else { @@ -514,13 +514,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (auto_return_enabled || (ptw & PostTransportLocate) || (_requested_return_frame >= 0) || - synced_to_jack()) { + synced_to_engine()) { if (pending_locate_flush) { flush_all_inserts (); } - if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) && + if ((auto_return_enabled || synced_to_engine() || _requested_return_frame >= 0) && !(ptw & PostTransportLocate)) { /* no explicit locate queued */ @@ -543,7 +543,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) /* don't try to handle loop play when synced to JACK */ - if (!synced_to_jack()) { + if (!synced_to_engine()) { Location *location = _locations->auto_loop_location(); @@ -734,7 +734,7 @@ Session::set_play_loop (bool yn) return; } - if (yn && Config->get_seamless_loop() && synced_to_jack()) { + if (yn && Config->get_seamless_loop() && synced_to_engine()) { warning << string_compose ( _("Seamless looping cannot be supported while %1 is using JACK transport.\n" "Recommend changing the configured options"), PROGRAM_NAME) @@ -811,7 +811,7 @@ Session::flush_all_inserts () void Session::start_locate (framepos_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force) { - if (synced_to_jack()) { + if (synced_to_engine()) { double sp; framepos_t pos; @@ -926,7 +926,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool bool transport_was_stopped = !transport_rolling(); - if (transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) { + if (transport_was_stopped && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_engine() && play_loop)) { realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct transport_was_stopped = true; } else { @@ -1067,7 +1067,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a set_track_monitor_input_status (true); } - if (synced_to_jack ()) { + if (synced_to_engine ()) { if (clear_state) { /* do this here because our response to the slave won't take care of it. @@ -1090,7 +1090,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a set_track_monitor_input_status (false); } - if (synced_to_jack()) { + if (synced_to_engine()) { _engine.transport_start (); } else { start_transport (); @@ -1100,7 +1100,7 @@ Session::set_transport_speed (double speed, bool abort, bool clear_state, bool a /* not zero, not 1.0 ... varispeed */ - if ((synced_to_jack()) && speed != 0.0 && speed != 1.0) { + if ((synced_to_engine()) && speed != 0.0 && speed != 1.0) { warning << string_compose ( _("Global varispeed cannot be supported while %1 is connected to JACK transport control"), PROGRAM_NAME) @@ -1429,8 +1429,8 @@ Session::switch_to_sync_source (SyncSource src) } break; - case JACK: - if (_slave && dynamic_cast(_slave)) { + case Engine: + if (_slave && dynamic_cast(_slave)) { return; } @@ -1438,7 +1438,7 @@ Session::switch_to_sync_source (SyncSource src) return; } - new_slave = new JACK_Slave (*AudioEngine::instance()); + new_slave = new Engine_Slave (*AudioEngine::instance()); break; default: @@ -1632,9 +1632,9 @@ bool Session::maybe_stop (framepos_t limit) { if ((_transport_speed > 0.0f && _transport_frame >= limit) || (_transport_speed < 0.0f && _transport_frame == 0)) { - if (synced_to_jack () && config.get_jack_time_master ()) { + if (synced_to_engine () && config.get_jack_time_master ()) { _engine.transport_stop (); - } else if (!synced_to_jack ()) { + } else if (!synced_to_engine ()) { stop_transport (); } return true; diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index e7b7648149..0c98461974 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -395,12 +395,12 @@ string_to_sync_source (string str) } if (str == _("JACK")) { - return JACK; + return Engine; } fatal << string_compose (_("programming error: unknown sync source string \"%1\""), str) << endmsg; /*NOTREACHED*/ - return JACK; + return Engine; } /** @param sh Return a short version of the string */ @@ -408,7 +408,10 @@ const char* sync_source_to_string (SyncSource src, bool sh) { switch (src) { - case JACK: + case Engine: + /* no other backends offer sync for now ... deal with this if we + * ever have to. + */ return _("JACK"); case MTC: diff --git a/libs/ardour/wscript b/libs/ardour/wscript index d367b2101e..474a9c58c6 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -69,6 +69,7 @@ libardour_sources = [ 'diskstream.cc', 'element_import_handler.cc', 'element_importer.cc', + 'engine_slave.cc', 'enums.cc', 'event_type_map.cc', 'export_channel.cc', @@ -103,7 +104,6 @@ libardour_sources = [ 'interpolation.cc', 'io.cc', 'io_processor.cc', - 'jack_slave.cc', 'kmeterdsp.cc', 'ladspa_plugin.cc', 'location.cc', From bab9184f7c648b8c6607e4c5890e25129e187619 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 20 Sep 2013 14:17:59 -0400 Subject: [PATCH 07/42] changes to integrate new/recent/browse in new session dialog. Probably some errors/mistakes in here and no doubt some improvements to be done. --- gtk2_ardour/startup.cc | 385 +++++++++++++++++++---------------------- gtk2_ardour/startup.h | 16 +- 2 files changed, 183 insertions(+), 218 deletions(-) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index 266a7e2a27..36f399224f 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -70,8 +70,6 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name, , config_modified (false) , new_only (require_new) , default_dir_chooser (0) - , ic_new_session_button (_("Create a new session")) - , ic_existing_session_button (_("Open an existing session")) , monitor_via_hardware_button (string_compose (_("Use an external mixer or the hardware mixer of your audio interface.\n" "%1 will play NO role in monitoring"), PROGRAM_NAME)) , monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME)) @@ -84,7 +82,7 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name, , new_user_page_index (-1) , default_folder_page_index (-1) , monitoring_page_index (-1) - , session_page_index (-1) + , new_session_page_index (-1) , initial_choice_index (-1) , final_page_index (-1) , session_options_page_index (-1) @@ -137,27 +135,19 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name, setup_first_time_config_page (); setup_monitoring_choice_page (); setup_monitor_section_choice_page (); - - ic_new_session_button.set_active (true); // always create new session on first run - + setup_final_page (); + setup_new_session_page (); + } else { - - setup_initial_choice_page (); + + if (!new_only) { + setup_initial_choice_page (); + } + setup_new_session_page (); } - setup_session_page (); setup_more_options_page (); - if (new_user) { - setup_final_page (); - } - - if (new_only) { - ic_vbox.hide (); - } else { - ic_vbox.show (); - } - if (!template_name.empty()) { use_template_button.set_active (false); load_template_override = template_name; @@ -232,10 +222,6 @@ ArdourStartup::session_template_name () return Glib::build_filename (the_path, load_template_override + ARDOUR::template_suffix); } - if (ic_existing_session_button.get_active()) { - return string(); - } - if (use_template_button.get_active()) { TreeModel::iterator iter = template_chooser.get_active (); TreeModel::Row row = (*iter); @@ -254,26 +240,24 @@ ArdourStartup::session_name (bool& should_be_new) return _provided_session_name; } - if (ic_new_session_button.get_active()) { - should_be_new = true; - string val = new_name_entry.get_text (); - strip_whitespace_edges (val); - return val; - } else if (_existing_session_chooser_used) { + /* Try recent session selection */ + + TreeIter iter = recent_session_display.get_selection()->get_selected(); + + if (iter) { + should_be_new = false; + return (*iter)[recent_session_columns.visible_name]; + } + + if (_existing_session_chooser_used) { /* existing session chosen from file chooser */ should_be_new = false; return existing_session_chooser.get_filename (); } else { - /* existing session chosen from recent list */ - should_be_new = false; - - TreeIter iter = recent_session_display.get_selection()->get_selected(); - - if (iter) { - return (*iter)[recent_session_columns.visible_name]; - } - - return ""; + should_be_new = true; + string val = new_name_entry.get_text (); + strip_whitespace_edges (val); + return val; } } @@ -284,20 +268,20 @@ ArdourStartup::session_folder () return _provided_session_path; } - if (ic_new_session_button.get_active()) { - std::string legal_session_folder_name = legalize_for_path (new_name_entry.get_text()); - return Glib::build_filename (new_folder_chooser.get_current_folder(), legal_session_folder_name); - } else if (_existing_session_chooser_used) { + /* Try recent session selection */ + + TreeIter iter = recent_session_display.get_selection()->get_selected(); + + if (iter) { + return (*iter)[recent_session_columns.fullpath]; + } + + if (_existing_session_chooser_used) { /* existing session chosen from file chooser */ return existing_session_chooser.get_current_folder (); } else { - /* existing session chosen from recent list */ - TreeIter iter = recent_session_display.get_selection()->get_selected(); - - if (iter) { - return (*iter)[recent_session_columns.fullpath]; - } - return ""; + std::string legal_session_folder_name = legalize_for_path (new_name_entry.get_text()); + return Glib::build_filename (new_folder_chooser.get_current_folder(), legal_session_folder_name); } } @@ -511,17 +495,32 @@ ArdourStartup::setup_initial_choice_page () ic_vbox.set_spacing (6); ic_vbox.set_border_width (24); - RadioButton::Group g (ic_new_session_button.get_group()); - ic_existing_session_button.set_group (g); + /* append the page early because the recent session display will cause + calls to set_page_complete() on this page. + */ + + initial_choice_index = append_page (ic_vbox); + set_page_title (ic_vbox, string_compose("%1 %2", PROGRAM_NAME, VERSIONSTRING)); + set_page_header_image (ic_vbox, icon_pixbuf); + HBox* centering_hbox = manage (new HBox); VBox* centering_vbox = manage (new VBox); centering_vbox->set_spacing (6); + Label* new_label = manage (new Label); + new_label->set_markup (string_compose ("%1", _("Create a new session"))); + new_label->set_alignment (0, 0.5); + + ic_new_session_button.set_label (_("Configure the new session ...")); + ic_new_session_button.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::new_session_button_clicked)); + + centering_vbox->pack_start (*new_label, false, false, 12); centering_vbox->pack_start (ic_new_session_button, false, true); - centering_vbox->pack_start (ic_existing_session_button, false, true); - + + /* Possible update message */ + if (ARDOUR_UI::instance()->announce_string() != "" ) { Gtk::Frame *info_frame = manage(new Gtk::Frame); @@ -548,23 +547,76 @@ ArdourStartup::setup_initial_choice_page () info_box->pack_start (*updates_button, false, false); } - - ic_new_session_button.signal_button_press_event().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_clicked), false); - ic_new_session_button.signal_activate().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_activated), false); - ic_existing_session_button.signal_button_press_event().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_clicked), false); - ic_existing_session_button.signal_activate().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_activated), false); + ARDOUR::RecentSessions rs; + ARDOUR::read_recent_sessions (rs); + + if (!rs.empty()) { + + /* recent session scroller */ + + Label* load_label = manage (new Label); + load_label->set_markup (string_compose ("%1", _("Load a recent session"))); + load_label->set_alignment (0, 0.5); + + centering_vbox->pack_start (*load_label, false, false, 12); + + recent_session_model = TreeStore::create (recent_session_columns); + redisplay_recent_sessions (); + + 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()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected)); + + recent_scroller.add (recent_session_display); + recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + recent_scroller.set_shadow_type (Gtk::SHADOW_IN); + + recent_session_display.show(); + + recent_scroller.show(); + recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated)); + + int cnt = redisplay_recent_sessions (); + if (cnt > 4) { + recent_scroller.set_size_request (-1, 300); + } + + centering_vbox->pack_start (recent_scroller, false, true); + } + + /* Browse button */ + + existing_session_chooser.set_title (_("Select session file")); + existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &ArdourStartup::existing_session_selected)); + existing_session_chooser.set_current_folder(poor_mans_glob (Config->get_default_session_parent_dir())); + + FileFilter session_filter; + session_filter.add_pattern ("*.ardour"); + session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME)); + existing_session_chooser.add_filter (session_filter); + existing_session_chooser.set_filter (session_filter); + +#ifdef GTKOSX + existing_session_chooser.add_shortcut_folder ("/Volumes"); +#endif + + Label* browse_label = manage (new Label); + browse_label->set_markup (string_compose ("%1", _("Browse for other sessions"))); + browse_label->set_alignment (0, 0.5); + + centering_vbox->pack_start (*browse_label, false, false, 12); + centering_vbox->pack_start (existing_session_chooser, false, false); + + /* pack it all up */ centering_hbox->pack_start (*centering_vbox, true, true); - ic_vbox.pack_start (*centering_hbox, true, true); - ic_vbox.show_all (); - initial_choice_index = append_page (ic_vbox); - set_page_title (ic_vbox, string_compose("%1 %2", PROGRAM_NAME, VERSIONSTRING)); - set_page_header_image (ic_vbox, icon_pixbuf); - /* user could just click on "Forward" if default * choice is correct. */ @@ -572,35 +624,33 @@ ArdourStartup::setup_initial_choice_page () set_page_complete (ic_vbox, true); } -bool -ArdourStartup::initial_button_clicked (GdkEventButton* ev) -{ - if (ev->type == GDK_2BUTTON_PRESS && session_page_index != -1) { - set_current_page(session_page_index); - } - - return false; -} - void -ArdourStartup::initial_button_activated () +ArdourStartup::session_selected () { - if (session_page_index != -1) { - set_current_page(session_page_index); + /* HACK HACK HACK ... change the "Apply" button label + to say "Open" + */ + + Gtk::Widget* tl = ic_vbox.get_toplevel(); + Gtk::Window* win; + if ((win = dynamic_cast(tl)) != 0) { + /* ::get_default_widget() is not wrapped in gtkmm */ + Gtk::Widget* def = wrap (gtk_window_get_default_widget (win->gobj())); + Gtk::Button* button; + if ((button = dynamic_cast(def)) != 0) { + if (more_new_session_options_button.get_active()) { + button->set_label (_("Next")); + } else { + button->set_label (_("Open")); + } + } } } void -ArdourStartup::setup_session_page () +ArdourStartup::new_session_button_clicked () { - session_vbox.set_border_width (24); - - session_vbox.pack_start (session_hbox, true, true); - session_vbox.show_all (); - - session_page_index = append_page (session_vbox); - /* initial setting */ - set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM); + set_current_page (new_session_page_index); } void @@ -621,6 +671,24 @@ ArdourStartup::on_cancel () gtk_main_quit (); } +void +ArdourStartup::on_prepare (Gtk::Widget* page) +{ + if (page == &session_new_vbox) { + + /* if the user already defined a name by using the recent + * session list or browsing to an existing session + * then we are done. + */ + + bool expect_new_ignored; + + if (!session_name (expect_new_ignored).empty()) { + on_apply (); + } + } +} + bool ArdourStartup::on_delete_event (GdkEventAny*) { @@ -662,41 +730,6 @@ ArdourStartup::on_apply () gtk_main_quit (); } -void -ArdourStartup::on_prepare (Gtk::Widget* page) -{ - if (page == &session_vbox) { - - if (ic_new_session_button.get_active()) { - /* new session requested */ - setup_new_session_page (); - } else { - /* existing session requested */ - setup_existing_session_page (); - - } - - /* HACK HACK HACK ... change the "Apply" button label - to say "Open" - */ - - Gtk::Widget* tl = session_vbox.get_toplevel(); - Gtk::Window* win; - if ((win = dynamic_cast(tl)) != 0) { - /* ::get_default_widget() is not wrapped in gtkmm */ - Gtk::Widget* def = wrap (gtk_window_get_default_widget (win->gobj())); - Gtk::Button* button; - if ((button = dynamic_cast(def)) != 0) { - if (more_new_session_options_button.get_active()) { - button->set_label (_("Forward")); - }else{ - button->set_label (_("Open")); - } - } - } - } -} - void ArdourStartup::populate_session_templates () { @@ -719,10 +752,7 @@ ArdourStartup::populate_session_templates () void ArdourStartup::setup_new_session_page () { - if (!session_hbox.get_children().empty()) { - session_hbox.remove (**session_hbox.get_children().begin()); - } - + session_new_vbox.set_border_width (12); session_new_vbox.set_spacing (18); if (session_new_vbox.get_children().empty()) { @@ -742,7 +772,7 @@ ArdourStartup::setup_new_session_page () if (!ARDOUR_COMMAND_LINE::session_name.empty()) { new_name_entry.set_text (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name)); /* name provided - they can move right along */ - set_page_complete (session_vbox, true); + set_page_complete (session_new_vbox, true); } new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_changed)); @@ -882,23 +912,26 @@ ArdourStartup::setup_new_session_page () } session_new_vbox.show_all (); - session_hbox.pack_start (session_new_vbox, true, true); - set_page_title (session_vbox, _("New Session")); - set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM); + + new_session_page_index = append_page (session_new_vbox); + set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); + set_page_title (session_new_vbox, _("New Session")); if (more_new_session_options_button.get_active()) { - set_page_type (session_vbox, ASSISTANT_PAGE_CONTENT); + set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); + } else { + set_page_type (session_new_vbox, ASSISTANT_PAGE_CONFIRM); } - session_hbox.show_all(); } void ArdourStartup::new_name_changed () { if (!new_name_entry.get_text().empty()) { - set_page_complete (session_vbox, true); + session_selected (); + set_page_complete (session_new_vbox, true); } else { - set_page_complete (session_vbox, false); + set_page_complete (session_new_vbox, false); } } @@ -996,87 +1029,22 @@ void ArdourStartup::recent_session_row_selected () { if (recent_session_display.get_selection()->count_selected_rows() > 0) { - set_page_complete (session_vbox, true); + set_page_complete (ic_vbox, true); + session_selected (); } else { - set_page_complete (session_vbox, false); + set_page_complete (ic_vbox, false); } } -void -ArdourStartup::setup_existing_session_page () -{ - recent_session_model = TreeStore::create (recent_session_columns); - redisplay_recent_sessions (); - - if (!session_hbox.get_children().empty()) { - session_hbox.remove (**session_hbox.get_children().begin()); - } - - if (session_existing_vbox.get_children().empty()) { - - 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_BROWSE); - - recent_session_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected)); - - recent_scroller.add (recent_session_display); - recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - recent_scroller.set_shadow_type (Gtk::SHADOW_IN); - - recent_session_display.show(); - - recent_scroller.show(); - int cnt = redisplay_recent_sessions (); - recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated)); - - if (cnt > 4) { - recent_scroller.set_size_request (-1, 300); - } - - session_existing_vbox.set_spacing (8); - session_existing_vbox.pack_start (recent_scroller, true, true); - - existing_session_chooser.set_title (_("Select session file")); - existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &ArdourStartup::existing_session_selected)); - existing_session_chooser.set_current_folder(poor_mans_glob (Config->get_default_session_parent_dir())); - - FileFilter session_filter; - session_filter.add_pattern ("*.ardour"); - session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME)); - existing_session_chooser.add_filter (session_filter); - existing_session_chooser.set_filter (session_filter); - -#ifdef GTKOSX - existing_session_chooser.add_shortcut_folder ("/Volumes"); -#endif - - HBox* hbox = manage (new HBox); - hbox->set_spacing (4); - hbox->pack_start (*manage (new Label (_("Browse:"))), PACK_SHRINK); - hbox->pack_start (existing_session_chooser); - session_existing_vbox.pack_start (*hbox, false, false); - hbox->show_all (); - } - - session_existing_vbox.show_all (); - session_hbox.pack_start (session_existing_vbox, true, true); - - set_page_title (session_vbox, _("Select a session")); - set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM); - session_hbox.show_all(); -} - void ArdourStartup::more_new_session_options_button_clicked () { if (more_new_session_options_button.get_active()) { more_options_vbox.show_all (); set_page_type (more_options_vbox, ASSISTANT_PAGE_CONFIRM); - set_page_type (session_vbox, ASSISTANT_PAGE_CONTENT); + set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); } else { - set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM); + set_page_type (session_new_vbox, ASSISTANT_PAGE_CONFIRM); more_options_vbox.hide (); } } @@ -1385,19 +1353,21 @@ ArdourStartup::move_along_now () { gint cur = get_current_page (); - if (cur == session_page_index) { + if (cur == new_session_page_index) { if (more_new_session_options_button.get_active()) { set_current_page (session_options_page_index); } else { on_apply (); } + } else { + on_apply (); } } void ArdourStartup::recent_row_activated (const Gtk::TreePath&, Gtk::TreeViewColumn*) { - set_page_complete (session_vbox, true); + set_page_complete (ic_vbox, true); move_along_now (); } @@ -1406,7 +1376,8 @@ ArdourStartup::existing_session_selected () { _existing_session_chooser_used = true; - set_page_complete (session_vbox, true); + session_selected (); + set_page_complete (ic_vbox, true); move_along_now (); } diff --git a/gtk2_ardour/startup.h b/gtk2_ardour/startup.h index 4dcc3a9fb2..7ddb3830a4 100644 --- a/gtk2_ardour/startup.h +++ b/gtk2_ardour/startup.h @@ -90,7 +90,7 @@ class ArdourStartup : public Gtk::Assistant { void on_apply (); void on_cancel (); bool on_delete_event (GdkEventAny*); - void on_prepare (Gtk::Widget*); + void on_prepare (Gtk::Widget*); static ArdourStartup *the_startup; @@ -113,10 +113,8 @@ class ArdourStartup : public Gtk::Assistant { void setup_initial_choice_page (); Gtk::VBox ic_vbox; - Gtk::RadioButton ic_new_session_button; - Gtk::RadioButton ic_existing_session_button; - bool initial_button_clicked(GdkEventButton*); - void initial_button_activated(); + Gtk::Button ic_new_session_button; + void new_session_button_clicked (); /* monitoring choices */ @@ -134,11 +132,6 @@ class ArdourStartup : public Gtk::Assistant { Gtk::RadioButton no_monitor_section_button; void setup_monitor_section_choice_page (); - /* session page (could be new or existing) */ - - void setup_session_page (); - Gtk::VBox session_vbox; - Gtk::HBox session_hbox; /* recent sessions */ @@ -171,6 +164,7 @@ class ArdourStartup : public Gtk::Assistant { void recent_row_activated (const Gtk::TreePath& path, Gtk::TreeViewColumn* col); void existing_session_selected (); + void session_selected (); /* new sessions */ @@ -278,7 +272,7 @@ class ArdourStartup : public Gtk::Assistant { gint default_folder_page_index; gint monitoring_page_index; gint monitor_section_page_index; - gint session_page_index; + gint new_session_page_index; gint initial_choice_index; gint final_page_index; gint session_options_page_index; From b188033bf752bfd32557f9b7078738a20b59d09b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 20 Sep 2013 14:30:50 -0400 Subject: [PATCH 08/42] rather hacky fix for the change of the SyncSource > JACK enum to SyncSource > Engine This is needed in order to get ardour started if ardour.rc names "JACK" as the sync source --- libs/ardour/ardour/types.h | 3 ++- libs/ardour/enums.cc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 658c64788e..ca3f1acc19 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -489,7 +489,8 @@ namespace ARDOUR { }; enum SyncSource { - Engine, + Engine = 0, + JACK = 0, MTC, MIDIClock, LTC diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 8fec499c35..3898a0e881 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -336,6 +336,7 @@ setup_enum_writer () REGISTER_ENUM (MTC); REGISTER_ENUM (Engine); + REGISTER_ENUM (JACK); REGISTER_ENUM (MIDIClock); REGISTER_ENUM (LTC); REGISTER (_SyncSource); From 53bd17d938887766eb56833205131b68d7e5cb1d Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 20 Sep 2013 16:05:54 -0400 Subject: [PATCH 09/42] move advanced new session options into an expander, change some wording --- gtk2_ardour/startup.cc | 56 ++++++------------------------------------ gtk2_ardour/startup.h | 5 ++-- 2 files changed, 10 insertions(+), 51 deletions(-) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index 36f399224f..52aa680f12 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -74,7 +74,7 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name, "%1 will play NO role in monitoring"), PROGRAM_NAME)) , monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME)) , new_folder_chooser (FILE_CHOOSER_ACTION_SELECT_FOLDER) - , more_new_session_options_button (_("I'd like more options for this session")) + , more_new_session_options_button (_("Advanced options ...")) , _output_limit_count_adj (1, 0, 100, 1, 10, 0) , _input_limit_count_adj (1, 0, 100, 1, 10, 0) , _master_bus_channel_count_adj (2, 0, 100, 1, 10, 0) @@ -146,8 +146,6 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name, setup_new_session_page (); } - setup_more_options_page (); - if (!template_name.empty()) { use_template_button.set_active (false); load_template_override = template_name; @@ -638,11 +636,7 @@ ArdourStartup::session_selected () Gtk::Widget* def = wrap (gtk_window_get_default_widget (win->gobj())); Gtk::Button* button; if ((button = dynamic_cast(def)) != 0) { - if (more_new_session_options_button.get_active()) { - button->set_label (_("Next")); - } else { - button->set_label (_("Open")); - } + button->set_label (_("Open")); } } } @@ -832,11 +826,6 @@ ArdourStartup::setup_new_session_page () vbox2->set_spacing (6); - label3->set_markup (_("Options")); - label3->set_alignment (0.0, 0.0); - - vbox2->pack_start (*label3, false, true); - VBox *vbox3 = manage (new VBox); vbox3->set_spacing (6); @@ -899,8 +888,8 @@ ArdourStartup::setup_new_session_page () hbox5->set_spacing (6); hbox5->pack_start (more_new_session_options_button, false, false); - more_new_session_options_button.show (); - more_new_session_options_button.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::more_new_session_options_button_clicked)); + setup_more_options_box (); + more_new_session_options_button.add (more_options_vbox); vbox3->pack_start (*hbox5, false, false); hbox3->pack_start (*vbox3, true, true, 8); @@ -917,11 +906,7 @@ ArdourStartup::setup_new_session_page () set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); set_page_title (session_new_vbox, _("New Session")); - if (more_new_session_options_button.get_active()) { - set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); - } else { - set_page_type (session_new_vbox, ASSISTANT_PAGE_CONFIRM); - } + set_page_type (session_new_vbox, ASSISTANT_PAGE_CONFIRM); } void @@ -1037,20 +1022,7 @@ ArdourStartup::recent_session_row_selected () } void -ArdourStartup::more_new_session_options_button_clicked () -{ - if (more_new_session_options_button.get_active()) { - more_options_vbox.show_all (); - set_page_type (more_options_vbox, ASSISTANT_PAGE_CONFIRM); - set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); - } else { - set_page_type (session_new_vbox, ASSISTANT_PAGE_CONFIRM); - more_options_vbox.hide (); - } -} - -void -ArdourStartup::setup_more_options_page () +ArdourStartup::setup_more_options_box () { more_options_vbox.set_border_width (24); @@ -1234,10 +1206,6 @@ ArdourStartup::setup_more_options_page () * doesn't resize. */ more_options_vbox.show_all (); - - session_options_page_index = append_page (more_options_vbox); - set_page_title (more_options_vbox, _("Advanced Session Options")); - set_page_complete (more_options_vbox, true); } bool @@ -1351,17 +1319,7 @@ ArdourStartup::master_bus_button_clicked () void ArdourStartup::move_along_now () { - gint cur = get_current_page (); - - if (cur == new_session_page_index) { - if (more_new_session_options_button.get_active()) { - set_current_page (session_options_page_index); - } else { - on_apply (); - } - } else { - on_apply (); - } + on_apply (); } void diff --git a/gtk2_ardour/startup.h b/gtk2_ardour/startup.h index 7ddb3830a4..2703ac7638 100644 --- a/gtk2_ardour/startup.h +++ b/gtk2_ardour/startup.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -189,7 +190,7 @@ class ArdourStartup : public Gtk::Assistant { Gtk::VBox session_new_vbox; Gtk::VBox session_existing_vbox; - Gtk::CheckButton more_new_session_options_button; + Gtk::Expander more_new_session_options_button; Gtk::RadioButtonGroup session_template_group; Gtk::RadioButton use_session_as_template_button; Gtk::RadioButton use_template_button; @@ -254,7 +255,7 @@ class ArdourStartup : public Gtk::Assistant { void limit_inputs_clicked (); void limit_outputs_clicked (); void master_bus_button_clicked (); - void setup_more_options_page (); + void setup_more_options_box (); /* final page */ From 3e5c1e3fc15629b1d986e9b4c03c7c12c8d63b68 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 20 Sep 2013 16:16:30 -0400 Subject: [PATCH 10/42] Revert "actually load new state after creating a session." This reverts commit 914ba475de48f72e57bb6ac8a81888ad71cea7fa. Unclear why I applied this or what it was supposed to do. A new session has no state. --- libs/ardour/session.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index ccb3b6bb38..4be52a7584 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -276,10 +276,6 @@ Session::Session (AudioEngine &eng, throw failed_constructor (); } - if (load_state (_current_snapshot_name)) { - throw failed_constructor (); - } - } else { if (load_state (_current_snapshot_name)) { From 461f94a3a177b87044b0dac7e38e21a06903813c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 20 Sep 2013 16:45:04 -0400 Subject: [PATCH 11/42] if new session button clicked, clear any selection in recent sessions and mark browser unused --- gtk2_ardour/startup.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index 52aa680f12..b0cbcef4a2 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -644,6 +644,8 @@ ArdourStartup::session_selected () void ArdourStartup::new_session_button_clicked () { + _existing_session_chooser_used = false; + recent_session_display.get_selection()->unselect_all (); set_current_page (new_session_page_index); } From f7586f3a0d3492a15cae901bb209f6a983e7db0a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 21 Sep 2013 12:50:45 -0400 Subject: [PATCH 12/42] likely fix for creating new sessions from templates --- libs/ardour/session.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 4be52a7584..d45375fe0d 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -276,6 +276,21 @@ Session::Session (AudioEngine &eng, throw failed_constructor (); } + /* if a mix template was provided, then ::create() will + * have copied it into the session and we need to load it + * so that we have the state ready for ::set_state() + * after the engine is started. + * + * Note that we do NOT try to get the sample rate from + * the template at this time, though doing so would + * be easy if we decided this was an appropriate part + * of a template. + */ + + if (!mix_template.empty() && load_state (_current_snapshot_name)) { + throw failed_constructor (); + } + } else { if (load_state (_current_snapshot_name)) { From 2577bf55c9d3a12d6438308bdc342a4b1736e8ed Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 21 Sep 2013 12:51:30 -0400 Subject: [PATCH 13/42] reset the visibility of the template selector stuff every time the startup/NSD gets mapped, so that it is always current --- gtk2_ardour/startup.cc | 301 +++++++++++++++++++++-------------------- gtk2_ardour/startup.h | 1 + 2 files changed, 158 insertions(+), 144 deletions(-) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index b0cbcef4a2..6c68f69fad 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -751,157 +751,152 @@ ArdourStartup::setup_new_session_page () session_new_vbox.set_border_width (12); session_new_vbox.set_spacing (18); - if (session_new_vbox.get_children().empty()) { - VBox *vbox1 = manage (new VBox); - HBox* hbox1 = manage (new HBox); - Label* label1 = manage (new Label); + VBox *vbox1 = manage (new VBox); + HBox* hbox1 = manage (new HBox); + Label* label1 = manage (new Label); - vbox1->set_spacing (6); + vbox1->set_spacing (6); - hbox1->set_spacing (6); - hbox1->pack_start (*label1, false, false); - hbox1->pack_start (new_name_entry, true, true); + hbox1->set_spacing (6); + hbox1->pack_start (*label1, false, false); + hbox1->pack_start (new_name_entry, true, true); - label1->set_text (_("Session name:")); + label1->set_text (_("Session name:")); - if (!ARDOUR_COMMAND_LINE::session_name.empty()) { - new_name_entry.set_text (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name)); - /* name provided - they can move right along */ - set_page_complete (session_new_vbox, true); - } - - new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_changed)); - new_name_entry.signal_activate().connect (sigc::mem_fun (*this, &ArdourStartup::move_along_now)); - - vbox1->pack_start (*hbox1, true, true); - - /* --- */ - - HBox* hbox2 = manage (new HBox); - Label* label2 = manage (new Label); - - hbox2->set_spacing (6); - hbox2->pack_start (*label2, false, false); - hbox2->pack_start (new_folder_chooser, true, true); - - label2->set_text (_("Create session folder in:")); - - if (!ARDOUR_COMMAND_LINE::session_name.empty()) { - new_folder_chooser.set_current_folder (poor_mans_glob (Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name))); - } else if (ARDOUR_UI::instance()->session_loaded) { - // point the new session file chooser at the parent directory of the current session - string session_parent_dir = Glib::path_get_dirname(ARDOUR_UI::instance()->the_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); - new_folder_chooser.set_current_folder (session_parent_dir); - string default_session_folder = poor_mans_glob (Config->get_default_session_parent_dir()); - - try { - /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */ - new_folder_chooser.add_shortcut_folder (default_session_folder); - } - catch (Glib::Error & e) { - std::cerr << "new_folder_chooser.add_shortcut_folder (" << default_session_folder << ") threw Glib::Error " << e.what() << std::endl; - } - } else { - new_folder_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); - } - new_folder_chooser.show (); - new_folder_chooser.set_title (_("Select folder for session")); - -#ifdef __APPLE__ - new_folder_chooser.add_shortcut_folder ("/Volumes"); -#endif - - vbox1->pack_start (*hbox2, false, false); - - session_new_vbox.pack_start (*vbox1, false, false); - - /* --- */ - - VBox *vbox2 = manage (new VBox); - HBox* hbox3 = manage (new HBox); - Label* label3 = manage (new Label); - template_model = ListStore::create (session_template_columns); - populate_session_templates (); - - vbox2->set_spacing (6); - - VBox *vbox3 = manage (new VBox); - - vbox3->set_spacing (6); - - if (!template_model->children().empty()) { - - HBox* hbox4a = manage (new HBox); - use_template_button.set_label (_("Use this template")); - - TreeModel::Row row = *template_model->prepend (); - row[session_template_columns.name] = (_("no template")); - row[session_template_columns.path] = string(); - - hbox4a->set_spacing (6); - hbox4a->pack_start (use_template_button, false, false); - hbox4a->pack_start (template_chooser, true, true); - - template_chooser.set_model (template_model); - - Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText); - text_renderer->property_editable() = false; - - template_chooser.pack_start (*text_renderer); - template_chooser.add_attribute (text_renderer->property_text(), session_template_columns.name); - template_chooser.set_active (0); - - use_template_button.show(); - template_chooser.show (); - - vbox3->pack_start (*hbox4a, false, false); - } - - /* --- */ - - if (!new_user) { - session_template_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); - - HBox* hbox4b = manage (new HBox); - use_session_as_template_button.set_label (_("Use an existing session as a template:")); - - hbox4b->set_spacing (6); - hbox4b->pack_start (use_session_as_template_button, false, false); - hbox4b->pack_start (session_template_chooser, true, true); - - use_session_as_template_button.show (); - session_template_chooser.show (); - - Gtk::FileFilter* session_filter = manage (new (Gtk::FileFilter)); - session_filter->add_pattern (X_("*.ardour")); - session_template_chooser.set_filter (*session_filter); - session_template_chooser.set_title (_("Select template")); - - vbox3->pack_start (*hbox4b, false, false); - } - - /* --- */ - - HBox* hbox5 = manage (new HBox); - - hbox5->set_spacing (6); - hbox5->pack_start (more_new_session_options_button, false, false); - - setup_more_options_box (); - more_new_session_options_button.add (more_options_vbox); - - vbox3->pack_start (*hbox5, false, false); - hbox3->pack_start (*vbox3, true, true, 8); - vbox2->pack_start (*hbox3, false, false); - - /* --- */ - - session_new_vbox.pack_start (*vbox2, false, false); + if (!ARDOUR_COMMAND_LINE::session_name.empty()) { + new_name_entry.set_text (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name)); + /* name provided - they can move right along */ + set_page_complete (session_new_vbox, true); } + new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_changed)); + new_name_entry.signal_activate().connect (sigc::mem_fun (*this, &ArdourStartup::move_along_now)); + + vbox1->pack_start (*hbox1, true, true); + + /* --- */ + + HBox* hbox2 = manage (new HBox); + Label* label2 = manage (new Label); + + hbox2->set_spacing (6); + hbox2->pack_start (*label2, false, false); + hbox2->pack_start (new_folder_chooser, true, true); + + label2->set_text (_("Create session folder in:")); + + if (!ARDOUR_COMMAND_LINE::session_name.empty()) { + new_folder_chooser.set_current_folder (poor_mans_glob (Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name))); + } else if (ARDOUR_UI::instance()->session_loaded) { + // point the new session file chooser at the parent directory of the current session + string session_parent_dir = Glib::path_get_dirname(ARDOUR_UI::instance()->the_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); + new_folder_chooser.set_current_folder (session_parent_dir); + string default_session_folder = poor_mans_glob (Config->get_default_session_parent_dir()); + + try { + /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */ + new_folder_chooser.add_shortcut_folder (default_session_folder); + } + catch (Glib::Error & e) { + std::cerr << "new_folder_chooser.add_shortcut_folder (" << default_session_folder << ") threw Glib::Error " << e.what() << std::endl; + } + } else { + new_folder_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); + } + new_folder_chooser.show (); + new_folder_chooser.set_title (_("Select folder for session")); + +#ifdef __APPLE__ + new_folder_chooser.add_shortcut_folder ("/Volumes"); +#endif + + vbox1->pack_start (*hbox2, false, false); + + session_new_vbox.pack_start (*vbox1, false, false); + + /* --- */ + + VBox *vbox2 = manage (new VBox); + HBox* hbox3 = manage (new HBox); + template_model = ListStore::create (session_template_columns); + + vbox2->set_spacing (6); + + VBox *vbox3 = manage (new VBox); + + vbox3->set_spacing (6); + + /* we may want to hide this and show it at various + times depending on the existence of templates. + */ + template_chooser.set_no_show_all (true); + use_template_button.set_no_show_all (true); + + HBox* hbox4a = manage (new HBox); + use_template_button.set_label (_("Use this template")); + + TreeModel::Row row = *template_model->prepend (); + row[session_template_columns.name] = (_("no template")); + row[session_template_columns.path] = string(); + + hbox4a->set_spacing (6); + hbox4a->pack_start (use_template_button, false, false); + hbox4a->pack_start (template_chooser, true, true); + + template_chooser.set_model (template_model); + + Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText); + text_renderer->property_editable() = false; + + template_chooser.pack_start (*text_renderer); + template_chooser.add_attribute (text_renderer->property_text(), session_template_columns.name); + template_chooser.set_active (0); + + vbox3->pack_start (*hbox4a, false, false); + + /* --- */ + + if (!new_user) { + session_template_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); + + HBox* hbox4b = manage (new HBox); + use_session_as_template_button.set_label (_("Use an existing session as a template:")); + + hbox4b->set_spacing (6); + hbox4b->pack_start (use_session_as_template_button, false, false); + hbox4b->pack_start (session_template_chooser, true, true); + + use_session_as_template_button.show (); + session_template_chooser.show (); + + Gtk::FileFilter* session_filter = manage (new (Gtk::FileFilter)); + session_filter->add_pattern (X_("*.ardour")); + session_template_chooser.set_filter (*session_filter); + session_template_chooser.set_title (_("Select template")); + + vbox3->pack_start (*hbox4b, false, false); + } + + /* --- */ + + HBox* hbox5 = manage (new HBox); + + hbox5->set_spacing (6); + hbox5->pack_start (more_new_session_options_button, false, false); + + setup_more_options_box (); + more_new_session_options_button.add (more_options_vbox); + + vbox3->pack_start (*hbox5, false, false); + hbox3->pack_start (*vbox3, true, true, 8); + vbox2->pack_start (*hbox3, false, false); + + /* --- */ + + session_new_vbox.pack_start (*vbox2, false, false); session_new_vbox.show_all (); new_session_page_index = append_page (session_new_vbox); @@ -1372,3 +1367,21 @@ ArdourStartup::info_scroller_update() return true; } + +void +ArdourStartup::on_map () +{ + Gtk::Assistant::on_map (); + + redisplay_recent_sessions (); + populate_session_templates (); + + if (!template_model->children().empty()) { + use_template_button.show(); + template_chooser.show (); + } else { + use_template_button.hide(); + template_chooser.hide (); + } +} + diff --git a/gtk2_ardour/startup.h b/gtk2_ardour/startup.h index 2703ac7638..fce2bdb2db 100644 --- a/gtk2_ardour/startup.h +++ b/gtk2_ardour/startup.h @@ -92,6 +92,7 @@ class ArdourStartup : public Gtk::Assistant { void on_cancel (); bool on_delete_event (GdkEventAny*); void on_prepare (Gtk::Widget*); + void on_map (); static ArdourStartup *the_startup; From 482a90cccfe458c354b39e60856909eb863010f2 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 21 Sep 2013 13:14:33 -0400 Subject: [PATCH 14/42] apply same always-check-display to recent sessions scroller in new session dialog It turns out that we always create a new ArdourStartup right now, so this and the previous commit are not actually necessary, but they do pave the way for keeping the dialog around instead --- gtk2_ardour/startup.cc | 67 +++++++++++++++++++++--------------------- gtk2_ardour/startup.h | 1 + 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index 6c68f69fad..ed6d3b020e 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -546,45 +546,32 @@ ArdourStartup::setup_initial_choice_page () info_box->pack_start (*updates_button, false, false); } - ARDOUR::RecentSessions rs; - ARDOUR::read_recent_sessions (rs); - - if (!rs.empty()) { + /* recent session scroller */ - /* recent session scroller */ - - Label* load_label = manage (new Label); - load_label->set_markup (string_compose ("%1", _("Load a recent session"))); - load_label->set_alignment (0, 0.5); - - centering_vbox->pack_start (*load_label, false, false, 12); - - recent_session_model = TreeStore::create (recent_session_columns); - redisplay_recent_sessions (); - - 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_label.set_no_show_all (true); + recent_scroller.set_no_show_all (true); - recent_session_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected)); + recent_label.set_markup (string_compose ("%1", _("Load a recent session"))); + recent_label.set_alignment (0, 0.5); - recent_scroller.add (recent_session_display); - recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - recent_scroller.set_shadow_type (Gtk::SHADOW_IN); + recent_session_model = TreeStore::create (recent_session_columns); - recent_session_display.show(); + 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_scroller.show(); - recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated)); + recent_session_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected)); - int cnt = redisplay_recent_sessions (); - if (cnt > 4) { - recent_scroller.set_size_request (-1, 300); - } + recent_scroller.add (recent_session_display); + recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + recent_scroller.set_shadow_type (Gtk::SHADOW_IN); - centering_vbox->pack_start (recent_scroller, false, true); - } + recent_session_display.show(); + recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated)); + + centering_vbox->pack_start (recent_label, false, false, 12); + centering_vbox->pack_start (recent_scroller, false, true); /* Browse button */ @@ -1373,7 +1360,6 @@ ArdourStartup::on_map () { Gtk::Assistant::on_map (); - redisplay_recent_sessions (); populate_session_templates (); if (!template_model->children().empty()) { @@ -1383,5 +1369,20 @@ ArdourStartup::on_map () use_template_button.hide(); template_chooser.hide (); } + + if (recent_session_model) { + int cnt = redisplay_recent_sessions (); + if (cnt > 0) { + recent_scroller.show(); + recent_label.show (); + + if (cnt > 4) { + recent_scroller.set_size_request (-1, 300); + } + } else { + recent_scroller.hide(); + recent_label.hide (); + } + } } diff --git a/gtk2_ardour/startup.h b/gtk2_ardour/startup.h index fce2bdb2db..45d11190f9 100644 --- a/gtk2_ardour/startup.h +++ b/gtk2_ardour/startup.h @@ -160,6 +160,7 @@ class ArdourStartup : public Gtk::Assistant { Gtk::TreeView recent_session_display; Glib::RefPtr recent_session_model; Gtk::ScrolledWindow recent_scroller; + Gtk::Label recent_label; Gtk::FileChooserButton existing_session_chooser; int redisplay_recent_sessions (); void recent_session_row_selected (); From e33b29d672a2bcad9fad4b797ba53dff1587c911 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 21 Sep 2013 13:22:06 -0400 Subject: [PATCH 15/42] make sure the template selector has an item visible if there are any --- gtk2_ardour/startup.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index ed6d3b020e..5d9e174249 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -730,6 +730,11 @@ ArdourStartup::populate_session_templates () row[session_template_columns.name] = (*x).name; row[session_template_columns.path] = (*x).path; } + + if (!templates.empty()) { + /* select first row */ + template_chooser.set_active (0); + } } void From 04d66a9e3ad2585b4bdd9ea3a022582ec2b9d428 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 21 Sep 2013 13:56:59 -0400 Subject: [PATCH 16/42] remove use-session-as-template option from new session dialog and fix ability to not use a template Note: using a template is still not actually working ... --- gtk2_ardour/startup.cc | 37 +++++-------------------------------- gtk2_ardour/startup.h | 5 +---- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index 5d9e174249..ff16d7c1e8 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -96,9 +96,6 @@ ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name, if (need_session_info || new_user) { - use_template_button.set_group (session_template_group); - use_session_as_template_button.set_group (session_template_group); - set_keep_above (true); set_position (WIN_POS_CENTER); set_border_width (12); @@ -207,9 +204,9 @@ ArdourStartup::use_session_template () if (use_template_button.get_active()) { return template_chooser.get_active_row_number() > 0; - } else { - return !session_template_chooser.get_filename().empty(); - } + } + + return false; } std::string @@ -225,10 +222,9 @@ ArdourStartup::session_template_name () TreeModel::Row row = (*iter); string s = row[session_template_columns.path]; return s; - } else { - return session_template_chooser.get_filename(); + } - } + return string(); } std::string @@ -849,29 +845,6 @@ ArdourStartup::setup_new_session_page () vbox3->pack_start (*hbox4a, false, false); - /* --- */ - - if (!new_user) { - session_template_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); - - HBox* hbox4b = manage (new HBox); - use_session_as_template_button.set_label (_("Use an existing session as a template:")); - - hbox4b->set_spacing (6); - hbox4b->pack_start (use_session_as_template_button, false, false); - hbox4b->pack_start (session_template_chooser, true, true); - - use_session_as_template_button.show (); - session_template_chooser.show (); - - Gtk::FileFilter* session_filter = manage (new (Gtk::FileFilter)); - session_filter->add_pattern (X_("*.ardour")); - session_template_chooser.set_filter (*session_filter); - session_template_chooser.set_title (_("Select template")); - - vbox3->pack_start (*hbox4b, false, false); - } - /* --- */ HBox* hbox5 = manage (new HBox); diff --git a/gtk2_ardour/startup.h b/gtk2_ardour/startup.h index 45d11190f9..361d00e9e1 100644 --- a/gtk2_ardour/startup.h +++ b/gtk2_ardour/startup.h @@ -174,7 +174,6 @@ class ArdourStartup : public Gtk::Assistant { void setup_new_session_page (); Gtk::Entry new_name_entry; Gtk::FileChooserButton new_folder_chooser; - Gtk::FileChooserButton session_template_chooser; struct SessionTemplateColumns : public Gtk::TreeModel::ColumnRecord { SessionTemplateColumns () { @@ -193,9 +192,7 @@ class ArdourStartup : public Gtk::Assistant { Gtk::VBox session_new_vbox; Gtk::VBox session_existing_vbox; Gtk::Expander more_new_session_options_button; - Gtk::RadioButtonGroup session_template_group; - Gtk::RadioButton use_session_as_template_button; - Gtk::RadioButton use_template_button; + Gtk::CheckButton use_template_button; std::string load_template_override; void more_new_session_options_button_clicked(); From 20f28c82ecec7725b0fb98dfe0539c0710328678 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 22 Sep 2013 11:19:34 -0400 Subject: [PATCH 17/42] make session creation from a template work again --- gtk2_ardour/startup.cc | 3 +-- libs/ardour/session_state.cc | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gtk2_ardour/startup.cc b/gtk2_ardour/startup.cc index ff16d7c1e8..06befae7f5 100644 --- a/gtk2_ardour/startup.cc +++ b/gtk2_ardour/startup.cc @@ -203,9 +203,8 @@ ArdourStartup::use_session_template () } if (use_template_button.get_active()) { - return template_chooser.get_active_row_number() > 0; + return true; } - return false; } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index c33fd91b5d..049cb5b5ee 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -493,9 +493,10 @@ Session::create (const string& session_template, BusProfile* bus_profile) ifstream in(in_path.c_str()); if (in) { - string out_path = _path; - out_path += _name; - out_path += statefile_suffix; + /* no need to call legalize_for_path() since the string + * in session_template is already a legal path name + */ + string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix); ofstream out(out_path.c_str()); From f1aa5839c0f35ef0ffbe1c739eafbe316025bf8a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 22 Sep 2013 19:22:56 -0400 Subject: [PATCH 18/42] use WindowManager/WMProxy to correctly manage the audio/MIDI setup window --- gtk2_ardour/ardour_ui.cc | 37 ++++--------------------------------- gtk2_ardour/ardour_ui.h | 3 +-- gtk2_ardour/ardour_ui_ed.cc | 3 +-- 3 files changed, 6 insertions(+), 37 deletions(-) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index f599442bc4..133b61c17f 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -191,6 +191,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , about (X_("about"), _("About")) , location_ui (X_("locations"), _("Locations")) , route_params (X_("inspector"), _("Tracks and Busses")) + , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup")) , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this)) , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this)) , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this)) @@ -202,7 +203,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , _status_bar_visibility (X_("status-bar")) , _feedback_exists (false) - , _audio_midi_setup (0) { Gtkmm2ext::init(localedir); @@ -213,7 +213,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) } ui_config = new UIConfiguration(); - _audio_midi_setup = new EngineControl; editor = 0; mixer = 0; @@ -348,6 +347,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) WM::Manager::instance().register_window (&add_route_dialog); WM::Manager::instance().register_window (&add_video_dialog); WM::Manager::instance().register_window (&route_params); + WM::Manager::instance().register_window (&audio_midi_setup); WM::Manager::instance().register_window (&bundle_manager); WM::Manager::instance().register_window (&location_ui); WM::Manager::instance().register_window (&big_clock_window); @@ -4077,41 +4077,12 @@ ARDOUR_UI::reset_route_peak_display (Route* route) } } -void -ARDOUR_UI::toggle_audio_midi_setup () -{ - Glib::RefPtr act = ActionManager::get_action (X_("Common"), X_("toggle-audio-midi-setup")); - if (!act) { - return; - } - - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic (act); - - if (tact->get_active()) { - launch_audio_midi_setup (); - } else { - _audio_midi_setup->hide (); - } -} - -void -ARDOUR_UI::launch_audio_midi_setup () -{ - if (!_audio_midi_setup) { - _audio_midi_setup = new EngineControl (); - } - - _audio_midi_setup->present (); -} - int ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate) { - launch_audio_midi_setup (); + audio_midi_setup->set_desired_sample_rate (desired_sample_rate); - _audio_midi_setup->set_desired_sample_rate (desired_sample_rate); - - switch (_audio_midi_setup->run()) { + switch (audio_midi_setup->run()) { case Gtk::RESPONSE_OK: return 0; case Gtk::RESPONSE_APPLY: diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index ea03c8590f..47d0f4f4e8 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -603,6 +603,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr WM::Proxy about; WM::Proxy location_ui; WM::Proxy route_params; + WM::Proxy audio_midi_setup; /* Windows/Dialogs that require a creator method */ @@ -747,8 +748,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr std::string _announce_string; void check_announcements (); - EngineControl* _audio_midi_setup; - void launch_audio_midi_setup (); int do_audio_midi_setup (uint32_t); }; diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index 96bbd8c4e3..251fc8f6fc 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -197,7 +197,6 @@ ARDOUR_UI::install_actions () ActionManager::register_toggle_action (common_actions, X_("toggle-mixer"), S_("Window|Mixer"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_mixer_window)); ActionManager::register_action (common_actions, X_("toggle-editor-mixer"), _("Toggle Editor+Mixer"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_editor_mixer)); ActionManager::register_toggle_action (common_actions, X_("toggle-meterbridge"), S_("Window|Meterbridge"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_meterbridge)); - ActionManager::register_toggle_action (common_actions, X_("toggle-audio-midi-setup"), S_("Window|Audio/MIDI Setup"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_audio_midi_setup)); act = ActionManager::register_action (common_actions, X_("NewMIDITracer"), _("MIDI Tracer"), sigc::mem_fun(*this, &ARDOUR_UI::new_midi_tracer_window)); ActionManager::session_sensitive_actions.push_back (act); @@ -560,7 +559,7 @@ ARDOUR_UI::save_ardour_state () window_node->add_child_nocopy (*tearoff_node); Config->add_extra_xml (*window_node); - Config->add_extra_xml (_audio_midi_setup->get_state()); + Config->add_extra_xml (audio_midi_setup->get_state()); Config->save_state(); From c72748508bf8c9f8ce189f834d3c3114ef27952d Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2013 13:33:28 -0400 Subject: [PATCH 19/42] the output of git describe --tags is not subject to localization, so we do not need LANG= in the environment when it runs --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index b3902c1b49..fded3e1652 100644 --- a/wscript +++ b/wscript @@ -67,7 +67,7 @@ def fetch_gcc_version (CC): return version def fetch_git_revision (): - cmd = "LANG= git describe --tags HEAD" + cmd = "git describe --tags HEAD" output = subprocess.Popen(cmd, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0].splitlines() rev = output[0].decode('utf-8') return rev From b362ff220cbd1a17f1b6621b624d3801101fad3e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2013 14:41:52 -0400 Subject: [PATCH 20/42] major rearrangement of startup/session loading code first-time user code remains in ArdourStartup session selection/setup moved to SessionDialog many other cleanups, logic improvements, and so forth to the overall session loading process. Not 100% finished yet. --- gtk2_ardour/ardour_ui.cc | 123 ++-- gtk2_ardour/ardour_ui.h | 11 +- gtk2_ardour/engine_dialog.cc | 1 + gtk2_ardour/session_dialog.cc | 997 ++++++++++++++++++++++++++++++++ gtk2_ardour/session_dialog.h | 231 ++++++++ gtk2_ardour/small-splash.png | Bin 0 -> 26238 bytes gtk2_ardour/startup.cc | 1015 ++------------------------------- gtk2_ardour/startup.h | 173 +----- gtk2_ardour/utils.cc | 2 +- gtk2_ardour/wscript | 1 + 10 files changed, 1354 insertions(+), 1200 deletions(-) create mode 100644 gtk2_ardour/session_dialog.cc create mode 100644 gtk2_ardour/session_dialog.h create mode 100644 gtk2_ardour/small-splash.png diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 133b61c17f..129b77f0a4 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -109,6 +109,7 @@ typedef uint64_t microseconds_t; #include "rc_option_editor.h" #include "route_time_axis.h" #include "route_params_ui.h" +#include "session_dialog.h" #include "session_metadata_dialog.h" #include "session_option_editor.h" #include "shuttle_control.h" @@ -156,7 +157,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) /* start of private members */ - , _startup (0) , nsm (0) , _was_dirty (false) , _mixer_on_top (false) @@ -775,10 +775,33 @@ ARDOUR_UI::startup () delete nsm; nsm = 0; } - } - else if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) { - exit (1); + } else { + + if (ArdourStartup::required()) { + ArdourStartup s; + s.present (); + main().run(); + s.hide (); + switch (s.response ()) { + case Gtk::RESPONSE_REJECT: + exit (1); + default: + break; + } + } + + /* we need to create this early because it may need to set the + * audio backend end up. + */ + + audio_midi_setup.get (true); + + /* go get a session */ + + if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) { + exit (1); + } } use_config (); @@ -2431,7 +2454,7 @@ ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path) } int -ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name) +ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name) { BusProfile bus_profile; @@ -2447,13 +2470,13 @@ ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::s /* get settings from advanced section of NSD */ - if (_startup->create_master_bus()) { - bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count(); + if (sd.create_master_bus()) { + bus_profile.master_out_channels = (uint32_t) sd.master_channel_count(); } else { bus_profile.master_out_channels = 0; } - if (_startup->connect_inputs()) { + if (sd.connect_inputs()) { bus_profile.input_ac = AutoConnectPhysical; } else { bus_profile.input_ac = AutoConnectOption (0); @@ -2461,16 +2484,16 @@ ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::s bus_profile.output_ac = AutoConnectOption (0); - if (_startup->connect_outputs ()) { - if (_startup->connect_outs_to_master()) { + if (sd.connect_outputs ()) { + if (sd.connect_outs_to_master()) { bus_profile.output_ac = AutoConnectMaster; - } else if (_startup->connect_outs_to_physical()) { + } else if (sd.connect_outs_to_physical()) { bus_profile.output_ac = AutoConnectPhysical; } } - bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count(); - bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count(); + bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count(); + bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count(); } if (build_session (session_path, session_name, bus_profile)) { @@ -2529,6 +2552,8 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri template_name = load_template; } + SessionDialog session_dialog (should_be_new, session_name, session_path, load_template); + while (ret != 0) { if (!ARDOUR_COMMAND_LINE::session_name.empty()) { @@ -2553,31 +2578,28 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri session_name = ""; } - delete _startup; - _startup = new ArdourStartup (should_be_new, session_name, session_path, load_template); - - if (!_startup->ready_without_display()) { - _startup->present (); - main().run(); - _startup->hide (); - } - - switch (_startup->response()) { - case RESPONSE_OK: - break; - default: - if (quit_on_cancel) { - exit (1); - } else { - return ret; + if (should_be_new || session_name.empty()) { + /* need the dialog to get info from user */ + + switch (session_dialog.run()) { + case RESPONSE_ACCEPT: + break; + default: + if (quit_on_cancel) { + exit (1); + } else { + return ret; + } } + + session_dialog.hide (); } /* if we run the startup dialog again, offer more than just "new session" */ should_be_new = false; - session_name = _startup->session_name (likely_new); + session_name = session_dialog.session_name (likely_new); if (nsm) { likely_new = true; @@ -2595,8 +2617,8 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri continue; } - if (_startup->use_session_template()) { - template_name = _startup->session_template_name(); + if (session_dialog.use_session_template()) { + template_name = session_dialog.session_template_name(); _session_is_new = true; } @@ -2613,12 +2635,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } else { - session_path = _startup->session_folder(); + session_path = session_dialog.session_folder(); char illegal = Session::session_name_is_legal (session_name); if (illegal) { - MessageDialog msg (*_startup, + MessageDialog msg (session_dialog, string_compose (_("To ensure compatibility with various systems\n" "session names may not contain a '%1' character"), illegal)); @@ -2645,12 +2667,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } else { if (!likely_new) { - if (_startup) { - pop_back_splash (*_startup); - } else { - hide_splash (); - } - + pop_back_splash (session_dialog); MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path)); msg.run (); ARDOUR_COMMAND_LINE::session_name = ""; // cancel that @@ -2659,8 +2676,8 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri 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" + pop_back_splash (session_dialog); + MessageDialog msg (session_dialog, 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 @@ -2672,7 +2689,9 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri if (likely_new && template_name.empty()) { - ret = build_session_from_nsd (session_path, session_name); + cerr << "building a session from dialog\n"; + + ret = build_session_from_dialog (session_dialog, session_path, session_name); } else { @@ -2779,22 +2798,12 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, Gtk::MESSAGE_INFO, BUTTONS_OK); + msg.set_keep_above (true); 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); - } - + (void) msg.run (); msg.hide (); goto out; @@ -4080,6 +4089,8 @@ ARDOUR_UI::reset_route_peak_display (Route* route) int ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate) { + cerr << "Do AMS\n"; + audio_midi_setup->set_desired_sample_rate (desired_sample_rate); switch (audio_midi_setup->run()) { diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 47d0f4f4e8..191df0d31d 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -83,7 +83,6 @@ class AddRouteDialog; class AddVideoDialog; class VideoTimeLine; class SystemExec; -class ArdourStartup; class ArdourKeyboard; class AudioClock; class BigClockWindow; @@ -98,6 +97,7 @@ class Mixer_UI; class PublicEditor; class RCOptionEditor; class RouteParams_UI; +class SessionDialog; class SessionOptionEditor; class ShuttleControl; class Splash; @@ -153,7 +153,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr bool get_smart_mode () const; int get_session_parameters (bool quit_on_cancel, bool should_be_new = false, std::string load_template = ""); - int build_session_from_nsd (const std::string& session_name, const std::string& session_path); + int build_session_from_dialog (SessionDialog&, const std::string& session_name, const std::string& session_path); bool ask_about_loading_existing_session (const std::string& session_path); /// @return true if session was successfully unloaded. @@ -312,11 +312,10 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr void toggle_session_options_window (); private: - ArdourStartup* _startup; - Gtk::Tooltips _tooltips; + Gtk::Tooltips _tooltips; NSM_Client *nsm; - bool _was_dirty; - bool _mixer_on_top; + bool _was_dirty; + bool _mixer_on_top; bool first_time_engine_run; void goto_editor_window (); diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index b10cc626b6..79bda1bcc5 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -234,6 +234,7 @@ EngineControl::EngineControl () ARDOUR::AudioEngine::instance()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context()); ARDOUR::AudioEngine::instance()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineControl::engine_stopped, this), gui_context()); + cerr << "AMS about to change backend\n"; backend_changed (); if (audio_setup) { diff --git a/gtk2_ardour/session_dialog.cc b/gtk2_ardour/session_dialog.cc new file mode 100644 index 0000000000..481b587b71 --- /dev/null +++ b/gtk2_ardour/session_dialog.cc @@ -0,0 +1,997 @@ +/* + Copyright (C) 2013 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifdef WAF_BUILD +#include "gtk2ardour-config.h" +#endif + +#include +#include + +#include + +#include "pbd/failed_constructor.h" +#include "pbd/file_utils.h" +#include "pbd/replace_all.h" +#include "pbd/whitespace.h" +#include "pbd/stacktrace.h" +#include "pbd/openuri.h" + +#include "ardour/audioengine.h" +#include "ardour/filesystem_paths.h" +#include "ardour/recent_sessions.h" +#include "ardour/session.h" +#include "ardour/session_state_utils.h" +#include "ardour/template_utils.h" +#include "ardour/filename_extensions.h" + +#include "ardour_ui.h" +#include "session_dialog.h" +#include "opts.h" +#include "engine_dialog.h" +#include "i18n.h" +#include "utils.h" + +using namespace std; +using namespace Gtk; +using namespace Gdk; +using namespace Glib; +using namespace PBD; +using namespace ARDOUR; + +static string poor_mans_glob (string path) +{ + string copy = path; + replace_all (copy, "~", Glib::get_home_dir()); + return copy; +} + +SessionDialog::SessionDialog (bool require_new, const std::string& session_name, const std::string& session_path, const std::string& template_name) + : ArdourDialog (_("Session Setup")) + , new_only (require_new) + , _provided_session_name (session_name) + , _provided_session_path (session_path) + , new_folder_chooser (FILE_CHOOSER_ACTION_SELECT_FOLDER) + , more_new_session_options_button (_("Advanced options ...")) + , _output_limit_count_adj (1, 0, 100, 1, 10, 0) + , _input_limit_count_adj (1, 0, 100, 1, 10, 0) + , _master_bus_channel_count_adj (2, 0, 100, 1, 10, 0) + , _existing_session_chooser_used (false) +{ + if (!session_name.empty() && !require_new) { + response (RESPONSE_OK); + return; + } + + set_keep_above (true); + set_position (WIN_POS_CENTER); + + string image_path; + + if (find_file_in_search_path (ardour_data_search_path(), "small-splash.png", image_path)) { + Gtk::Image* image; + if ((image = manage (new Gtk::Image (image_path))) != 0) { + get_vbox()->pack_start (*image, false, false); + } + } + + setup_new_session_page (); + + if (!new_only) { + setup_initial_choice_box (); + get_vbox()->pack_start (ic_vbox, true, true); + } else { + get_vbox()->pack_start (session_new_vbox, true, true); + } + + if (!template_name.empty()) { + use_template_button.set_active (false); + load_template_override = template_name; + } + + get_vbox()->show_all (); + + cancel_button = add_button (Stock::QUIT, RESPONSE_CANCEL); + back_button = add_button (Stock::GO_BACK, RESPONSE_NO); + open_button = add_button (Stock::OPEN, RESPONSE_ACCEPT); + + back_button->signal_button_press_event().connect (sigc::mem_fun (*this, &SessionDialog::back_button_pressed), false); + + open_button->set_sensitive (false); + back_button->set_sensitive (false); + + /* fill data models and how/hide accordingly */ + + populate_session_templates (); + + if (!template_model->children().empty()) { + use_template_button.show(); + template_chooser.show (); + } else { + use_template_button.hide(); + template_chooser.hide (); + } + + if (recent_session_model) { + int cnt = redisplay_recent_sessions (); + if (cnt > 0) { + recent_scroller.show(); + recent_label.show (); + + if (cnt > 4) { + recent_scroller.set_size_request (-1, 300); + } + } else { + recent_scroller.hide(); + recent_label.hide (); + } + } +} + +SessionDialog::~SessionDialog() +{ +} + +bool +SessionDialog::use_session_template () +{ + if (!load_template_override.empty()) { + return true; + } + + if (use_template_button.get_active()) { + return true; + } + + return false; +} + +std::string +SessionDialog::session_template_name () +{ + if (!load_template_override.empty()) { + string the_path (ARDOUR::user_template_directory()); + return Glib::build_filename (the_path, load_template_override + ARDOUR::template_suffix); + } + + if (use_template_button.get_active()) { + TreeModel::iterator iter = template_chooser.get_active (); + TreeModel::Row row = (*iter); + string s = row[session_template_columns.path]; + return s; + } + + return string(); +} + +std::string +SessionDialog::session_name (bool& should_be_new) +{ + if (!_provided_session_name.empty() && !new_only) { + return _provided_session_name; + } + + /* Try recent session selection */ + + TreeIter iter = recent_session_display.get_selection()->get_selected(); + + if (iter) { + should_be_new = false; + return (*iter)[recent_session_columns.visible_name]; + } + + if (_existing_session_chooser_used) { + /* existing session chosen from file chooser */ + should_be_new = false; + return existing_session_chooser.get_filename (); + } else { + should_be_new = true; + string val = new_name_entry.get_text (); + strip_whitespace_edges (val); + return val; + } +} + +std::string +SessionDialog::session_folder () +{ + if (!_provided_session_path.empty() && !new_only) { + return _provided_session_path; + } + + /* Try recent session selection */ + + TreeIter iter = recent_session_display.get_selection()->get_selected(); + + if (iter) { + return (*iter)[recent_session_columns.fullpath]; + } + + if (_existing_session_chooser_used) { + /* existing session chosen from file chooser */ + return existing_session_chooser.get_current_folder (); + } else { + std::string legal_session_folder_name = legalize_for_path (new_name_entry.get_text()); + return Glib::build_filename (new_folder_chooser.get_current_folder(), legal_session_folder_name); + } +} + +void +SessionDialog::setup_initial_choice_box () +{ + ic_vbox.set_spacing (6); + ic_vbox.set_border_width (24); + + HBox* centering_hbox = manage (new HBox); + VBox* centering_vbox = manage (new VBox); + + centering_vbox->set_spacing (6); + + Label* new_label = manage (new Label); + new_label->set_markup (string_compose ("%1", _("Create a new session"))); + + ic_new_session_button.add (*new_label); + ic_new_session_button.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::new_session_button_clicked)); + + centering_vbox->pack_start (ic_new_session_button, false, true); + + /* Possible update message */ + + if (ARDOUR_UI::instance()->announce_string() != "" ) { + + Gtk::Frame *info_frame = manage(new Gtk::Frame); + info_frame->set_shadow_type(SHADOW_ETCHED_OUT); + centering_vbox->pack_start (*info_frame, false, false, 20); + + Box *info_box = manage (new VBox); + info_box->set_border_width (12); + info_box->set_spacing (6); + info_box->set_name("mixbus_info_box"); + + info_box->pack_start (info_scroller_label, false, false); + + info_frame->add (*info_box); + info_frame->show_all(); + + info_scroller_count = 0; + info_scroller_connection = Glib::signal_timeout().connect (mem_fun(*this, &SessionDialog::info_scroller_update), 50); + + Gtk::Button *updates_button = manage (new Gtk::Button (_("Check the website for more..."))); + + updates_button->signal_clicked().connect (mem_fun(*this, &SessionDialog::updates_button_clicked) ); + ARDOUR_UI::instance()->tooltips().set_tip (*updates_button, _("Click to open the program website in your web browser")); + + info_box->pack_start (*updates_button, false, false); + } + + /* recent session scroller */ + + recent_label.set_no_show_all (true); + recent_scroller.set_no_show_all (true); + + recent_label.set_markup (string_compose ("%1", _("... or load a recent session"))); + recent_label.set_alignment (0, 0.5); + + recent_session_model = TreeStore::create (recent_session_columns); + + 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()->signal_changed().connect (sigc::mem_fun (*this, &SessionDialog::recent_session_row_selected)); + + recent_scroller.add (recent_session_display); + recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + recent_scroller.set_shadow_type (Gtk::SHADOW_IN); + + recent_session_display.show(); + recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &SessionDialog::recent_row_activated)); + + centering_vbox->pack_start (recent_label, false, false, 12); + centering_vbox->pack_start (recent_scroller, false, true); + + /* Browse button */ + + existing_session_chooser.set_title (_("Select session file")); + existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &SessionDialog::existing_session_selected)); + existing_session_chooser.set_current_folder(poor_mans_glob (Config->get_default_session_parent_dir())); + + FileFilter session_filter; + session_filter.add_pattern ("*.ardour"); + session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME)); + existing_session_chooser.add_filter (session_filter); + existing_session_chooser.set_filter (session_filter); + +#ifdef GTKOSX + existing_session_chooser.add_shortcut_folder ("/Volumes"); +#endif + + Label* browse_label = manage (new Label); + browse_label->set_markup (string_compose ("%1", _("... or browse for existing sessions"))); + browse_label->set_alignment (0, 0.5); + + centering_vbox->pack_start (*browse_label, false, false, 12); + centering_vbox->pack_start (existing_session_chooser, false, false); + + /* pack it all up */ + + centering_hbox->pack_start (*centering_vbox, true, true); + ic_vbox.pack_start (*centering_hbox, true, true); + ic_vbox.show_all (); +} + +void +SessionDialog::session_selected () +{ + /* HACK HACK HACK ... change the "Apply" button label + to say "Open" + */ + + Gtk::Widget* tl = ic_vbox.get_toplevel(); + Gtk::Window* win; + if ((win = dynamic_cast(tl)) != 0) { + /* ::get_default_widget() is not wrapped in gtkmm */ + Gtk::Widget* def = wrap (gtk_window_get_default_widget (win->gobj())); + Gtk::Button* button; + if ((button = dynamic_cast(def)) != 0) { + button->set_label (_("Open")); + } + } +} + +void +SessionDialog::new_session_button_clicked () +{ + _existing_session_chooser_used = false; + recent_session_display.get_selection()->unselect_all (); + + get_vbox()->remove (ic_vbox); + get_vbox()->pack_start (session_new_vbox, true, true); + back_button->set_sensitive (true); + new_name_entry.grab_focus (); +} + +bool +SessionDialog::back_button_pressed (GdkEventButton*) +{ + get_vbox()->remove (session_new_vbox); + back_button->set_sensitive (false); + get_vbox()->pack_start (ic_vbox); + + return true; +} + +void +SessionDialog::populate_session_templates () +{ + vector templates; + + find_session_templates (templates); + + template_model->clear (); + + for (vector::iterator x = templates.begin(); x != templates.end(); ++x) { + TreeModel::Row row; + + row = *(template_model->append ()); + + row[session_template_columns.name] = (*x).name; + row[session_template_columns.path] = (*x).path; + } + + if (!templates.empty()) { + /* select first row */ + template_chooser.set_active (0); + } +} + +void +SessionDialog::setup_new_session_page () +{ + session_new_vbox.set_border_width (12); + session_new_vbox.set_spacing (18); + + VBox *vbox1 = manage (new VBox); + HBox* hbox1 = manage (new HBox); + Label* label1 = manage (new Label); + + vbox1->set_spacing (6); + + hbox1->set_spacing (6); + hbox1->pack_start (*label1, false, false); + hbox1->pack_start (new_name_entry, true, true); + + label1->set_text (_("Session name:")); + + if (!ARDOUR_COMMAND_LINE::session_name.empty()) { + new_name_entry.set_text (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name)); + /* name provided - they can move right along */ + open_button->set_sensitive (true); + } + + new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &SessionDialog::new_name_changed)); + new_name_entry.signal_activate().connect (sigc::mem_fun (*this, &SessionDialog::new_name_activated)); + + vbox1->pack_start (*hbox1, true, true); + + /* --- */ + + HBox* hbox2 = manage (new HBox); + Label* label2 = manage (new Label); + + hbox2->set_spacing (6); + hbox2->pack_start (*label2, false, false); + hbox2->pack_start (new_folder_chooser, true, true); + + label2->set_text (_("Create session folder in:")); + + if (!ARDOUR_COMMAND_LINE::session_name.empty()) { + new_folder_chooser.set_current_folder (poor_mans_glob (Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name))); + } else if (ARDOUR_UI::instance()->session_loaded) { + // point the new session file chooser at the parent directory of the current session + string session_parent_dir = Glib::path_get_dirname(ARDOUR_UI::instance()->the_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); + new_folder_chooser.set_current_folder (session_parent_dir); + string default_session_folder = poor_mans_glob (Config->get_default_session_parent_dir()); + + try { + /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */ + new_folder_chooser.add_shortcut_folder (default_session_folder); + } + catch (Glib::Error & e) { + std::cerr << "new_folder_chooser.add_shortcut_folder (" << default_session_folder << ") threw Glib::Error " << e.what() << std::endl; + } + } else { + new_folder_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); + } + new_folder_chooser.show (); + new_folder_chooser.set_title (_("Select folder for session")); + +#ifdef __APPLE__ + new_folder_chooser.add_shortcut_folder ("/Volumes"); +#endif + + vbox1->pack_start (*hbox2, false, false); + + session_new_vbox.pack_start (*vbox1, false, false); + + /* --- */ + + VBox *vbox2 = manage (new VBox); + HBox* hbox3 = manage (new HBox); + template_model = ListStore::create (session_template_columns); + + vbox2->set_spacing (6); + + VBox *vbox3 = manage (new VBox); + + vbox3->set_spacing (6); + + /* we may want to hide this and show it at various + times depending on the existence of templates. + */ + template_chooser.set_no_show_all (true); + use_template_button.set_no_show_all (true); + + HBox* hbox4a = manage (new HBox); + use_template_button.set_label (_("Use this template")); + + TreeModel::Row row = *template_model->prepend (); + row[session_template_columns.name] = (_("no template")); + row[session_template_columns.path] = string(); + + hbox4a->set_spacing (6); + hbox4a->pack_start (use_template_button, false, false); + hbox4a->pack_start (template_chooser, true, true); + + template_chooser.set_model (template_model); + + Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText); + text_renderer->property_editable() = false; + + template_chooser.pack_start (*text_renderer); + template_chooser.add_attribute (text_renderer->property_text(), session_template_columns.name); + template_chooser.set_active (0); + + vbox3->pack_start (*hbox4a, false, false); + + /* --- */ + + HBox* hbox5 = manage (new HBox); + + hbox5->set_spacing (6); + hbox5->pack_start (more_new_session_options_button, false, false); + + setup_more_options_box (); + more_new_session_options_button.add (more_options_vbox); + + vbox3->pack_start (*hbox5, false, false); + hbox3->pack_start (*vbox3, true, true, 8); + vbox2->pack_start (*hbox3, false, false); + + /* --- */ + + session_new_vbox.pack_start (*vbox2, false, false); + session_new_vbox.show_all (); +} + +void +SessionDialog::new_name_changed () +{ + if (!new_name_entry.get_text().empty()) { + session_selected (); + open_button->set_sensitive (true); + } else { + open_button->set_sensitive (false); + } +} + +void +SessionDialog::new_name_activated () +{ + response (RESPONSE_ACCEPT); +} + +int +SessionDialog::redisplay_recent_sessions () +{ + std::vector session_directories; + RecentSessionsSorter cmp; + + recent_session_display.set_model (Glib::RefPtr(0)); + recent_session_model->clear (); + + ARDOUR::RecentSessions rs; + ARDOUR::read_recent_sessions (rs); + + if (rs.empty()) { + recent_session_display.set_model (recent_session_model); + return 0; + } + // + // sort them alphabetically + sort (rs.begin(), rs.end(), cmp); + + for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) { + session_directories.push_back ((*i).second); + } + + int session_snapshot_count = 0; + + for (vector::const_iterator i = session_directories.begin(); i != session_directories.end(); ++i) + { + std::vector state_file_paths; + + // now get available states for this session + + get_state_files_in_directory (*i, state_file_paths); + + vector* states; + vector item; + string fullpath = *i; + + /* 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 */ + continue; + } + + /* now get available states for this session */ + + if ((states = Session::possible_states (fullpath)) == 0) { + /* no state file? */ + continue; + } + + std::vector 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; + row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); + + ++session_snapshot_count; + + if (state_file_names.size() > 1) { + + // add the children + + for (std::vector::iterator i2 = state_file_names.begin(); + i2 != state_file_names.end(); ++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; + child_row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); + ++session_snapshot_count; + } + } + } + + recent_session_display.set_tooltip_column(1); // recent_session_columns.tip + recent_session_display.set_model (recent_session_model); + return session_snapshot_count; + // return rs.size(); +} + +void +SessionDialog::recent_session_row_selected () +{ + if (recent_session_display.get_selection()->count_selected_rows() > 0) { + open_button->set_sensitive (true); + session_selected (); + } else { + open_button->set_sensitive (false); + } +} + +void +SessionDialog::setup_more_options_box () +{ + more_options_vbox.set_border_width (24); + + _output_limit_count.set_adjustment (_output_limit_count_adj); + _input_limit_count.set_adjustment (_input_limit_count_adj); + _master_bus_channel_count.set_adjustment (_master_bus_channel_count_adj); + + chan_count_label_1.set_text (_("channels")); + chan_count_label_3.set_text (_("channels")); + chan_count_label_4.set_text (_("channels")); + + chan_count_label_1.set_alignment(0,0.5); + chan_count_label_1.set_padding(0,0); + chan_count_label_1.set_line_wrap(false); + + chan_count_label_3.set_alignment(0,0.5); + chan_count_label_3.set_padding(0,0); + chan_count_label_3.set_line_wrap(false); + + chan_count_label_4.set_alignment(0,0.5); + chan_count_label_4.set_padding(0,0); + chan_count_label_4.set_line_wrap(false); + + bus_label.set_markup (_("Busses")); + input_label.set_markup (_("Inputs")); + output_label.set_markup (_("Outputs")); + + _master_bus_channel_count.set_flags(Gtk::CAN_FOCUS); + _master_bus_channel_count.set_update_policy(Gtk::UPDATE_ALWAYS); + _master_bus_channel_count.set_numeric(true); + _master_bus_channel_count.set_digits(0); + _master_bus_channel_count.set_wrap(false); + + _create_master_bus.set_label (_("Create master bus")); + _create_master_bus.set_flags(Gtk::CAN_FOCUS); + _create_master_bus.set_relief(Gtk::RELIEF_NORMAL); + _create_master_bus.set_mode(true); + _create_master_bus.set_active(true); + _create_master_bus.set_border_width(0); + + advanced_table.set_row_spacings(0); + advanced_table.set_col_spacings(0); + + _connect_inputs.set_label (_("Automatically connect to physical inputs")); + _connect_inputs.set_flags(Gtk::CAN_FOCUS); + _connect_inputs.set_relief(Gtk::RELIEF_NORMAL); + _connect_inputs.set_mode(true); + _connect_inputs.set_active(Config->get_input_auto_connect() != ManualConnect); + _connect_inputs.set_border_width(0); + + _limit_input_ports.set_label (_("Use only")); + _limit_input_ports.set_flags(Gtk::CAN_FOCUS); + _limit_input_ports.set_relief(Gtk::RELIEF_NORMAL); + _limit_input_ports.set_mode(true); + _limit_input_ports.set_sensitive(true); + _limit_input_ports.set_border_width(0); + + _input_limit_count.set_flags(Gtk::CAN_FOCUS); + _input_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS); + _input_limit_count.set_numeric(true); + _input_limit_count.set_digits(0); + _input_limit_count.set_wrap(false); + _input_limit_count.set_sensitive(false); + + bus_hbox.pack_start (bus_table, Gtk::PACK_SHRINK, 18); + + bus_label.set_alignment(0, 0.5); + bus_label.set_padding(0,0); + bus_label.set_line_wrap(false); + bus_label.set_selectable(false); + bus_label.set_use_markup(true); + bus_frame.set_shadow_type(Gtk::SHADOW_NONE); + bus_frame.set_label_align(0,0.5); + bus_frame.add(bus_hbox); + bus_frame.set_label_widget(bus_label); + + bus_table.set_row_spacings (0); + bus_table.set_col_spacings (0); + bus_table.attach (_create_master_bus, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0); + bus_table.attach (_master_bus_channel_count, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0); + bus_table.attach (chan_count_label_1, 2, 3, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 0); + + input_port_limit_hbox.pack_start(_limit_input_ports, Gtk::PACK_SHRINK, 6); + input_port_limit_hbox.pack_start(_input_limit_count, Gtk::PACK_SHRINK, 0); + input_port_limit_hbox.pack_start(chan_count_label_3, Gtk::PACK_SHRINK, 6); + input_port_vbox.pack_start(_connect_inputs, Gtk::PACK_SHRINK, 0); + input_port_vbox.pack_start(input_port_limit_hbox, Gtk::PACK_EXPAND_PADDING, 0); + input_table.set_row_spacings(0); + input_table.set_col_spacings(0); + input_table.attach(input_port_vbox, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 6); + + input_hbox.pack_start (input_table, Gtk::PACK_SHRINK, 18); + + input_label.set_alignment(0, 0.5); + input_label.set_padding(0,0); + input_label.set_line_wrap(false); + input_label.set_selectable(false); + input_label.set_use_markup(true); + input_frame.set_shadow_type(Gtk::SHADOW_NONE); + input_frame.set_label_align(0,0.5); + input_frame.add(input_hbox); + input_frame.set_label_widget(input_label); + + _connect_outputs.set_label (_("Automatically connect outputs")); + _connect_outputs.set_flags(Gtk::CAN_FOCUS); + _connect_outputs.set_relief(Gtk::RELIEF_NORMAL); + _connect_outputs.set_mode(true); + _connect_outputs.set_active(Config->get_output_auto_connect() != ManualConnect); + _connect_outputs.set_border_width(0); + _limit_output_ports.set_label (_("Use only")); + _limit_output_ports.set_flags(Gtk::CAN_FOCUS); + _limit_output_ports.set_relief(Gtk::RELIEF_NORMAL); + _limit_output_ports.set_mode(true); + _limit_output_ports.set_sensitive(true); + _limit_output_ports.set_border_width(0); + _output_limit_count.set_flags(Gtk::CAN_FOCUS); + _output_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS); + _output_limit_count.set_numeric(false); + _output_limit_count.set_digits(0); + _output_limit_count.set_wrap(false); + _output_limit_count.set_sensitive(false); + output_port_limit_hbox.pack_start(_limit_output_ports, Gtk::PACK_SHRINK, 6); + output_port_limit_hbox.pack_start(_output_limit_count, Gtk::PACK_SHRINK, 0); + output_port_limit_hbox.pack_start(chan_count_label_4, Gtk::PACK_SHRINK, 6); + + _connect_outputs_to_master.set_label (_("... to master bus")); + _connect_outputs_to_master.set_flags(Gtk::CAN_FOCUS); + _connect_outputs_to_master.set_relief(Gtk::RELIEF_NORMAL); + _connect_outputs_to_master.set_mode(true); + _connect_outputs_to_master.set_active(Config->get_output_auto_connect() == AutoConnectMaster); + _connect_outputs_to_master.set_border_width(0); + + _connect_outputs_to_master.set_group (connect_outputs_group); + _connect_outputs_to_physical.set_group (connect_outputs_group); + + _connect_outputs_to_physical.set_label (_("... to physical outputs")); + _connect_outputs_to_physical.set_flags(Gtk::CAN_FOCUS); + _connect_outputs_to_physical.set_relief(Gtk::RELIEF_NORMAL); + _connect_outputs_to_physical.set_mode(true); + _connect_outputs_to_physical.set_active(Config->get_output_auto_connect() == AutoConnectPhysical); + _connect_outputs_to_physical.set_border_width(0); + + output_conn_vbox.pack_start(_connect_outputs, Gtk::PACK_SHRINK, 0); + output_conn_vbox.pack_start(_connect_outputs_to_master, Gtk::PACK_SHRINK, 0); + output_conn_vbox.pack_start(_connect_outputs_to_physical, Gtk::PACK_SHRINK, 0); + output_vbox.set_border_width(6); + + output_port_vbox.pack_start(output_port_limit_hbox, Gtk::PACK_SHRINK, 0); + + output_vbox.pack_start(output_conn_vbox); + output_vbox.pack_start(output_port_vbox); + + output_label.set_alignment(0, 0.5); + output_label.set_padding(0,0); + output_label.set_line_wrap(false); + output_label.set_selectable(false); + output_label.set_use_markup(true); + output_frame.set_shadow_type(Gtk::SHADOW_NONE); + output_frame.set_label_align(0,0.5); + + output_hbox.pack_start (output_vbox, Gtk::PACK_SHRINK, 18); + + output_frame.add(output_hbox); + output_frame.set_label_widget(output_label); + + more_options_vbox.pack_start(advanced_table, Gtk::PACK_SHRINK, 0); + more_options_vbox.pack_start(bus_frame, Gtk::PACK_SHRINK, 6); + more_options_vbox.pack_start(input_frame, Gtk::PACK_SHRINK, 6); + more_options_vbox.pack_start(output_frame, Gtk::PACK_SHRINK, 0); + + /* signals */ + + _connect_inputs.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::connect_inputs_clicked)); + _connect_outputs.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::connect_outputs_clicked)); + _limit_input_ports.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::limit_inputs_clicked)); + _limit_output_ports.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::limit_outputs_clicked)); + _create_master_bus.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::master_bus_button_clicked)); + + /* note that more_options_vbox is "visible" by default even + * though it may not be displayed to the user, this is so the dialog + * doesn't resize. + */ + more_options_vbox.show_all (); +} + +bool +SessionDialog::create_master_bus() const +{ + return _create_master_bus.get_active(); +} + +int +SessionDialog::master_channel_count() const +{ + return _master_bus_channel_count.get_value_as_int(); +} + +bool +SessionDialog::connect_inputs() const +{ + return _connect_inputs.get_active(); +} + +bool +SessionDialog::limit_inputs_used_for_connection() const +{ + return _limit_input_ports.get_active(); +} + +int +SessionDialog::input_limit_count() const +{ + return _input_limit_count.get_value_as_int(); +} + +bool +SessionDialog::connect_outputs() const +{ + return _connect_outputs.get_active(); +} + +bool +SessionDialog::limit_outputs_used_for_connection() const +{ + return _limit_output_ports.get_active(); +} + +int +SessionDialog::output_limit_count() const +{ + return _output_limit_count.get_value_as_int(); +} + +bool +SessionDialog::connect_outs_to_master() const +{ + return _connect_outputs_to_master.get_active(); +} + +bool +SessionDialog::connect_outs_to_physical() const +{ + return _connect_outputs_to_physical.get_active(); +} + +void +SessionDialog::connect_inputs_clicked () +{ + _limit_input_ports.set_sensitive(_connect_inputs.get_active()); + + if (_connect_inputs.get_active() && _limit_input_ports.get_active()) { + _input_limit_count.set_sensitive(true); + } else { + _input_limit_count.set_sensitive(false); + } +} + +void +SessionDialog::connect_outputs_clicked () +{ + bool const co = _connect_outputs.get_active (); + _limit_output_ports.set_sensitive(co); + _connect_outputs_to_master.set_sensitive(co); + _connect_outputs_to_physical.set_sensitive(co); + + if (co && _limit_output_ports.get_active()) { + _output_limit_count.set_sensitive(true); + } else { + _output_limit_count.set_sensitive(false); + } +} + +void +SessionDialog::limit_inputs_clicked () +{ + _input_limit_count.set_sensitive(_limit_input_ports.get_active()); +} + +void +SessionDialog::limit_outputs_clicked () +{ + _output_limit_count.set_sensitive(_limit_output_ports.get_active()); +} + +void +SessionDialog::master_bus_button_clicked () +{ + bool const yn = _create_master_bus.get_active(); + + _master_bus_channel_count.set_sensitive(yn); + _connect_outputs_to_master.set_sensitive(yn); +} + +void +SessionDialog::recent_row_activated (const Gtk::TreePath&, Gtk::TreeViewColumn*) +{ + response (RESPONSE_ACCEPT); +} + +void +SessionDialog::existing_session_selected () +{ + _existing_session_chooser_used = true; + /* mark this sensitive in case we come back here after a failed open + * attempt and the user has hacked up the fix. sigh. + */ + open_button->set_sensitive (true); + response (RESPONSE_ACCEPT); +} + +void +SessionDialog::updates_button_clicked () +{ + //now open a browser window so user can see more + PBD::open_uri (Config->get_updates_url()); +} + +bool +SessionDialog::info_scroller_update() +{ + info_scroller_count++; + + char buf[512]; + snprintf (buf, std::min(info_scroller_count,sizeof(buf)-1), "%s", ARDOUR_UI::instance()->announce_string().c_str() ); + buf[info_scroller_count] = 0; + info_scroller_label.set_text (buf); + info_scroller_label.show(); + + if (info_scroller_count > ARDOUR_UI::instance()->announce_string().length()) { + info_scroller_connection.disconnect(); + } + + return true; +} + +bool +SessionDialog::on_delete_event (GdkEventAny* ev) +{ + response (RESPONSE_CANCEL); + return ArdourDialog::on_delete_event (ev); +} + diff --git a/gtk2_ardour/session_dialog.h b/gtk2_ardour/session_dialog.h new file mode 100644 index 0000000000..ac4c1a7925 --- /dev/null +++ b/gtk2_ardour/session_dialog.h @@ -0,0 +1,231 @@ +/* + Copyright (C) 2010 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtk2_ardour_session_dialog_h__ +#define __gtk2_ardour_session_dialog_h__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ardour/utils.h" + +#include "ardour_dialog.h" + +class EngineControl; + +class SessionDialog : public ArdourDialog { + public: + SessionDialog (bool require_new, const std::string& session_name, const std::string& session_path, const std::string& template_name); + ~SessionDialog (); + + std::string session_name (bool& should_be_new); + std::string session_folder (); + + bool use_session_template(); + std::string session_template_name(); + + // advanced session options + + bool create_master_bus() const; + int master_channel_count() const; + + bool connect_inputs() const; + bool limit_inputs_used_for_connection() const; + int input_limit_count() const; + + bool connect_outputs() const; + bool limit_outputs_used_for_connection() const; + int output_limit_count() const; + + bool connect_outs_to_master() const; + bool connect_outs_to_physical() const; + + private: + bool new_only; + std::string _provided_session_name; + std::string _provided_session_path; + + bool on_delete_event (GdkEventAny*); + + Gtk::Button* cancel_button; + Gtk::Button* open_button; + Gtk::Button* back_button; + Gtk::Button* quit_button; + + bool back_button_pressed (GdkEventButton*); + + /* initial choice page */ + + void setup_initial_choice_box (); + Gtk::VBox ic_vbox; + Gtk::Button ic_new_session_button; + void new_session_button_clicked (); + + /* recent sessions */ + + void setup_existing_session_page (); + + struct RecentSessionsSorter { + bool operator() (std::pair a, std::pair b) const { + return cmp_nocase(a.first, b.first) == -1; + } + }; + + struct RecentSessionModelColumns : public Gtk::TreeModel::ColumnRecord { + RecentSessionModelColumns() { + add (visible_name); + add (tip); + add (fullpath); + } + Gtk::TreeModelColumn visible_name; + Gtk::TreeModelColumn tip; + Gtk::TreeModelColumn fullpath; + }; + + RecentSessionModelColumns recent_session_columns; + Gtk::TreeView recent_session_display; + Glib::RefPtr recent_session_model; + Gtk::ScrolledWindow recent_scroller; + Gtk::Label recent_label; + Gtk::FileChooserButton existing_session_chooser; + int redisplay_recent_sessions (); + void recent_session_row_selected (); + void recent_row_activated (const Gtk::TreePath& path, Gtk::TreeViewColumn* col); + + void existing_session_selected (); + void session_selected (); + + /* new sessions */ + + void setup_new_session_page (); + Gtk::Entry new_name_entry; + Gtk::FileChooserButton new_folder_chooser; + + struct SessionTemplateColumns : public Gtk::TreeModel::ColumnRecord { + SessionTemplateColumns () { + add (name); + add (path); + } + + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn path; + }; + + SessionTemplateColumns session_template_columns; + Glib::RefPtr template_model; + Gtk::ComboBox template_chooser; + + Gtk::VBox session_new_vbox; + Gtk::VBox session_existing_vbox; + Gtk::Expander more_new_session_options_button; + Gtk::CheckButton use_template_button; + std::string load_template_override; + + void more_new_session_options_button_clicked(); + void new_name_changed (); + void new_name_activated (); + void populate_session_templates (); + + /* more options for new sessions */ + + Gtk::VBox more_options_vbox; + + Gtk::Label chan_count_label_1; + Gtk::Label chan_count_label_3; + Gtk::Label chan_count_label_4; + Gtk::Table advanced_table; + Gtk::HBox input_port_limit_hbox; + Gtk::VBox input_port_vbox; + Gtk::Table input_table; + Gtk::HBox input_hbox; + + Gtk::Label bus_label; + Gtk::Frame bus_frame; + Gtk::Table bus_table; + Gtk::HBox bus_hbox; + + Gtk::Label input_label; + Gtk::Frame input_frame; + Gtk::HBox output_port_limit_hbox; + Gtk::VBox output_port_vbox; + Gtk::VBox output_conn_vbox; + Gtk::VBox output_vbox; + Gtk::HBox output_hbox; + + Gtk::Label output_label; + Gtk::Frame output_frame; + Gtk::VBox advanced_vbox; + Gtk::Label advanced_label; + + Gtk::CheckButton _create_master_bus; + Gtk::SpinButton _master_bus_channel_count; + + Gtk::CheckButton _connect_inputs; + Gtk::CheckButton _limit_input_ports; + Gtk::SpinButton _input_limit_count; + + Gtk::CheckButton _connect_outputs; + Gtk::CheckButton _limit_output_ports; + Gtk::SpinButton _output_limit_count; + + Gtk::RadioButtonGroup connect_outputs_group; + Gtk::RadioButton _connect_outputs_to_master; + Gtk::RadioButton _connect_outputs_to_physical; + + Gtk::Adjustment _output_limit_count_adj; + Gtk::Adjustment _input_limit_count_adj; + Gtk::Adjustment _master_bus_channel_count_adj; + + void connect_inputs_clicked (); + void connect_outputs_clicked (); + void limit_inputs_clicked (); + void limit_outputs_clicked (); + void master_bus_button_clicked (); + void setup_more_options_box (); + + /* always there */ + + Glib::RefPtr layout; + + bool _existing_session_chooser_used; ///< set to true when the existing session chooser has been used + + Gtk::Label info_scroller_label; + std::string::size_type info_scroller_count; + bool info_scroller_update(); + sigc::connection info_scroller_connection; + void updates_button_clicked (); +}; + +#endif /* __gtk2_ardour_session_dialog_h__ */ diff --git a/gtk2_ardour/small-splash.png b/gtk2_ardour/small-splash.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3c33ea77de9ad1bf58f8338eb1a158c0addae4 GIT binary patch literal 26238 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 tP~uO > window_icons; - Glib::RefPtr icon; - - if ((icon = ::get_icon ("ardour_icon_16px")) != 0) { - window_icons.push_back (icon); - } - if ((icon = ::get_icon ("ardour_icon_22px")) != 0) { - window_icons.push_back (icon); - } - if ((icon = ::get_icon ("ardour_icon_32px")) != 0) { - window_icons.push_back (icon); - } - if ((icon = ::get_icon ("ardour_icon_48px")) != 0) { - window_icons.push_back (icon); - } - if (!window_icons.empty ()) { - set_default_icon_list (window_icons); - } - -#ifdef __APPLE__ - setup_prerelease_page (); -#endif - if (new_user) { - - setup_new_user_page (); - setup_first_time_config_page (); - setup_monitoring_choice_page (); - setup_monitor_section_choice_page (); - setup_final_page (); - setup_new_session_page (); - - } else { - - if (!new_only) { - setup_initial_choice_page (); - } - setup_new_session_page (); - } - - if (!template_name.empty()) { - use_template_button.set_active (false); - load_template_override = template_name; - } + if ((icon_pixbuf = ::get_icon ("ardour_icon_48px")) == 0) { + throw failed_constructor(); } + + list > window_icons; + Glib::RefPtr icon; + + if ((icon = ::get_icon ("ardour_icon_16px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon ("ardour_icon_22px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon ("ardour_icon_32px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon ("ardour_icon_48px")) != 0) { + window_icons.push_back (icon); + } + if (!window_icons.empty ()) { + set_default_icon_list (window_icons); + } + +#ifdef __APPLE__ + setup_prerelease_page (); +#endif + + setup_new_user_page (); + setup_first_time_config_page (); + setup_monitoring_choice_page (); + setup_monitor_section_choice_page (); + setup_final_page (); the_startup = this; } @@ -157,9 +123,16 @@ ArdourStartup::~ArdourStartup () } bool -ArdourStartup::ready_without_display () const +ArdourStartup::required () { - return !new_user && !need_session_info; + return !Glib::file_test (been_here_before_path(), Glib::FILE_TEST_EXISTS); +} + +std::string +ArdourStartup::been_here_before_path () +{ + // XXXX use more specific version so we can catch upgrades + return Glib::build_filename (user_config_directory (), ".a3"); } void @@ -195,89 +168,6 @@ Full information on all the above can be found on the support page at\n\ set_page_complete (*vbox, true); } -bool -ArdourStartup::use_session_template () -{ - if (!load_template_override.empty()) { - return true; - } - - if (use_template_button.get_active()) { - return true; - } - return false; -} - -std::string -ArdourStartup::session_template_name () -{ - if (!load_template_override.empty()) { - string the_path (ARDOUR::user_template_directory()); - return Glib::build_filename (the_path, load_template_override + ARDOUR::template_suffix); - } - - if (use_template_button.get_active()) { - TreeModel::iterator iter = template_chooser.get_active (); - TreeModel::Row row = (*iter); - string s = row[session_template_columns.path]; - return s; - } - - return string(); -} - -std::string -ArdourStartup::session_name (bool& should_be_new) -{ - if (ready_without_display()) { - return _provided_session_name; - } - - /* Try recent session selection */ - - TreeIter iter = recent_session_display.get_selection()->get_selected(); - - if (iter) { - should_be_new = false; - return (*iter)[recent_session_columns.visible_name]; - } - - if (_existing_session_chooser_used) { - /* existing session chosen from file chooser */ - should_be_new = false; - return existing_session_chooser.get_filename (); - } else { - should_be_new = true; - string val = new_name_entry.get_text (); - strip_whitespace_edges (val); - return val; - } -} - -std::string -ArdourStartup::session_folder () -{ - if (ready_without_display()) { - return _provided_session_path; - } - - /* Try recent session selection */ - - TreeIter iter = recent_session_display.get_selection()->get_selected(); - - if (iter) { - return (*iter)[recent_session_columns.fullpath]; - } - - if (_existing_session_chooser_used) { - /* existing session chosen from file chooser */ - return existing_session_chooser.get_current_folder (); - } else { - std::string legal_session_folder_name = legalize_for_path (new_name_entry.get_text()); - return Glib::build_filename (new_folder_chooser.get_current_folder(), legal_session_folder_name); - } -} - void ArdourStartup::setup_new_user_page () { @@ -482,159 +372,12 @@ greater control in monitoring without affecting the mix.")); set_page_complete (mon_sec_vbox, true); } -void -ArdourStartup::setup_initial_choice_page () -{ - ic_vbox.set_spacing (6); - ic_vbox.set_border_width (24); - - /* append the page early because the recent session display will cause - calls to set_page_complete() on this page. - */ - - initial_choice_index = append_page (ic_vbox); - set_page_title (ic_vbox, string_compose("%1 %2", PROGRAM_NAME, VERSIONSTRING)); - set_page_header_image (ic_vbox, icon_pixbuf); - - - HBox* centering_hbox = manage (new HBox); - VBox* centering_vbox = manage (new VBox); - - centering_vbox->set_spacing (6); - - Label* new_label = manage (new Label); - new_label->set_markup (string_compose ("%1", _("Create a new session"))); - new_label->set_alignment (0, 0.5); - - ic_new_session_button.set_label (_("Configure the new session ...")); - ic_new_session_button.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::new_session_button_clicked)); - - centering_vbox->pack_start (*new_label, false, false, 12); - centering_vbox->pack_start (ic_new_session_button, false, true); - - /* Possible update message */ - - if (ARDOUR_UI::instance()->announce_string() != "" ) { - - Gtk::Frame *info_frame = manage(new Gtk::Frame); - info_frame->set_shadow_type(SHADOW_ETCHED_OUT); - centering_vbox->pack_start (*info_frame, false, false, 20); - - Box *info_box = manage (new VBox); - info_box->set_border_width (12); - info_box->set_spacing (6); - info_box->set_name("mixbus_info_box"); - - info_box->pack_start (info_scroller_label, false, false); - - info_frame->add (*info_box); - info_frame->show_all(); - - info_scroller_count = 0; - info_scroller_connection = Glib::signal_timeout().connect (mem_fun(*this, &ArdourStartup::info_scroller_update), 50); - - Gtk::Button *updates_button = manage (new Gtk::Button (_("Check the website for more..."))); - - updates_button->signal_clicked().connect (mem_fun(*this, &ArdourStartup::updates_button_clicked) ); - ARDOUR_UI::instance()->tooltips().set_tip (*updates_button, _("Click to open the program website in your web browser")); - - info_box->pack_start (*updates_button, false, false); - } - - /* recent session scroller */ - - recent_label.set_no_show_all (true); - recent_scroller.set_no_show_all (true); - - recent_label.set_markup (string_compose ("%1", _("Load a recent session"))); - recent_label.set_alignment (0, 0.5); - - recent_session_model = TreeStore::create (recent_session_columns); - - 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()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected)); - - recent_scroller.add (recent_session_display); - recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - recent_scroller.set_shadow_type (Gtk::SHADOW_IN); - - recent_session_display.show(); - recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated)); - - centering_vbox->pack_start (recent_label, false, false, 12); - centering_vbox->pack_start (recent_scroller, false, true); - - /* Browse button */ - - existing_session_chooser.set_title (_("Select session file")); - existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &ArdourStartup::existing_session_selected)); - existing_session_chooser.set_current_folder(poor_mans_glob (Config->get_default_session_parent_dir())); - - FileFilter session_filter; - session_filter.add_pattern ("*.ardour"); - session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME)); - existing_session_chooser.add_filter (session_filter); - existing_session_chooser.set_filter (session_filter); - -#ifdef GTKOSX - existing_session_chooser.add_shortcut_folder ("/Volumes"); -#endif - - Label* browse_label = manage (new Label); - browse_label->set_markup (string_compose ("%1", _("Browse for other sessions"))); - browse_label->set_alignment (0, 0.5); - - centering_vbox->pack_start (*browse_label, false, false, 12); - centering_vbox->pack_start (existing_session_chooser, false, false); - - /* pack it all up */ - - centering_hbox->pack_start (*centering_vbox, true, true); - ic_vbox.pack_start (*centering_hbox, true, true); - ic_vbox.show_all (); - - /* user could just click on "Forward" if default - * choice is correct. - */ - - set_page_complete (ic_vbox, true); -} - -void -ArdourStartup::session_selected () -{ - /* HACK HACK HACK ... change the "Apply" button label - to say "Open" - */ - - Gtk::Widget* tl = ic_vbox.get_toplevel(); - Gtk::Window* win; - if ((win = dynamic_cast(tl)) != 0) { - /* ::get_default_widget() is not wrapped in gtkmm */ - Gtk::Widget* def = wrap (gtk_window_get_default_widget (win->gobj())); - Gtk::Button* button; - if ((button = dynamic_cast(def)) != 0) { - button->set_label (_("Open")); - } - } -} - -void -ArdourStartup::new_session_button_clicked () -{ - _existing_session_chooser_used = false; - recent_session_display.get_selection()->unselect_all (); - set_current_page (new_session_page_index); -} - void ArdourStartup::setup_final_page () { - final_page.set_text (string_compose (_("%1 is ready for use"), PROGRAM_NAME)); + string msg = string_compose (_("%1 is ready for use"), PROGRAM_NAME); + + final_page.set_markup (string_compose ("%1", msg)); final_page.show (); final_page_index = append_page (final_page); set_page_complete (final_page, true); @@ -649,24 +392,6 @@ ArdourStartup::on_cancel () gtk_main_quit (); } -void -ArdourStartup::on_prepare (Gtk::Widget* page) -{ - if (page == &session_new_vbox) { - - /* if the user already defined a name by using the recent - * session list or browsing to an existing session - * then we are done. - */ - - bool expect_new_ignored; - - if (!session_name (expect_new_ignored).empty()) { - on_apply (); - } - } -} - bool ArdourStartup::on_delete_event (GdkEventAny*) { @@ -708,574 +433,6 @@ ArdourStartup::on_apply () gtk_main_quit (); } -void -ArdourStartup::populate_session_templates () -{ - vector templates; - - find_session_templates (templates); - - template_model->clear (); - - for (vector::iterator x = templates.begin(); x != templates.end(); ++x) { - TreeModel::Row row; - - row = *(template_model->append ()); - - row[session_template_columns.name] = (*x).name; - row[session_template_columns.path] = (*x).path; - } - - if (!templates.empty()) { - /* select first row */ - template_chooser.set_active (0); - } -} - -void -ArdourStartup::setup_new_session_page () -{ - session_new_vbox.set_border_width (12); - session_new_vbox.set_spacing (18); - - VBox *vbox1 = manage (new VBox); - HBox* hbox1 = manage (new HBox); - Label* label1 = manage (new Label); - - vbox1->set_spacing (6); - - hbox1->set_spacing (6); - hbox1->pack_start (*label1, false, false); - hbox1->pack_start (new_name_entry, true, true); - - label1->set_text (_("Session name:")); - - - if (!ARDOUR_COMMAND_LINE::session_name.empty()) { - new_name_entry.set_text (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name)); - /* name provided - they can move right along */ - set_page_complete (session_new_vbox, true); - } - - new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_changed)); - new_name_entry.signal_activate().connect (sigc::mem_fun (*this, &ArdourStartup::move_along_now)); - - vbox1->pack_start (*hbox1, true, true); - - /* --- */ - - HBox* hbox2 = manage (new HBox); - Label* label2 = manage (new Label); - - hbox2->set_spacing (6); - hbox2->pack_start (*label2, false, false); - hbox2->pack_start (new_folder_chooser, true, true); - - label2->set_text (_("Create session folder in:")); - - if (!ARDOUR_COMMAND_LINE::session_name.empty()) { - new_folder_chooser.set_current_folder (poor_mans_glob (Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name))); - } else if (ARDOUR_UI::instance()->session_loaded) { - // point the new session file chooser at the parent directory of the current session - string session_parent_dir = Glib::path_get_dirname(ARDOUR_UI::instance()->the_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); - new_folder_chooser.set_current_folder (session_parent_dir); - string default_session_folder = poor_mans_glob (Config->get_default_session_parent_dir()); - - try { - /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */ - new_folder_chooser.add_shortcut_folder (default_session_folder); - } - catch (Glib::Error & e) { - std::cerr << "new_folder_chooser.add_shortcut_folder (" << default_session_folder << ") threw Glib::Error " << e.what() << std::endl; - } - } else { - new_folder_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); - } - new_folder_chooser.show (); - new_folder_chooser.set_title (_("Select folder for session")); - -#ifdef __APPLE__ - new_folder_chooser.add_shortcut_folder ("/Volumes"); -#endif - - vbox1->pack_start (*hbox2, false, false); - - session_new_vbox.pack_start (*vbox1, false, false); - - /* --- */ - - VBox *vbox2 = manage (new VBox); - HBox* hbox3 = manage (new HBox); - template_model = ListStore::create (session_template_columns); - - vbox2->set_spacing (6); - - VBox *vbox3 = manage (new VBox); - - vbox3->set_spacing (6); - - /* we may want to hide this and show it at various - times depending on the existence of templates. - */ - template_chooser.set_no_show_all (true); - use_template_button.set_no_show_all (true); - - HBox* hbox4a = manage (new HBox); - use_template_button.set_label (_("Use this template")); - - TreeModel::Row row = *template_model->prepend (); - row[session_template_columns.name] = (_("no template")); - row[session_template_columns.path] = string(); - - hbox4a->set_spacing (6); - hbox4a->pack_start (use_template_button, false, false); - hbox4a->pack_start (template_chooser, true, true); - - template_chooser.set_model (template_model); - - Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText); - text_renderer->property_editable() = false; - - template_chooser.pack_start (*text_renderer); - template_chooser.add_attribute (text_renderer->property_text(), session_template_columns.name); - template_chooser.set_active (0); - - vbox3->pack_start (*hbox4a, false, false); - - /* --- */ - - HBox* hbox5 = manage (new HBox); - - hbox5->set_spacing (6); - hbox5->pack_start (more_new_session_options_button, false, false); - - setup_more_options_box (); - more_new_session_options_button.add (more_options_vbox); - - vbox3->pack_start (*hbox5, false, false); - hbox3->pack_start (*vbox3, true, true, 8); - vbox2->pack_start (*hbox3, false, false); - - /* --- */ - - session_new_vbox.pack_start (*vbox2, false, false); - session_new_vbox.show_all (); - - new_session_page_index = append_page (session_new_vbox); - set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); - set_page_title (session_new_vbox, _("New Session")); - - set_page_type (session_new_vbox, ASSISTANT_PAGE_CONFIRM); -} - -void -ArdourStartup::new_name_changed () -{ - if (!new_name_entry.get_text().empty()) { - session_selected (); - set_page_complete (session_new_vbox, true); - } else { - set_page_complete (session_new_vbox, false); - } -} - -int -ArdourStartup::redisplay_recent_sessions () -{ - std::vector session_directories; - RecentSessionsSorter cmp; - - recent_session_display.set_model (Glib::RefPtr(0)); - recent_session_model->clear (); - - ARDOUR::RecentSessions rs; - ARDOUR::read_recent_sessions (rs); - - if (rs.empty()) { - recent_session_display.set_model (recent_session_model); - return 0; - } - // - // sort them alphabetically - sort (rs.begin(), rs.end(), cmp); - - for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) { - session_directories.push_back ((*i).second); - } - - int session_snapshot_count = 0; - - for (vector::const_iterator i = session_directories.begin(); i != session_directories.end(); ++i) - { - std::vector state_file_paths; - - // now get available states for this session - - get_state_files_in_directory (*i, state_file_paths); - - vector* states; - vector item; - string fullpath = *i; - - /* 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 */ - continue; - } - - /* now get available states for this session */ - - if ((states = Session::possible_states (fullpath)) == 0) { - /* no state file? */ - continue; - } - - std::vector 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; - row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); - - ++session_snapshot_count; - - if (state_file_names.size() > 1) { - - // add the children - - for (std::vector::iterator i2 = state_file_names.begin(); - i2 != state_file_names.end(); ++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; - child_row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); - ++session_snapshot_count; - } - } - } - - recent_session_display.set_tooltip_column(1); // recent_session_columns.tip - recent_session_display.set_model (recent_session_model); - return session_snapshot_count; - // return rs.size(); -} - -void -ArdourStartup::recent_session_row_selected () -{ - if (recent_session_display.get_selection()->count_selected_rows() > 0) { - set_page_complete (ic_vbox, true); - session_selected (); - } else { - set_page_complete (ic_vbox, false); - } -} - -void -ArdourStartup::setup_more_options_box () -{ - more_options_vbox.set_border_width (24); - - _output_limit_count.set_adjustment (_output_limit_count_adj); - _input_limit_count.set_adjustment (_input_limit_count_adj); - _master_bus_channel_count.set_adjustment (_master_bus_channel_count_adj); - - chan_count_label_1.set_text (_("channels")); - chan_count_label_3.set_text (_("channels")); - chan_count_label_4.set_text (_("channels")); - - chan_count_label_1.set_alignment(0,0.5); - chan_count_label_1.set_padding(0,0); - chan_count_label_1.set_line_wrap(false); - - chan_count_label_3.set_alignment(0,0.5); - chan_count_label_3.set_padding(0,0); - chan_count_label_3.set_line_wrap(false); - - chan_count_label_4.set_alignment(0,0.5); - chan_count_label_4.set_padding(0,0); - chan_count_label_4.set_line_wrap(false); - - bus_label.set_markup (_("Busses")); - input_label.set_markup (_("Inputs")); - output_label.set_markup (_("Outputs")); - - _master_bus_channel_count.set_flags(Gtk::CAN_FOCUS); - _master_bus_channel_count.set_update_policy(Gtk::UPDATE_ALWAYS); - _master_bus_channel_count.set_numeric(true); - _master_bus_channel_count.set_digits(0); - _master_bus_channel_count.set_wrap(false); - - _create_master_bus.set_label (_("Create master bus")); - _create_master_bus.set_flags(Gtk::CAN_FOCUS); - _create_master_bus.set_relief(Gtk::RELIEF_NORMAL); - _create_master_bus.set_mode(true); - _create_master_bus.set_active(true); - _create_master_bus.set_border_width(0); - - advanced_table.set_row_spacings(0); - advanced_table.set_col_spacings(0); - - _connect_inputs.set_label (_("Automatically connect to physical inputs")); - _connect_inputs.set_flags(Gtk::CAN_FOCUS); - _connect_inputs.set_relief(Gtk::RELIEF_NORMAL); - _connect_inputs.set_mode(true); - _connect_inputs.set_active(Config->get_input_auto_connect() != ManualConnect); - _connect_inputs.set_border_width(0); - - _limit_input_ports.set_label (_("Use only")); - _limit_input_ports.set_flags(Gtk::CAN_FOCUS); - _limit_input_ports.set_relief(Gtk::RELIEF_NORMAL); - _limit_input_ports.set_mode(true); - _limit_input_ports.set_sensitive(true); - _limit_input_ports.set_border_width(0); - - _input_limit_count.set_flags(Gtk::CAN_FOCUS); - _input_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS); - _input_limit_count.set_numeric(true); - _input_limit_count.set_digits(0); - _input_limit_count.set_wrap(false); - _input_limit_count.set_sensitive(false); - - bus_hbox.pack_start (bus_table, Gtk::PACK_SHRINK, 18); - - bus_label.set_alignment(0, 0.5); - bus_label.set_padding(0,0); - bus_label.set_line_wrap(false); - bus_label.set_selectable(false); - bus_label.set_use_markup(true); - bus_frame.set_shadow_type(Gtk::SHADOW_NONE); - bus_frame.set_label_align(0,0.5); - bus_frame.add(bus_hbox); - bus_frame.set_label_widget(bus_label); - - bus_table.set_row_spacings (0); - bus_table.set_col_spacings (0); - bus_table.attach (_create_master_bus, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0); - bus_table.attach (_master_bus_channel_count, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0); - bus_table.attach (chan_count_label_1, 2, 3, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 0); - - input_port_limit_hbox.pack_start(_limit_input_ports, Gtk::PACK_SHRINK, 6); - input_port_limit_hbox.pack_start(_input_limit_count, Gtk::PACK_SHRINK, 0); - input_port_limit_hbox.pack_start(chan_count_label_3, Gtk::PACK_SHRINK, 6); - input_port_vbox.pack_start(_connect_inputs, Gtk::PACK_SHRINK, 0); - input_port_vbox.pack_start(input_port_limit_hbox, Gtk::PACK_EXPAND_PADDING, 0); - input_table.set_row_spacings(0); - input_table.set_col_spacings(0); - input_table.attach(input_port_vbox, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 6); - - input_hbox.pack_start (input_table, Gtk::PACK_SHRINK, 18); - - input_label.set_alignment(0, 0.5); - input_label.set_padding(0,0); - input_label.set_line_wrap(false); - input_label.set_selectable(false); - input_label.set_use_markup(true); - input_frame.set_shadow_type(Gtk::SHADOW_NONE); - input_frame.set_label_align(0,0.5); - input_frame.add(input_hbox); - input_frame.set_label_widget(input_label); - - _connect_outputs.set_label (_("Automatically connect outputs")); - _connect_outputs.set_flags(Gtk::CAN_FOCUS); - _connect_outputs.set_relief(Gtk::RELIEF_NORMAL); - _connect_outputs.set_mode(true); - _connect_outputs.set_active(Config->get_output_auto_connect() != ManualConnect); - _connect_outputs.set_border_width(0); - _limit_output_ports.set_label (_("Use only")); - _limit_output_ports.set_flags(Gtk::CAN_FOCUS); - _limit_output_ports.set_relief(Gtk::RELIEF_NORMAL); - _limit_output_ports.set_mode(true); - _limit_output_ports.set_sensitive(true); - _limit_output_ports.set_border_width(0); - _output_limit_count.set_flags(Gtk::CAN_FOCUS); - _output_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS); - _output_limit_count.set_numeric(false); - _output_limit_count.set_digits(0); - _output_limit_count.set_wrap(false); - _output_limit_count.set_sensitive(false); - output_port_limit_hbox.pack_start(_limit_output_ports, Gtk::PACK_SHRINK, 6); - output_port_limit_hbox.pack_start(_output_limit_count, Gtk::PACK_SHRINK, 0); - output_port_limit_hbox.pack_start(chan_count_label_4, Gtk::PACK_SHRINK, 6); - - _connect_outputs_to_master.set_label (_("... to master bus")); - _connect_outputs_to_master.set_flags(Gtk::CAN_FOCUS); - _connect_outputs_to_master.set_relief(Gtk::RELIEF_NORMAL); - _connect_outputs_to_master.set_mode(true); - _connect_outputs_to_master.set_active(Config->get_output_auto_connect() == AutoConnectMaster); - _connect_outputs_to_master.set_border_width(0); - - _connect_outputs_to_master.set_group (connect_outputs_group); - _connect_outputs_to_physical.set_group (connect_outputs_group); - - _connect_outputs_to_physical.set_label (_("... to physical outputs")); - _connect_outputs_to_physical.set_flags(Gtk::CAN_FOCUS); - _connect_outputs_to_physical.set_relief(Gtk::RELIEF_NORMAL); - _connect_outputs_to_physical.set_mode(true); - _connect_outputs_to_physical.set_active(Config->get_output_auto_connect() == AutoConnectPhysical); - _connect_outputs_to_physical.set_border_width(0); - - output_conn_vbox.pack_start(_connect_outputs, Gtk::PACK_SHRINK, 0); - output_conn_vbox.pack_start(_connect_outputs_to_master, Gtk::PACK_SHRINK, 0); - output_conn_vbox.pack_start(_connect_outputs_to_physical, Gtk::PACK_SHRINK, 0); - output_vbox.set_border_width(6); - - output_port_vbox.pack_start(output_port_limit_hbox, Gtk::PACK_SHRINK, 0); - - output_vbox.pack_start(output_conn_vbox); - output_vbox.pack_start(output_port_vbox); - - output_label.set_alignment(0, 0.5); - output_label.set_padding(0,0); - output_label.set_line_wrap(false); - output_label.set_selectable(false); - output_label.set_use_markup(true); - output_frame.set_shadow_type(Gtk::SHADOW_NONE); - output_frame.set_label_align(0,0.5); - - output_hbox.pack_start (output_vbox, Gtk::PACK_SHRINK, 18); - - output_frame.add(output_hbox); - output_frame.set_label_widget(output_label); - - more_options_vbox.pack_start(advanced_table, Gtk::PACK_SHRINK, 0); - more_options_vbox.pack_start(bus_frame, Gtk::PACK_SHRINK, 6); - more_options_vbox.pack_start(input_frame, Gtk::PACK_SHRINK, 6); - more_options_vbox.pack_start(output_frame, Gtk::PACK_SHRINK, 0); - - /* signals */ - - _connect_inputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_inputs_clicked)); - _connect_outputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_outputs_clicked)); - _limit_input_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_inputs_clicked)); - _limit_output_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_outputs_clicked)); - _create_master_bus.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::master_bus_button_clicked)); - - /* note that more_options_vbox is "visible" by default even - * though it may not be displayed to the user, this is so the dialog - * doesn't resize. - */ - more_options_vbox.show_all (); -} - -bool -ArdourStartup::create_master_bus() const -{ - return _create_master_bus.get_active(); -} - -int -ArdourStartup::master_channel_count() const -{ - return _master_bus_channel_count.get_value_as_int(); -} - -bool -ArdourStartup::connect_inputs() const -{ - return _connect_inputs.get_active(); -} - -bool -ArdourStartup::limit_inputs_used_for_connection() const -{ - return _limit_input_ports.get_active(); -} - -int -ArdourStartup::input_limit_count() const -{ - return _input_limit_count.get_value_as_int(); -} - -bool -ArdourStartup::connect_outputs() const -{ - return _connect_outputs.get_active(); -} - -bool -ArdourStartup::limit_outputs_used_for_connection() const -{ - return _limit_output_ports.get_active(); -} - -int -ArdourStartup::output_limit_count() const -{ - return _output_limit_count.get_value_as_int(); -} - -bool -ArdourStartup::connect_outs_to_master() const -{ - return _connect_outputs_to_master.get_active(); -} - -bool -ArdourStartup::connect_outs_to_physical() const -{ - return _connect_outputs_to_physical.get_active(); -} - -void -ArdourStartup::connect_inputs_clicked () -{ - _limit_input_ports.set_sensitive(_connect_inputs.get_active()); - - if (_connect_inputs.get_active() && _limit_input_ports.get_active()) { - _input_limit_count.set_sensitive(true); - } else { - _input_limit_count.set_sensitive(false); - } -} - -void -ArdourStartup::connect_outputs_clicked () -{ - bool const co = _connect_outputs.get_active (); - _limit_output_ports.set_sensitive(co); - _connect_outputs_to_master.set_sensitive(co); - _connect_outputs_to_physical.set_sensitive(co); - - if (co && _limit_output_ports.get_active()) { - _output_limit_count.set_sensitive(true); - } else { - _output_limit_count.set_sensitive(false); - } -} - -void -ArdourStartup::limit_inputs_clicked () -{ - _input_limit_count.set_sensitive(_limit_input_ports.get_active()); -} - -void -ArdourStartup::limit_outputs_clicked () -{ - _output_limit_count.set_sensitive(_limit_output_ports.get_active()); -} - -void -ArdourStartup::master_bus_button_clicked () -{ - bool const yn = _create_master_bus.get_active(); - - _master_bus_channel_count.set_sensitive(yn); - _connect_outputs_to_master.set_sensitive(yn); -} void ArdourStartup::move_along_now () @@ -1283,83 +440,5 @@ ArdourStartup::move_along_now () on_apply (); } -void -ArdourStartup::recent_row_activated (const Gtk::TreePath&, Gtk::TreeViewColumn*) -{ - set_page_complete (ic_vbox, true); - move_along_now (); -} -void -ArdourStartup::existing_session_selected () -{ - _existing_session_chooser_used = true; - - session_selected (); - set_page_complete (ic_vbox, true); - move_along_now (); -} - -std::string -ArdourStartup::been_here_before_path () const -{ - // XXXX use more specific version so we can catch upgrades - return Glib::build_filename (user_config_directory (), ".a3"); -} - -void -ArdourStartup::updates_button_clicked () -{ - //now open a browser window so user can see more - PBD::open_uri (Config->get_updates_url()); -} - -bool -ArdourStartup::info_scroller_update() -{ - info_scroller_count++; - - char buf[512]; - snprintf (buf, std::min(info_scroller_count,sizeof(buf)-1), "%s", ARDOUR_UI::instance()->announce_string().c_str() ); - buf[info_scroller_count] = 0; - info_scroller_label.set_text (buf); - info_scroller_label.show(); - - if (info_scroller_count > ARDOUR_UI::instance()->announce_string().length()) { - info_scroller_connection.disconnect(); - } - - return true; -} - -void -ArdourStartup::on_map () -{ - Gtk::Assistant::on_map (); - - populate_session_templates (); - - if (!template_model->children().empty()) { - use_template_button.show(); - template_chooser.show (); - } else { - use_template_button.hide(); - template_chooser.hide (); - } - - if (recent_session_model) { - int cnt = redisplay_recent_sessions (); - if (cnt > 0) { - recent_scroller.show(); - recent_label.show (); - - if (cnt > 4) { - recent_scroller.set_size_request (-1, 300); - } - } else { - recent_scroller.hide(); - recent_label.hide (); - } - } -} diff --git a/gtk2_ardour/startup.h b/gtk2_ardour/startup.h index 361d00e9e1..c5a9a30162 100644 --- a/gtk2_ardour/startup.h +++ b/gtk2_ardour/startup.h @@ -46,32 +46,10 @@ class EngineControl; class ArdourStartup : public Gtk::Assistant { public: - ArdourStartup (bool require_new, const std::string& session_name, const std::string& session_path, const std::string& template_name); + ArdourStartup (); ~ArdourStartup (); - bool ready_without_display () const; - - std::string session_name (bool& should_be_new); - std::string session_folder (); - - bool use_session_template(); - std::string session_template_name(); - - // advanced session options - - bool create_master_bus() const; - int master_channel_count() const; - - bool connect_inputs() const; - bool limit_inputs_used_for_connection() const; - int input_limit_count() const; - - bool connect_outputs() const; - bool limit_outputs_used_for_connection() const; - int output_limit_count() const; - - bool connect_outs_to_master() const; - bool connect_outs_to_physical() const; + static bool required (); gint response () const { return _response; @@ -81,18 +59,12 @@ class ArdourStartup : public Gtk::Assistant { gint _response; bool config_modified; bool new_user; - bool need_session_info; - bool new_only; - std::string _provided_session_name; - std::string _provided_session_path; - std::string been_here_before_path () const; + static std::string been_here_before_path (); void on_apply (); void on_cancel (); bool on_delete_event (GdkEventAny*); - void on_prepare (Gtk::Widget*); - void on_map (); static ArdourStartup *the_startup; @@ -110,13 +82,7 @@ class ArdourStartup : public Gtk::Assistant { Gtk::FileChooserButton* default_dir_chooser; void default_dir_changed(); void setup_first_page (); - - /* initial choice page */ - - void setup_initial_choice_page (); - Gtk::VBox ic_vbox; - Gtk::Button ic_new_session_button; - void new_session_button_clicked (); + Gtk::FileChooserButton new_folder_chooser; /* monitoring choices */ @@ -134,128 +100,6 @@ class ArdourStartup : public Gtk::Assistant { Gtk::RadioButton no_monitor_section_button; void setup_monitor_section_choice_page (); - - /* recent sessions */ - - void setup_existing_session_page (); - - struct RecentSessionsSorter { - bool operator() (std::pair a, std::pair b) const { - return cmp_nocase(a.first, b.first) == -1; - } - }; - - struct RecentSessionModelColumns : public Gtk::TreeModel::ColumnRecord { - RecentSessionModelColumns() { - add (visible_name); - add (tip); - add (fullpath); - } - Gtk::TreeModelColumn visible_name; - Gtk::TreeModelColumn tip; - Gtk::TreeModelColumn fullpath; - }; - - RecentSessionModelColumns recent_session_columns; - Gtk::TreeView recent_session_display; - Glib::RefPtr recent_session_model; - Gtk::ScrolledWindow recent_scroller; - Gtk::Label recent_label; - Gtk::FileChooserButton existing_session_chooser; - int redisplay_recent_sessions (); - void recent_session_row_selected (); - void recent_row_activated (const Gtk::TreePath& path, Gtk::TreeViewColumn* col); - - void existing_session_selected (); - void session_selected (); - - /* new sessions */ - - void setup_new_session_page (); - Gtk::Entry new_name_entry; - Gtk::FileChooserButton new_folder_chooser; - - struct SessionTemplateColumns : public Gtk::TreeModel::ColumnRecord { - SessionTemplateColumns () { - add (name); - add (path); - } - - Gtk::TreeModelColumn name; - Gtk::TreeModelColumn path; - }; - - SessionTemplateColumns session_template_columns; - Glib::RefPtr template_model; - Gtk::ComboBox template_chooser; - - Gtk::VBox session_new_vbox; - Gtk::VBox session_existing_vbox; - Gtk::Expander more_new_session_options_button; - Gtk::CheckButton use_template_button; - std::string load_template_override; - - void more_new_session_options_button_clicked(); - void new_name_changed (); - void populate_session_templates (); - - /* more options for new sessions */ - - Gtk::VBox more_options_vbox; - - Gtk::Label chan_count_label_1; - Gtk::Label chan_count_label_3; - Gtk::Label chan_count_label_4; - Gtk::Table advanced_table; - Gtk::HBox input_port_limit_hbox; - Gtk::VBox input_port_vbox; - Gtk::Table input_table; - Gtk::HBox input_hbox; - - Gtk::Label bus_label; - Gtk::Frame bus_frame; - Gtk::Table bus_table; - Gtk::HBox bus_hbox; - - Gtk::Label input_label; - Gtk::Frame input_frame; - Gtk::HBox output_port_limit_hbox; - Gtk::VBox output_port_vbox; - Gtk::VBox output_conn_vbox; - Gtk::VBox output_vbox; - Gtk::HBox output_hbox; - - Gtk::Label output_label; - Gtk::Frame output_frame; - Gtk::VBox advanced_vbox; - Gtk::Label advanced_label; - - Gtk::CheckButton _create_master_bus; - Gtk::SpinButton _master_bus_channel_count; - - Gtk::CheckButton _connect_inputs; - Gtk::CheckButton _limit_input_ports; - Gtk::SpinButton _input_limit_count; - - Gtk::CheckButton _connect_outputs; - Gtk::CheckButton _limit_output_ports; - Gtk::SpinButton _output_limit_count; - - Gtk::RadioButtonGroup connect_outputs_group; - Gtk::RadioButton _connect_outputs_to_master; - Gtk::RadioButton _connect_outputs_to_physical; - - Gtk::Adjustment _output_limit_count_adj; - Gtk::Adjustment _input_limit_count_adj; - Gtk::Adjustment _master_bus_channel_count_adj; - - void connect_inputs_clicked (); - void connect_outputs_clicked (); - void limit_inputs_clicked (); - void limit_outputs_clicked (); - void master_bus_button_clicked (); - void setup_more_options_box (); - /* final page */ void setup_final_page (); @@ -272,21 +116,12 @@ class ArdourStartup : public Gtk::Assistant { gint default_folder_page_index; gint monitoring_page_index; gint monitor_section_page_index; - gint new_session_page_index; - gint initial_choice_index; gint final_page_index; - gint session_options_page_index; void move_along_now (); - bool _existing_session_chooser_used; ///< set to true when the existing session chooser has been used void setup_prerelease_page (); - Gtk::Label info_scroller_label; - std::string::size_type info_scroller_count; - bool info_scroller_update(); - sigc::connection info_scroller_connection; - void updates_button_clicked (); }; #endif /* __gtk2_ardour_startup_h__ */ diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 304b8508c6..c81aff85ab 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -401,7 +401,7 @@ emulate_key_event (Gtk::Widget* w, unsigned int keyval) ev.state = 0; ev.keyval = keyval; ev.length = 0; - ev.string = (const gchar*) ""; + ev.string = const_cast (""); ev.hardware_keycode = keymapkey[0].keycode; ev.group = keymapkey[0].group; g_free(keymapkey); diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 1f4c7940f8..be7164cf05 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -203,6 +203,7 @@ gtk2_ardour_sources = [ 'search_path_option.cc', 'selection.cc', 'send_ui.cc', + 'session_dialog.cc', 'session_import_dialog.cc', 'session_metadata_dialog.cc', 'session_option_editor.cc', From 884789bfadddadcda49cef603a754f8e12e911a6 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2013 16:49:24 -0400 Subject: [PATCH 21/42] move announcements frame around in the session dialog and adjust spacing/borders --- gtk2_ardour/session_dialog.cc | 25 ++++++++++++++++--------- gtk2_ardour/session_dialog.h | 2 ++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/gtk2_ardour/session_dialog.cc b/gtk2_ardour/session_dialog.cc index 481b587b71..710833b873 100644 --- a/gtk2_ardour/session_dialog.cc +++ b/gtk2_ardour/session_dialog.cc @@ -81,6 +81,7 @@ SessionDialog::SessionDialog (bool require_new, const std::string& session_name, set_keep_above (true); set_position (WIN_POS_CENTER); + get_vbox()->set_spacing (6); string image_path; @@ -91,6 +92,15 @@ SessionDialog::SessionDialog (bool require_new, const std::string& session_name, } } + /* this is where announcements will be displayed, but it may be empty + * and invisible most of the time. + */ + + info_frame.set_shadow_type(SHADOW_ETCHED_OUT); + info_frame.set_no_show_all (true); + info_frame.set_border_width (12); + get_vbox()->pack_start (info_frame, false, false); + setup_new_session_page (); if (!new_only) { @@ -236,7 +246,6 @@ void SessionDialog::setup_initial_choice_box () { ic_vbox.set_spacing (6); - ic_vbox.set_border_width (24); HBox* centering_hbox = manage (new HBox); VBox* centering_vbox = manage (new VBox); @@ -249,25 +258,19 @@ SessionDialog::setup_initial_choice_box () ic_new_session_button.add (*new_label); ic_new_session_button.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::new_session_button_clicked)); - centering_vbox->pack_start (ic_new_session_button, false, true); + centering_vbox->pack_start (ic_new_session_button, false, false); /* Possible update message */ if (ARDOUR_UI::instance()->announce_string() != "" ) { - Gtk::Frame *info_frame = manage(new Gtk::Frame); - info_frame->set_shadow_type(SHADOW_ETCHED_OUT); - centering_vbox->pack_start (*info_frame, false, false, 20); - Box *info_box = manage (new VBox); info_box->set_border_width (12); info_box->set_spacing (6); - info_box->set_name("mixbus_info_box"); info_box->pack_start (info_scroller_label, false, false); - info_frame->add (*info_box); - info_frame->show_all(); + cerr << "Frame should be visible\n"; info_scroller_count = 0; info_scroller_connection = Glib::signal_timeout().connect (mem_fun(*this, &SessionDialog::info_scroller_update), 50); @@ -278,6 +281,10 @@ SessionDialog::setup_initial_choice_box () ARDOUR_UI::instance()->tooltips().set_tip (*updates_button, _("Click to open the program website in your web browser")); info_box->pack_start (*updates_button, false, false); + + info_frame.add (*info_box); + info_box->show_all (); + info_frame.show (); } /* recent session scroller */ diff --git a/gtk2_ardour/session_dialog.h b/gtk2_ardour/session_dialog.h index ac4c1a7925..bb43bc2931 100644 --- a/gtk2_ardour/session_dialog.h +++ b/gtk2_ardour/session_dialog.h @@ -86,6 +86,8 @@ class SessionDialog : public ArdourDialog { bool back_button_pressed (GdkEventButton*); + Gtk::Frame info_frame; + /* initial choice page */ void setup_initial_choice_box (); From cff174b5417d9b242673588792d390db9f61ca93 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2013 21:35:17 -0400 Subject: [PATCH 22/42] move rate_as_string() from EngineControl to utils.cc --- gtk2_ardour/engine_dialog.cc | 13 +------------ gtk2_ardour/engine_dialog.h | 1 - gtk2_ardour/utils.cc | 13 +++++++++++++ gtk2_ardour/utils.h | 2 ++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index 79bda1bcc5..a63e310b3f 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -48,6 +48,7 @@ #include "ardour_ui.h" #include "engine_dialog.h" #include "gui_thread.h" +#include "utils.h" #include "i18n.h" using namespace std; @@ -800,18 +801,6 @@ EngineControl::device_changed () push_state_to_backend (false); } -string -EngineControl::rate_as_string (float r) -{ - char buf[32]; - if (fmod (r, 1000.0f)) { - snprintf (buf, sizeof (buf), "%.1f kHz", r/1000.0); - } else { - snprintf (buf, sizeof (buf), "%.0f kHz", r/1000.0); - } - return buf; -} - string EngineControl::bufsize_as_string (uint32_t sz) { diff --git a/gtk2_ardour/engine_dialog.h b/gtk2_ardour/engine_dialog.h index 59924e0f0a..ac17814a5f 100644 --- a/gtk2_ardour/engine_dialog.h +++ b/gtk2_ardour/engine_dialog.h @@ -122,7 +122,6 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList { void setup_midi_tab_for_jack (); void refresh_midi_display (); - std::string rate_as_string (float); std::string bufsize_as_string (uint32_t); float get_rate() const; diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index c81aff85ab..a0fd7016b5 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -860,3 +861,15 @@ unique_random_color (list& used_colors) /* XXX need throttle here to make sure we don't spin for ever */ } } + +string +rate_as_string (float r) +{ + char buf[32]; + if (fmod (r, 1000.0f)) { + snprintf (buf, sizeof (buf), "%.1f kHz", r/1000.0); + } else { + snprintf (buf, sizeof (buf), "%.0f kHz", r/1000.0); + } + return buf; +} diff --git a/gtk2_ardour/utils.h b/gtk2_ardour/utils.h index 5d7bf000ea..a1a54898b5 100644 --- a/gtk2_ardour/utils.h +++ b/gtk2_ardour/utils.h @@ -86,4 +86,6 @@ std::string escape_angled_brackets (std::string const &); Gdk::Color unique_random_color (std::list &); +std::string rate_as_string (float r); + #endif /* __ardour_gtk_utils_h__ */ From 4209e8a8347940a5d17b129fa1f52d4f57efd02c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2013 21:35:51 -0400 Subject: [PATCH 23/42] add new static functions to get SR and disk sample format from session XML --- libs/ardour/ardour/session.h | 4 +++ libs/ardour/session_state.cc | 56 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index ae5339796c..2fcf6d476a 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -161,6 +161,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi virtual ~Session (); + static int get_info_from_path (const std::string& xmlpath, float& sample_rate, SampleFormat& data_format); + std::string path() const { return _path; } std::string name() const { return _name; } std::string snap_name() const { return _current_snapshot_name; } @@ -1618,6 +1620,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void setup_ltc (); void setup_click (); void setup_bundles (); + + static int get_session_info_from_path (XMLTree& state_tree, const std::string& xmlpath); }; } // namespace ARDOUR diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 049cb5b5ee..2b2afc0d3d 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -3743,3 +3743,59 @@ Session::rename (const std::string& new_name) #undef RENAME } + +int +Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath) +{ + if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) { + return -1; + } + + if (!tree.read (xmlpath)) { + return -1; + } + + return 0; +} + +int +Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format) +{ + XMLTree tree; + bool found_sr = false; + bool found_data_format = false; + + if (get_session_info_from_path (tree, xmlpath)) { + return -1; + } + + /* sample rate */ + + const XMLProperty* prop; + if ((prop = tree.root()->property (X_("sample-rate"))) != 0) { + sample_rate = atoi (prop->value()); + found_sr = true; + } + + const XMLNodeList& children (tree.root()->children()); + for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) { + const XMLNode* child = *c; + if (child->name() == "Config") { + const XMLNodeList& options (child->children()); + for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) { + const XMLNode* option = *oc; + if (option->property("name")->value() == "native-file-data-format") { + SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt); + data_format = fmt; + found_data_format = true; + break; + } + } + } + if (found_data_format) { + break; + } + } + + return !(found_sr && found_data_format); // zero if they are both found +} From 0f6ba422f673af136c592b5ea3d913cd86f57b19 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2013 21:36:13 -0400 Subject: [PATCH 24/42] use new Session API to show session SR and disk bit depth in recent sessions list --- gtk2_ardour/session_dialog.cc | 76 ++++++++++++++++++++++++++++------- gtk2_ardour/session_dialog.h | 4 ++ 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/gtk2_ardour/session_dialog.cc b/gtk2_ardour/session_dialog.cc index 710833b873..e70f8600e1 100644 --- a/gtk2_ardour/session_dialog.cc +++ b/gtk2_ardour/session_dialog.cc @@ -299,6 +299,8 @@ SessionDialog::setup_initial_choice_box () recent_session_display.set_model (recent_session_model); recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name); + recent_session_display.append_column (_("Sample Rate"), recent_session_columns.sample_rate); + recent_session_display.append_column (_("Disk Format"), recent_session_columns.disk_format); recent_session_display.set_headers_visible (false); recent_session_display.get_selection()->set_mode (SELECTION_SINGLE); @@ -593,49 +595,94 @@ SessionDialog::redisplay_recent_sessions () vector* states; vector item; - string fullpath = *i; + string dirname = *i; /* remove any trailing / */ - if (fullpath[fullpath.length()-1] == '/') { - fullpath = fullpath.substr (0, fullpath.length()-1); + if (dirname[dirname.length()-1] == '/') { + dirname = dirname.substr (0, dirname.length()-1); } /* check whether session still exists */ - if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) { + if (!Glib::file_test(dirname.c_str(), Glib::FILE_TEST_EXISTS)) { /* session doesn't exist */ continue; } /* now get available states for this session */ - if ((states = Session::possible_states (fullpath)) == 0) { + if ((states = Session::possible_states (dirname)) == 0) { /* no state file? */ continue; } std::vector state_file_names(get_file_names_no_extension (state_file_paths)); + if (state_file_names.empty()) { + continue; + } + 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; - row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); - + float sr; + SampleFormat sf; + std::string s = Glib::build_filename (dirname, state_file_names.front() + statefile_suffix); + + row[recent_session_columns.visible_name] = Glib::path_get_basename (dirname); + row[recent_session_columns.fullpath] = dirname; /* just the dir, but this works too */ + row[recent_session_columns.tip] = Glib::Markup::escape_text (dirname); + + if (Session::get_info_from_path (s, sr, sf) == 0) { + row[recent_session_columns.sample_rate] = rate_as_string (sr); + switch (sf) { + case FormatFloat: + row[recent_session_columns.disk_format] = _("32 bit float"); + break; + case FormatInt24: + row[recent_session_columns.disk_format] = _("24 bit"); + break; + case FormatInt16: + row[recent_session_columns.disk_format] = _("16 bit"); + break; + } + } else { + row[recent_session_columns.sample_rate] = "??"; + row[recent_session_columns.disk_format] = "--"; + } + ++session_snapshot_count; if (state_file_names.size() > 1) { // add the children - for (std::vector::iterator i2 = state_file_names.begin(); - i2 != state_file_names.end(); ++i2) { + for (std::vector::iterator i2 = state_file_names.begin(); i2 != state_file_names.end(); ++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; - child_row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); + child_row[recent_session_columns.fullpath] = Glib::build_filename (dirname, *i2 + statefile_suffix); + child_row[recent_session_columns.tip] = Glib::Markup::escape_text (dirname); + + if (Session::get_info_from_path (s, sr, sf) == 0) { + child_row[recent_session_columns.sample_rate] = rate_as_string (sr); + switch (sf) { + case FormatFloat: + child_row[recent_session_columns.disk_format] = _("32 bit float"); + break; + case FormatInt24: + child_row[recent_session_columns.disk_format] = _("24 bit"); + break; + case FormatInt16: + child_row[recent_session_columns.disk_format] = _("16 bit"); + break; + } + } else { + child_row[recent_session_columns.sample_rate] = "??"; + child_row[recent_session_columns.disk_format] = "--"; + } + + ++session_snapshot_count; } } @@ -644,7 +691,6 @@ SessionDialog::redisplay_recent_sessions () recent_session_display.set_tooltip_column(1); // recent_session_columns.tip recent_session_display.set_model (recent_session_model); return session_snapshot_count; - // return rs.size(); } void diff --git a/gtk2_ardour/session_dialog.h b/gtk2_ardour/session_dialog.h index bb43bc2931..21d2f5ea3f 100644 --- a/gtk2_ardour/session_dialog.h +++ b/gtk2_ardour/session_dialog.h @@ -110,10 +110,14 @@ class SessionDialog : public ArdourDialog { add (visible_name); add (tip); add (fullpath); + add (sample_rate); + add (disk_format); } Gtk::TreeModelColumn visible_name; Gtk::TreeModelColumn tip; Gtk::TreeModelColumn fullpath; + Gtk::TreeModelColumn sample_rate; + Gtk::TreeModelColumn disk_format; }; RecentSessionModelColumns recent_session_columns; From f7b6a27de6c63795be79991ffae993932a9fa0eb Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 23 Sep 2013 23:12:42 -0400 Subject: [PATCH 25/42] shrink small-splash.png image by 50% --- gtk2_ardour/small-splash.png | Bin 26238 -> 9671 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/gtk2_ardour/small-splash.png b/gtk2_ardour/small-splash.png index 0a3c33ea77de9ad1bf58f8338eb1a158c0addae4..045062036cdfae2cabfc0bc0304c75e84590ad78 100644 GIT binary patch literal 9671 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 tP~uO Date: Mon, 23 Sep 2013 23:13:07 -0400 Subject: [PATCH 26/42] tighten up layout of session dialog; make button say cancel or quit in difference scenarios --- gtk2_ardour/ardour_ui.cc | 8 ++++++- gtk2_ardour/session_dialog.cc | 40 +++++++++++++++++++---------------- gtk2_ardour/session_dialog.h | 3 ++- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 129b77f0a4..e98e3e00a0 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -2529,6 +2529,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri string template_name; int ret = -1; bool likely_new = false; + bool cancel_not_quit; /* deal with any existing DIRTY session now, rather than later. don't * treat a non-dirty session this way, so that it stays visible @@ -2539,6 +2540,11 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri ARDOUR_UI::instance()->video_timeline->sync_session_state(); } + /* if there is already a session, relabel the button + on the SessionDialog so that we don't Quit directly + */ + cancel_not_quit = (_session != 0); + if (_session && _session->dirty()) { if (unload_session (false)) { /* unload cancelled by user */ @@ -2552,7 +2558,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri template_name = load_template; } - SessionDialog session_dialog (should_be_new, session_name, session_path, load_template); + SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit); while (ret != 0) { diff --git a/gtk2_ardour/session_dialog.cc b/gtk2_ardour/session_dialog.cc index e70f8600e1..038ea11d76 100644 --- a/gtk2_ardour/session_dialog.cc +++ b/gtk2_ardour/session_dialog.cc @@ -62,8 +62,8 @@ static string poor_mans_glob (string path) return copy; } -SessionDialog::SessionDialog (bool require_new, const std::string& session_name, const std::string& session_path, const std::string& template_name) - : ArdourDialog (_("Session Setup")) +SessionDialog::SessionDialog (bool require_new, const std::string& session_name, const std::string& session_path, const std::string& template_name, bool cancel_not_quit) + : ArdourDialog (_("Session Setup"), true, true) , new_only (require_new) , _provided_session_name (session_name) , _provided_session_path (session_path) @@ -83,15 +83,6 @@ SessionDialog::SessionDialog (bool require_new, const std::string& session_name, set_position (WIN_POS_CENTER); get_vbox()->set_spacing (6); - string image_path; - - if (find_file_in_search_path (ardour_data_search_path(), "small-splash.png", image_path)) { - Gtk::Image* image; - if ((image = manage (new Gtk::Image (image_path))) != 0) { - get_vbox()->pack_start (*image, false, false); - } - } - /* this is where announcements will be displayed, but it may be empty * and invisible most of the time. */ @@ -117,7 +108,7 @@ SessionDialog::SessionDialog (bool require_new, const std::string& session_name, get_vbox()->show_all (); - cancel_button = add_button (Stock::QUIT, RESPONSE_CANCEL); + cancel_button = add_button ((cancel_not_quit ? Stock::CANCEL : Stock::QUIT), RESPONSE_CANCEL); back_button = add_button (Stock::GO_BACK, RESPONSE_NO); open_button = add_button (Stock::OPEN, RESPONSE_ACCEPT); @@ -253,12 +244,27 @@ SessionDialog::setup_initial_choice_box () centering_vbox->set_spacing (6); Label* new_label = manage (new Label); - new_label->set_markup (string_compose ("%1", _("Create a new session"))); + new_label->set_markup (string_compose ("%1", _("New Session"))); + new_label->set_justify (JUSTIFY_CENTER); ic_new_session_button.add (*new_label); ic_new_session_button.signal_clicked().connect (sigc::mem_fun (*this, &SessionDialog::new_session_button_clicked)); - centering_vbox->pack_start (ic_new_session_button, false, false); + Gtk::HBox* hbox = manage (new HBox); + hbox->set_spacing (12); + + string image_path; + + if (find_file_in_search_path (ardour_data_search_path(), "small-splash.png", image_path)) { + Gtk::Image* image; + if ((image = manage (new Gtk::Image (image_path))) != 0) { + hbox->pack_start (*image, false, false); + } + } + + hbox->pack_start (ic_new_session_button, true, true); + + centering_vbox->pack_start (*hbox, false, false); /* Possible update message */ @@ -292,8 +298,7 @@ SessionDialog::setup_initial_choice_box () recent_label.set_no_show_all (true); recent_scroller.set_no_show_all (true); - recent_label.set_markup (string_compose ("%1", _("... or load a recent session"))); - recent_label.set_alignment (0, 0.5); + recent_label.set_markup (string_compose ("%1", _("Recent Sessions"))); recent_session_model = TreeStore::create (recent_session_columns); @@ -333,8 +338,7 @@ SessionDialog::setup_initial_choice_box () #endif Label* browse_label = manage (new Label); - browse_label->set_markup (string_compose ("%1", _("... or browse for existing sessions"))); - browse_label->set_alignment (0, 0.5); + browse_label->set_markup (string_compose ("%1", _("Other Sessions"))); centering_vbox->pack_start (*browse_label, false, false, 12); centering_vbox->pack_start (existing_session_chooser, false, false); diff --git a/gtk2_ardour/session_dialog.h b/gtk2_ardour/session_dialog.h index 21d2f5ea3f..782466a834 100644 --- a/gtk2_ardour/session_dialog.h +++ b/gtk2_ardour/session_dialog.h @@ -47,7 +47,8 @@ class EngineControl; class SessionDialog : public ArdourDialog { public: - SessionDialog (bool require_new, const std::string& session_name, const std::string& session_path, const std::string& template_name); + SessionDialog (bool require_new, const std::string& session_name, const std::string& session_path, + const std::string& template_name, bool cancel_not_quit); ~SessionDialog (); std::string session_name (bool& should_be_new); From d0b67dce80412883da01d4fcd8c5ed283cb85436 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 24 Sep 2013 22:22:16 -0400 Subject: [PATCH 27/42] fix crash when cmdline provides session name --- gtk2_ardour/session_dialog.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gtk2_ardour/session_dialog.cc b/gtk2_ardour/session_dialog.cc index 038ea11d76..51c7e24f80 100644 --- a/gtk2_ardour/session_dialog.cc +++ b/gtk2_ardour/session_dialog.cc @@ -83,6 +83,15 @@ SessionDialog::SessionDialog (bool require_new, const std::string& session_name, set_position (WIN_POS_CENTER); get_vbox()->set_spacing (6); + cancel_button = add_button ((cancel_not_quit ? Stock::CANCEL : Stock::QUIT), RESPONSE_CANCEL); + back_button = add_button (Stock::GO_BACK, RESPONSE_NO); + open_button = add_button (Stock::OPEN, RESPONSE_ACCEPT); + + back_button->signal_button_press_event().connect (sigc::mem_fun (*this, &SessionDialog::back_button_pressed), false); + + open_button->set_sensitive (false); + back_button->set_sensitive (false); + /* this is where announcements will be displayed, but it may be empty * and invisible most of the time. */ @@ -108,15 +117,6 @@ SessionDialog::SessionDialog (bool require_new, const std::string& session_name, get_vbox()->show_all (); - cancel_button = add_button ((cancel_not_quit ? Stock::CANCEL : Stock::QUIT), RESPONSE_CANCEL); - back_button = add_button (Stock::GO_BACK, RESPONSE_NO); - open_button = add_button (Stock::OPEN, RESPONSE_ACCEPT); - - back_button->signal_button_press_event().connect (sigc::mem_fun (*this, &SessionDialog::back_button_pressed), false); - - open_button->set_sensitive (false); - back_button->set_sensitive (false); - /* fill data models and how/hide accordingly */ populate_session_templates (); From f5cd838afcbee304302b3ab6b56a058f72c1bc2e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 24 Sep 2013 22:22:43 -0400 Subject: [PATCH 28/42] start explicitly linking against libtimecode (this needs to happen elsewhere too) --- libs/ardour/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 474a9c58c6..0fd5c4e80f 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -341,7 +341,7 @@ def build(bld): 'OSX','BOOST','CURL','DL'] obj.use = ['libpbd','libmidipp','libevoral','libvamphost', 'libvampplugin','libtaglib','librubberband', - 'libaudiographer','libltc'] + 'libaudiographer','libltc','libtimecode'] obj.vnum = LIBARDOUR_LIB_VERSION obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3') obj.defines = [ From e43a8dac1ccfd7bb9766c9714eb0f47aca72283b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 25 Sep 2013 17:59:10 -0400 Subject: [PATCH 29/42] make information extraction from session file options list robust against some old badly formatted session files Fixes crash experienced by GillesM, where a rogue XML entry caused a segfault --- libs/ardour/session_state.cc | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 2b2afc0d3d..d96db8f188 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -3784,11 +3784,20 @@ Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFo const XMLNodeList& options (child->children()); for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) { const XMLNode* option = *oc; - if (option->property("name")->value() == "native-file-data-format") { - SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt); - data_format = fmt; - found_data_format = true; - break; + const XMLProperty* name = option->property("name"); + + if (!name) { + continue; + } + + if (name->value() == "native-file-data-format") { + const XMLProperty* value = option->property ("value"); + if (value) { + SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt); + data_format = fmt; + found_data_format = true; + break; + } } } } From d6274d5c3e588ee0b66bf95551567a77b38b3619 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 25 Sep 2013 18:24:32 -0400 Subject: [PATCH 30/42] fix up enum mess caused by switching from JACK to Engine as the name for jack-related transport sync This will allow older versions of Ardour to continue to startup when the user sync preference is "JACK", because the string used by enum_2_string() will still be "JACK". Versions of ardour3 from git after the enum change until this commit will leave ardour.rc unloaded by old versions of Ardour ***if*** the user sync choice was "JACK". --- libs/ardour/ardour/types.h | 6 +++++- libs/ardour/enums.cc | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index ca3f1acc19..526a71c58b 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -489,8 +489,12 @@ namespace ARDOUR { }; enum SyncSource { - Engine = 0, + /* These are "synonyms". It is important for JACK to be first + both here and in enums.cc, so that the string "JACK" is + correctly recognized in older session and preference files. + */ JACK = 0, + Engine = 0, MTC, MIDIClock, LTC diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 3898a0e881..2a38cd2c8a 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -335,8 +335,8 @@ setup_enum_writer () REGISTER (_PluginType); REGISTER_ENUM (MTC); - REGISTER_ENUM (Engine); REGISTER_ENUM (JACK); + REGISTER_ENUM (Engine); REGISTER_ENUM (MIDIClock); REGISTER_ENUM (LTC); REGISTER (_SyncSource); From c736d88a5f71a1e5d8c975c7222b93cdc1d4204b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 25 Sep 2013 22:56:28 -0400 Subject: [PATCH 31/42] don't ping JACK server 4 times to see if it is already up when ardour starts --- libs/backends/jack/jack_api.cc | 2 +- libs/backends/jack/jack_audiobackend.cc | 5 +++- libs/backends/jack/jack_connection.cc | 36 ++++++++----------------- libs/backends/jack/jack_connection.h | 6 ++--- 4 files changed, 18 insertions(+), 31 deletions(-) diff --git a/libs/backends/jack/jack_api.cc b/libs/backends/jack/jack_api.cc index 836acfda11..c8859a1fc9 100644 --- a/libs/backends/jack/jack_api.cc +++ b/libs/backends/jack/jack_api.cc @@ -63,7 +63,7 @@ deinstantiate () static bool already_configured () { - return JackConnection::server_running (); + return !JackConnection::in_control (); } static ARDOUR::AudioBackendInfo _descriptor = { diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index d4e2f310d3..c6a523f4d2 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -513,7 +513,10 @@ JACKAudioBackend::start () { if (!available()) { - if (!_jack_connection->server_running()) { + if (_jack_connection->in_control()) { + /* we will be starting JACK, so set up the + command that JACK will use when it (auto-)starts + */ setup_jack_startup_command (); } diff --git a/libs/backends/jack/jack_connection.cc b/libs/backends/jack/jack_connection.cc index d5d25c747f..b3d7fcecc4 100644 --- a/libs/backends/jack/jack_connection.cc +++ b/libs/backends/jack/jack_connection.cc @@ -36,6 +36,8 @@ using std::vector; using std::cerr; using std::endl; +bool JackConnection::_in_control = false; + static void jack_halted_callback (void* arg) { JackConnection* jc = static_cast (arg); @@ -54,17 +56,9 @@ JackConnection::JackConnection (const std::string& arg1, const std::string& arg2 , _client_name (arg1) , session_uuid (arg2) { - _in_control = !server_running(); -} + /* See if the server is already up + */ -JackConnection::~JackConnection () -{ - close (); -} - -bool -JackConnection::server_running () -{ EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa (); boost::scoped_ptr current_epa; @@ -83,10 +77,15 @@ JackConnection::server_running () if (status == 0) { jack_client_close (c); - return true; + _in_control = false; + } else { + _in_control = true; } +} - return false; +JackConnection::~JackConnection () +{ + close (); } int @@ -106,19 +105,6 @@ JackConnection::open () global_epa->restore (); } - /* check to see if the server is already running so that we know if we - * are starting it. - */ - - jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status); - - if (status == 0) { - _in_control = false; - jack_client_close (c); - } else { - _in_control = true; - } - /* ensure that PATH or equivalent includes likely locations of the JACK * server, in case the user's default does not. */ diff --git a/libs/backends/jack/jack_connection.h b/libs/backends/jack/jack_connection.h index 229d9697d9..8d15be6e3a 100644 --- a/libs/backends/jack/jack_connection.h +++ b/libs/backends/jack/jack_connection.h @@ -27,15 +27,13 @@ class JackConnection { void halted_callback (); void halted_info_callback (jack_status_t, const char*); - bool in_control() const { return _in_control; } + static bool in_control() { return _in_control; } - static bool server_running(); - private: jack_client_t* volatile _jack; std::string _client_name; std::string session_uuid; - bool _in_control; + static bool _in_control; }; } // namespace From 82f0f3a9a76097402afae8be1c9a65d526ad8cf2 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 2 Oct 2013 16:17:22 -0400 Subject: [PATCH 32/42] fix up crash caused by changes in object creation order and setting the state of the click IO object --- libs/ardour/ardour/session.h | 1 + libs/ardour/session.cc | 15 +++++++++++---- libs/ardour/session_state.cc | 8 +------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 2fcf6d476a..937ae4fb2e 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1619,6 +1619,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void setup_ltc (); void setup_click (); + void setup_click_state (const XMLNode&); void setup_bundles (); static int get_session_info_from_path (XMLTree& state_tree, const std::string& xmlpath); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index d45375fe0d..28849e2930 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -592,14 +592,21 @@ Session::setup_ltc () void Session::setup_click () { - XMLNode* child = 0; - _clicking = false; _click_io.reset (new ClickIO (*this, "click")); _click_gain.reset (new Amp (*this)); _click_gain->activate (); - - if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) { + if (state_tree) { + setup_click_state (*state_tree->root()); + } +} + +void +Session::setup_click_state (const XMLNode& node) +{ + const XMLNode* child = 0; + + if ((child = find_named_node (node, "Click")) != 0) { /* existing state for Click */ int c = 0; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index d96db8f188..94e9f00564 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -1317,13 +1317,7 @@ Session::set_state (const XMLNode& node, int version) if ((child = find_named_node (node, "Click")) == 0) { warning << _("Session: XML state has no click section") << endmsg; } else if (_click_io) { - const XMLNodeList& children (child->children()); - XMLNodeList::const_iterator i = children.begin(); - _click_io->set_state (**i, version); - ++i; - if (i != children.end()) { - _click_gain->set_state (**i, version); - } + setup_click_state (node); } if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) { From df363a4fb3057253c1530941176cac49a7ffd409 Mon Sep 17 00:00:00 2001 From: Tim Mayberry Date: Wed, 14 Aug 2013 20:30:09 +1000 Subject: [PATCH 33/42] Add AudioBackendThread class to support different thread type on windows --- libs/ardour/ardour/audio_backend.h | 8 +++- libs/ardour/ardour/audio_backend_thread.h | 32 +++++++++++++++ libs/ardour/ardour/audioengine.h | 9 ++++- libs/ardour/ardour/graph.h | 6 +-- libs/ardour/ardour/types.h | 10 ----- libs/ardour/audioengine.cc | 19 ++++++--- libs/ardour/graph.cc | 21 ++++------ libs/backends/jack/jack_audiobackend.cc | 48 ++++++++++++++++++++--- libs/backends/jack/jack_audiobackend.h | 5 ++- 9 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 libs/ardour/ardour/audio_backend_thread.h diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index 9052acd530..3d65af481d 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -399,13 +399,17 @@ class AudioBackend : public PortEngine { * stacksize. The thread will begin executing @param func, and will exit * when that function returns. */ - virtual int create_process_thread (boost::function func, AudioBackendNativeThread*, size_t stacksize) = 0; + virtual int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize) = 0; /** Wait for the thread specified by @param thread to exit. * * Return zero on success, non-zero on failure. */ - virtual int wait_for_process_thread_exit (AudioBackendNativeThread thread) = 0; + virtual int join_process_thread (AudioBackendThread* thread) = 0; + + /** Return true if execution context is in a backend thread + */ + virtual bool in_process_thread () = 0; virtual void update_latencies () = 0; diff --git a/libs/ardour/ardour/audio_backend_thread.h b/libs/ardour/ardour/audio_backend_thread.h new file mode 100644 index 0000000000..90efecbc94 --- /dev/null +++ b/libs/ardour/ardour/audio_backend_thread.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2013 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +namespace ARDOUR { + +class AudioBackendThread +{ +public: + + AudioBackendThread () { } + + virtual ~AudioBackendThread () { } + +}; + +} // namespace ARDOUR diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 201d960479..82364ca191 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -58,6 +58,7 @@ class Session; class ProcessThread; class AudioBackend; class AudioBackendInfo; +class AudioBackendThread; class AudioEngine : public SessionHandlePtr, public PortManager { @@ -100,8 +101,12 @@ public: pframes_t sample_time_at_cycle_start (); pframes_t samples_since_cycle_start (); bool get_sync_offset (pframes_t& offset) const; - int create_process_thread (boost::function func, AudioBackendNativeThread*, size_t stacksize); - int wait_for_process_thread_exit (AudioBackendNativeThread); + + int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize); + int join_process_thread (AudioBackendThread*); + + bool in_process_thread (); + bool is_realtime() const; bool connected() const; diff --git a/libs/ardour/ardour/graph.h b/libs/ardour/ardour/graph.h index 08af6fb721..ed9e22de31 100644 --- a/libs/ardour/ardour/graph.h +++ b/libs/ardour/ardour/graph.h @@ -31,8 +31,6 @@ #include #include -#include - #include "pbd/semutils.h" #include "ardour/types.h" @@ -49,6 +47,8 @@ class Route; class Session; class GraphEdges; +class AudioBackendThread; + typedef boost::shared_ptr node_ptr_t; typedef std::list< node_ptr_t > node_list_t; @@ -93,7 +93,7 @@ protected: virtual void session_going_away (); private: - std::list _thread_list; + std::list _thread_list; volatile bool _quit_threads; void reset_thread_list (); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 526a71c58b..ee43d1f30f 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -615,16 +615,6 @@ namespace ARDOUR { uint32_t max; //< samples }; -/* PLATFORM SPECIFIC #ifdef's here */ - - /** Define the native thread type used on the platform */ - typedef pthread_t AudioBackendNativeThread; - static inline bool self_thread_equal (AudioBackendNativeThread thr) { - return pthread_equal (thr, pthread_self()); - } - -/* PLATFORM SPECIFIC #endif's here */ - } // namespace ARDOUR diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 465f88de56..38e9ad0b86 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -826,21 +826,30 @@ AudioEngine::get_sync_offset (pframes_t& offset) const } int -AudioEngine::create_process_thread (boost::function func, AudioBackendNativeThread* thr, size_t stacksize) +AudioEngine::create_process_thread (boost::function func, AudioBackendThread* thread, size_t stacksize) { if (!_backend) { return -1; } - return _backend->create_process_thread (func, thr, stacksize); + return _backend->create_process_thread (func, thread, stacksize); } int -AudioEngine::wait_for_process_thread_exit (AudioBackendNativeThread thr) +AudioEngine::join_process_thread (AudioBackendThread* thr) { if (!_backend) { - return 0; + return -1; } - return _backend->wait_for_process_thread_exit (thr); + return _backend->join_process_thread (thr); +} + +bool +AudioEngine::in_process_thread () +{ + if (!_backend) { + return false; + } + return _backend->in_process_thread (); } int diff --git a/libs/ardour/graph.cc b/libs/ardour/graph.cc index c8e374cddc..8b3d24031b 100644 --- a/libs/ardour/graph.cc +++ b/libs/ardour/graph.cc @@ -101,24 +101,24 @@ Graph::reset_thread_list () } Glib::Threads::Mutex::Lock lm (_session.engine().process_lock()); - AudioBackendNativeThread a_thread; + AudioBackendThread* backend_thread; if (!_thread_list.empty()) { drop_threads (); } - if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), &a_thread, 100000) != 0) { + if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), backend_thread, 100000) != 0) { throw failed_constructor (); } - _thread_list.push_back (a_thread); + _thread_list.push_back (backend_thread); for (uint32_t i = 1; i < num_threads; ++i) { - if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), &a_thread, 100000) != 0) { + if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), backend_thread, 100000) != 0) { throw failed_constructor (); } - _thread_list.push_back (a_thread); + _thread_list.push_back (backend_thread); } } @@ -146,8 +146,8 @@ Graph::drop_threads () _callback_start_sem.signal (); - for (list::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) { - AudioEngine::instance()->wait_for_process_thread_exit (*i); + for (list::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) { + AudioEngine::instance()->join_process_thread (*i); } _thread_list.clear (); @@ -583,10 +583,5 @@ Graph::process_one_route (Route* route) bool Graph::in_process_thread () const { - for (list::const_iterator i = _thread_list.begin (); i != _thread_list.end(); ++i) { - if (self_thread_equal (*i)) { - return true; - } - } - return false; + return AudioEngine::instance()->in_process_thread (); } diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index c6a523f4d2..cd4874e85a 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -33,6 +33,7 @@ #include "ardour/audioengine.h" #include "ardour/session.h" #include "ardour/types.h" +#include "ardour/audio_backend_thread.h" #include "jack_audiobackend.h" #include "jack_connection.h" @@ -45,6 +46,17 @@ using namespace PBD; using std::string; using std::vector; +class JACKAudioBackendThread : public AudioBackendThread +{ +public: + + JACKAudioBackendThread (jack_native_thread_t id) + : thread_id(id) { } + + jack_native_thread_t thread_id; + +}; + #define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; } #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; } @@ -825,25 +837,49 @@ JACKAudioBackend::_latency_callback (jack_latency_callback_mode_t mode, void* ar } int -JACKAudioBackend::create_process_thread (boost::function f, pthread_t* thread, size_t stacksize) +JACKAudioBackend::create_process_thread (boost::function f, AudioBackendThread* backend_thread, size_t stacksize) { GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + + jack_native_thread_t thread_id; ThreadData* td = new ThreadData (this, f, stacksize); - if (jack_client_create_thread (_priv_jack, thread, jack_client_real_time_priority (_priv_jack), + if (jack_client_create_thread (_priv_jack, &thread_id, jack_client_real_time_priority (_priv_jack), jack_is_realtime (_priv_jack), _start_process_thread, td)) { return -1; } - return 0; + backend_thread = new JACKAudioBackendThread(thread_id); + return 0; } int -JACKAudioBackend::wait_for_process_thread_exit (AudioBackendNativeThread thr) +JACKAudioBackend::join_process_thread (AudioBackendThread* backend_thread) { + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + + JACKAudioBackendThread * jack_thread = dynamic_cast(backend_thread); + int ret = 0; + +#if defined(USING_JACK2_EXPANSION_OF_JACK_API) || defined(PLATFORM_WINDOWS) + if (jack_client_stop_thread (_priv_jack, jack_thread->thread_id) != 0) { + error << "AudioEngine: cannot stop process thread" << endmsg; + ret = -1; + } +#else void* status; - /* this doesn't actively try to stop the thread, it just waits till it exits */ - return pthread_join (thr, &status); + ret = pthread_join (jack_thread->thread_id, &status); +#endif + delete jack_thread; + return ret; +} + +bool +JACKAudioBackend::in_process_thread () +{ + // XXX TODO + + return false; } void* diff --git a/libs/backends/jack/jack_audiobackend.h b/libs/backends/jack/jack_audiobackend.h index 9ab545f3ee..822dc71053 100644 --- a/libs/backends/jack/jack_audiobackend.h +++ b/libs/backends/jack/jack_audiobackend.h @@ -103,8 +103,9 @@ class JACKAudioBackend : public AudioBackend { size_t raw_buffer_size (DataType t); - int create_process_thread (boost::function func, AudioBackendNativeThread*, size_t stacksize); - int wait_for_process_thread_exit (AudioBackendNativeThread); + int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize); + int join_process_thread (AudioBackendThread*); + bool in_process_thread (); void transport_start (); void transport_stop (); From 53ad2d187ffb31edcb90f7db5799886ee1806586 Mon Sep 17 00:00:00 2001 From: Tim Mayberry Date: Wed, 2 Oct 2013 19:40:48 +1000 Subject: [PATCH 34/42] Move processing thread list from ARDOUR::Graph into AudioBackend implementation --- libs/ardour/ardour/audio_backend.h | 14 +++++-- libs/ardour/ardour/audio_backend_thread.h | 32 ---------------- libs/ardour/ardour/audioengine.h | 7 ++-- libs/ardour/ardour/graph.h | 5 --- libs/ardour/audioengine.cc | 17 +++++++-- libs/ardour/graph.cc | 23 ++++-------- libs/backends/jack/jack_audiobackend.cc | 46 +++++++++++------------ libs/backends/jack/jack_audiobackend.h | 7 +++- 8 files changed, 63 insertions(+), 88 deletions(-) delete mode 100644 libs/ardour/ardour/audio_backend_thread.h diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index 3d65af481d..0e39625e8c 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -399,18 +399,26 @@ class AudioBackend : public PortEngine { * stacksize. The thread will begin executing @param func, and will exit * when that function returns. */ - virtual int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize) = 0; + virtual int create_process_thread (boost::function func) = 0; - /** Wait for the thread specified by @param thread to exit. + /** Wait for all processing threads to exit. * * Return zero on success, non-zero on failure. */ - virtual int join_process_thread (AudioBackendThread* thread) = 0; + virtual int join_process_threads () = 0; /** Return true if execution context is in a backend thread */ virtual bool in_process_thread () = 0; + /** Return the minimum stack size of audio threads in bytes + */ + static size_t thread_stack_size () { return 100000; } + + /** Return number of processing threads + */ + virtual uint32_t process_thread_count () = 0; + virtual void update_latencies () = 0; protected: diff --git a/libs/ardour/ardour/audio_backend_thread.h b/libs/ardour/ardour/audio_backend_thread.h deleted file mode 100644 index 90efecbc94..0000000000 --- a/libs/ardour/ardour/audio_backend_thread.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright (C) 2013 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -namespace ARDOUR { - -class AudioBackendThread -{ -public: - - AudioBackendThread () { } - - virtual ~AudioBackendThread () { } - -}; - -} // namespace ARDOUR diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 82364ca191..1bf4be3243 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -58,7 +58,6 @@ class Session; class ProcessThread; class AudioBackend; class AudioBackendInfo; -class AudioBackendThread; class AudioEngine : public SessionHandlePtr, public PortManager { @@ -102,10 +101,10 @@ public: pframes_t samples_since_cycle_start (); bool get_sync_offset (pframes_t& offset) const; - int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize); - int join_process_thread (AudioBackendThread*); - + int create_process_thread (boost::function func); + int join_process_threads (); bool in_process_thread (); + uint32_t process_thread_count (); bool is_realtime() const; bool connected() const; diff --git a/libs/ardour/ardour/graph.h b/libs/ardour/ardour/graph.h index ed9e22de31..763723c792 100644 --- a/libs/ardour/ardour/graph.h +++ b/libs/ardour/ardour/graph.h @@ -47,8 +47,6 @@ class Route; class Session; class GraphEdges; -class AudioBackendThread; - typedef boost::shared_ptr node_ptr_t; typedef std::list< node_ptr_t > node_list_t; @@ -59,8 +57,6 @@ class Graph : public SessionHandleRef public: Graph (Session & session); - uint32_t threads_in_use () const { return _thread_list.size(); } - void prep(); void trigger (GraphNode * n); void rechain (boost::shared_ptr, GraphEdges const &); @@ -93,7 +89,6 @@ protected: virtual void session_going_away (); private: - std::list _thread_list; volatile bool _quit_threads; void reset_thread_list (); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 38e9ad0b86..631a861741 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -826,21 +826,21 @@ AudioEngine::get_sync_offset (pframes_t& offset) const } int -AudioEngine::create_process_thread (boost::function func, AudioBackendThread* thread, size_t stacksize) +AudioEngine::create_process_thread (boost::function func) { if (!_backend) { return -1; } - return _backend->create_process_thread (func, thread, stacksize); + return _backend->create_process_thread (func); } int -AudioEngine::join_process_thread (AudioBackendThread* thr) +AudioEngine::join_process_threads () { if (!_backend) { return -1; } - return _backend->join_process_thread (thr); + return _backend->join_process_threads (); } bool @@ -852,6 +852,15 @@ AudioEngine::in_process_thread () return _backend->in_process_thread (); } +uint32_t +AudioEngine::process_thread_count () +{ + if (!_backend) { + return 0; + } + return _backend->process_thread_count (); +} + int AudioEngine::set_device_name (const std::string& name) { diff --git a/libs/ardour/graph.cc b/libs/ardour/graph.cc index 8b3d24031b..71eeee41ea 100644 --- a/libs/ardour/graph.cc +++ b/libs/ardour/graph.cc @@ -96,29 +96,24 @@ Graph::reset_thread_list () number of threads. */ - if (_thread_list.size() == num_threads) { + if (AudioEngine::instance()->process_thread_count() == num_threads) { return; } Glib::Threads::Mutex::Lock lm (_session.engine().process_lock()); - AudioBackendThread* backend_thread; - if (!_thread_list.empty()) { + if (AudioEngine::instance()->process_thread_count() != 0) { drop_threads (); } - if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), backend_thread, 100000) != 0) { + if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this)) != 0) { throw failed_constructor (); } - _thread_list.push_back (backend_thread); - for (uint32_t i = 1; i < num_threads; ++i) { - if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), backend_thread, 100000) != 0) { + if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this))) { throw failed_constructor (); } - - _thread_list.push_back (backend_thread); } } @@ -140,17 +135,15 @@ Graph::drop_threads () { _quit_threads = true; - for (unsigned int i=0; i< _thread_list.size(); i++) { + uint32_t thread_count = AudioEngine::instance()->process_thread_count (); + + for (unsigned int i=0; i < thread_count; i++) { _execution_sem.signal (); } _callback_start_sem.signal (); - for (list::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) { - AudioEngine::instance()->join_process_thread (*i); - } - - _thread_list.clear (); + AudioEngine::instance()->join_process_threads (); _execution_tokens = 0; diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index cd4874e85a..19f15b1fa1 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -33,7 +33,6 @@ #include "ardour/audioengine.h" #include "ardour/session.h" #include "ardour/types.h" -#include "ardour/audio_backend_thread.h" #include "jack_audiobackend.h" #include "jack_connection.h" @@ -46,16 +45,6 @@ using namespace PBD; using std::string; using std::vector; -class JACKAudioBackendThread : public AudioBackendThread -{ -public: - - JACKAudioBackendThread (jack_native_thread_t id) - : thread_id(id) { } - - jack_native_thread_t thread_id; - -}; #define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; } #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; } @@ -837,40 +826,45 @@ JACKAudioBackend::_latency_callback (jack_latency_callback_mode_t mode, void* ar } int -JACKAudioBackend::create_process_thread (boost::function f, AudioBackendThread* backend_thread, size_t stacksize) +JACKAudioBackend::create_process_thread (boost::function f) { GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); jack_native_thread_t thread_id; - ThreadData* td = new ThreadData (this, f, stacksize); + ThreadData* td = new ThreadData (this, f, thread_stack_size()); if (jack_client_create_thread (_priv_jack, &thread_id, jack_client_real_time_priority (_priv_jack), jack_is_realtime (_priv_jack), _start_process_thread, td)) { return -1; } - backend_thread = new JACKAudioBackendThread(thread_id); + _jack_threads.push_back(thread_id); return 0; } int -JACKAudioBackend::join_process_thread (AudioBackendThread* backend_thread) +JACKAudioBackend::join_process_threads () { GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); - JACKAudioBackendThread * jack_thread = dynamic_cast(backend_thread); int ret = 0; + for (std::vector::const_iterator i = _jack_threads.begin (); + i != _jack_threads.end(); i++) { + #if defined(USING_JACK2_EXPANSION_OF_JACK_API) || defined(PLATFORM_WINDOWS) - if (jack_client_stop_thread (_priv_jack, jack_thread->thread_id) != 0) { - error << "AudioEngine: cannot stop process thread" << endmsg; - ret = -1; - } + if (jack_client_stop_thread (_priv_jack, *i) != 0) { #else - void* status; - ret = pthread_join (jack_thread->thread_id, &status); + void* status; + if (pthread_join (*i, &status) != 0) { #endif - delete jack_thread; + error << "AudioEngine: cannot stop process thread" << endmsg; + ret += -1; + } + } + + _jack_threads.clear(); + return ret; } @@ -882,6 +876,12 @@ JACKAudioBackend::in_process_thread () return false; } +uint32_t +JACKAudioBackend::process_thread_count () +{ + return _jack_threads.size(); +} + void* JACKAudioBackend::_start_process_thread (void* arg) { diff --git a/libs/backends/jack/jack_audiobackend.h b/libs/backends/jack/jack_audiobackend.h index 822dc71053..b8d8b3b3f1 100644 --- a/libs/backends/jack/jack_audiobackend.h +++ b/libs/backends/jack/jack_audiobackend.h @@ -103,9 +103,10 @@ class JACKAudioBackend : public AudioBackend { size_t raw_buffer_size (DataType t); - int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize); - int join_process_thread (AudioBackendThread*); + int create_process_thread (boost::function func); + int join_process_threads (); bool in_process_thread (); + uint32_t process_thread_count (); void transport_start (); void transport_stop (); @@ -185,6 +186,8 @@ class JACKAudioBackend : public AudioBackend { bool _freewheeling; std::map _raw_buffer_sizes; + std::vector _jack_threads; + static int _xrun_callback (void *arg); static void* _process_thread (void *arg); static int _sample_rate_callback (pframes_t nframes, void *arg); From f3a22fb88027548aebe67107e70113950d72417a Mon Sep 17 00:00:00 2001 From: Tim Mayberry Date: Thu, 3 Oct 2013 19:38:58 +1000 Subject: [PATCH 35/42] Implement JACKAudioBackend::in_process_thread --- libs/backends/jack/jack_audiobackend.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index 19f15b1fa1..a651f2522d 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -871,7 +871,19 @@ JACKAudioBackend::join_process_threads () bool JACKAudioBackend::in_process_thread () { - // XXX TODO + for (std::vector::const_iterator i = _jack_threads.begin (); + i != _jack_threads.end(); i++) { + +#ifdef COMPILER_MINGW + if (*i == GetCurrentThread()) { + return true; + } +#else // pthreads + if (pthread_equal (*i, pthread_self()) != 0) { + return true; + } +#endif + } return false; } From 74f3955682ba25f9d0bd5cc9fb7c8b86a9d36517 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 4 Oct 2013 11:46:50 -0400 Subject: [PATCH 36/42] remove OSC related cruft from ardour_ui_options.cc control surface activation is handled via an entirely separate mechanism now --- gtk2_ardour/ardour_ui_options.cc | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/gtk2_ardour/ardour_ui_options.cc b/gtk2_ardour/ardour_ui_options.cc index 618169d2e8..0e28900450 100644 --- a/gtk2_ardour/ardour_ui_options.cc +++ b/gtk2_ardour/ardour_ui_options.cc @@ -29,10 +29,6 @@ #include "ardour/rc_configuration.h" #include "ardour/session.h" -#ifdef HAVE_LIBLO -#include "ardour/osc.h" -#endif - #include "audio_clock.h" #include "ardour_ui.h" #include "actions.h" @@ -342,16 +338,6 @@ ARDOUR_UI::parameter_changed (std::string p) ActionManager::map_some_state ("options", "SendMMC", &RCConfiguration::get_send_mmc); - } else if (p == "use-osc") { - -#ifdef HAVE_LIBLO - if (Config->get_use_osc()) { - osc->start (); - } else { - osc->stop (); - } -#endif - } else if (p == "keep-tearoffs") { ActionManager::map_some_state ("Common", "KeepTearoffs", &RCConfiguration::get_keep_tearoffs); } else if (p == "mmc-control") { From 3aee160b19b7ae0637475331ae003eb2ae78aae6 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 4 Oct 2013 12:22:00 -0400 Subject: [PATCH 37/42] provide PBD::demangle() even on platforms without HAVE_EXECINFO --- libs/pbd/stacktrace.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/pbd/stacktrace.cc b/libs/pbd/stacktrace.cc index 805b9a2e84..b78f0e9338 100644 --- a/libs/pbd/stacktrace.cc +++ b/libs/pbd/stacktrace.cc @@ -96,6 +96,12 @@ PBD::stacktrace (std::ostream& out, int levels) #else +std::string +PBD::demangle (std::string const & l) +{ + return string; +} + void PBD::stacktrace (std::ostream& out, int /*levels*/) { From 6daa7c1bc31d9688cb2aa2d20bac7c7893f6fc1c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 4 Oct 2013 12:46:02 -0400 Subject: [PATCH 38/42] remove unnecessary header include --- gtk2_ardour/transcode_video_dialog.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/gtk2_ardour/transcode_video_dialog.cc b/gtk2_ardour/transcode_video_dialog.cc index d4ad8a24ed..6e4a1a3298 100644 --- a/gtk2_ardour/transcode_video_dialog.cc +++ b/gtk2_ardour/transcode_video_dialog.cc @@ -28,7 +28,6 @@ #include #include -#include #include "pbd/error.h" #include "pbd/convert.h" From 1344014cbdc92cd8db6dbb20a9547ea143d8ed20 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 4 Oct 2013 12:46:31 -0400 Subject: [PATCH 39/42] switch from MAXPATHLEN to PATH_MAX, and use not for portability --- gtk2_ardour/sfdb_ui.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc index 5f8564374e..4944ef41a0 100644 --- a/gtk2_ardour/sfdb_ui.cc +++ b/gtk2_ardour/sfdb_ui.cc @@ -26,8 +26,8 @@ #include #include +#include #include -#include #include #include @@ -1468,7 +1468,7 @@ SoundFileOmega::check_link_status (const Session* s, const vector& paths for (vector::const_iterator i = paths.begin(); i != paths.end(); ++i) { - char tmpc[MAXPATHLEN+1]; + char tmpc[PATH_MAX+1]; snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str()); From 028cd5660f72576dd13dbf838b8ae8eef2e74098 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 4 Oct 2013 12:50:03 -0400 Subject: [PATCH 40/42] use g_strcasecmp() instead of strcasecmp() which doesn't exist with MSVC (some versions, at least) --- gtk2_ardour/gtk_pianokeyboard.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gtk2_ardour/gtk_pianokeyboard.c b/gtk2_ardour/gtk_pianokeyboard.c index 1e5768040e..f3897e3d44 100644 --- a/gtk2_ardour/gtk_pianokeyboard.c +++ b/gtk2_ardour/gtk_pianokeyboard.c @@ -33,9 +33,9 @@ #include #include -#include #include #include + #include #include @@ -732,13 +732,13 @@ piano_keyboard_set_keyboard_layout(PianoKeyboard *pk, const char *layout) { assert(layout); - if (!strcasecmp(layout, "QWERTY")) { + if (!g_strcasecmp(layout, "QWERTY")) { bind_keys_qwerty(pk); - } else if (!strcasecmp(layout, "QWERTZ")) { + } else if (!g_strcasecmp(layout, "QWERTZ")) { bind_keys_qwertz(pk); - } else if (!strcasecmp(layout, "AZERTY")) { + } else if (!g_strcasecmp(layout, "AZERTY")) { bind_keys_azerty(pk); } else { From ddcb78f3e2a6e6e6404a61e7ea52a1d4fd2c44e7 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 4 Oct 2013 13:00:59 -0400 Subject: [PATCH 41/42] use g_strcasecmp() instead of strcasecmp() which doesn't exist with MSVC (some versions, at least), part 2 --- gtk2_ardour/editor_regions.cc | 8 ++++---- gtk2_ardour/plugin_selector.cc | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gtk2_ardour/editor_regions.cc b/gtk2_ardour/editor_regions.cc index ad5263d1d1..72a0da2909 100644 --- a/gtk2_ardour/editor_regions.cc +++ b/gtk2_ardour/editor_regions.cc @@ -1115,7 +1115,7 @@ EditorRegions::sorter (TreeModel::iterator a, TreeModel::iterator b) switch (_sort_type) { case ByName: - cmp = strcasecmp (region1->name().c_str(), region2->name().c_str()); + cmp = g_strcasecmp (region1->name().c_str(), region2->name().c_str()); break; case ByLength: @@ -1140,7 +1140,7 @@ EditorRegions::sorter (TreeModel::iterator a, TreeModel::iterator b) break; case BySourceFileName: - cmp = strcasecmp (region1->source()->name().c_str(), region2->source()->name().c_str()); + cmp = g_strcasecmp (region1->source()->name().c_str(), region2->source()->name().c_str()); break; case BySourceFileLength: @@ -1153,9 +1153,9 @@ EditorRegions::sorter (TreeModel::iterator a, TreeModel::iterator b) case BySourceFileFS: if (region1->source()->name() == region2->source()->name()) { - cmp = strcasecmp (region1->name().c_str(), region2->name().c_str()); + cmp = g_strcasecmp (region1->name().c_str(), region2->name().c_str()); } else { - cmp = strcasecmp (region1->source()->name().c_str(), region2->source()->name().c_str()); + cmp = g_strcasecmp (region1->source()->name().c_str(), region2->source()->name().c_str()); } break; } diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc index 81adf40896..ebfcc677ac 100644 --- a/gtk2_ardour/plugin_selector.cc +++ b/gtk2_ardour/plugin_selector.cc @@ -538,13 +538,13 @@ struct PluginMenuCompareByCreator { bool operator() (PluginInfoPtr a, PluginInfoPtr b) const { int cmp; - cmp = strcasecmp (a->creator.c_str(), b->creator.c_str()); + cmp = g_strcasecmp (a->creator.c_str(), b->creator.c_str()); if (cmp < 0) { return true; } else if (cmp == 0) { /* same creator ... compare names */ - if (strcasecmp (a->name.c_str(), b->name.c_str()) < 0) { + if (g_strcasecmp (a->name.c_str(), b->name.c_str()) < 0) { return true; } } @@ -556,7 +556,7 @@ struct PluginMenuCompareByName { bool operator() (PluginInfoPtr a, PluginInfoPtr b) const { int cmp; - cmp = strcasecmp (a->name.c_str(), b->name.c_str()); + cmp = g_strcasecmp (a->name.c_str(), b->name.c_str()); if (cmp < 0) { return true; @@ -574,13 +574,13 @@ struct PluginMenuCompareByCategory { bool operator() (PluginInfoPtr a, PluginInfoPtr b) const { int cmp; - cmp = strcasecmp (a->category.c_str(), b->category.c_str()); + cmp = g_strcasecmp (a->category.c_str(), b->category.c_str()); if (cmp < 0) { return true; } else if (cmp == 0) { /* same category ... compare names */ - if (strcasecmp (a->name.c_str(), b->name.c_str()) < 0) { + if (g_strcasecmp (a->name.c_str(), b->name.c_str()) < 0) { return true; } } From 449f600c699ebc60d6520ea43b0ac2b91b13f878 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 4 Oct 2013 13:02:41 -0400 Subject: [PATCH 42/42] remove another unnecessary use of libgen.h --- gtk2_ardour/export_video_dialog.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/gtk2_ardour/export_video_dialog.cc b/gtk2_ardour/export_video_dialog.cc index b1b59fa088..dd08b58661 100644 --- a/gtk2_ardour/export_video_dialog.cc +++ b/gtk2_ardour/export_video_dialog.cc @@ -28,7 +28,6 @@ #include #include -#include #include "pbd/error.h" #include "pbd/convert.h"