summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Emmas <johne53@tiscali.co.uk>2013-10-14 19:31:22 +0100
committerJohn Emmas <johne53@tiscali.co.uk>2013-10-14 19:31:22 +0100
commite466ce40ad1ba591543020cb7c0aa15dbebef81e (patch)
treef8e43560917a0a70c48d32ac171e828472cfd794
parent4fac237fdcf025c5fd5aafe207113abd6abb469b (diff)
parenta901f28c6287ff99444d6a8afe67b71531a5f7d0 (diff)
Merge branch 'master' into windows+cc
Conflicts (hopefully resolved): gtk2_ardour/ardour_ui.cc
-rw-r--r--gtk2_ardour/ardour.menus.in11
-rw-r--r--gtk2_ardour/ardour_button.cc2
-rw-r--r--gtk2_ardour/ardour_button.h2
-rw-r--r--gtk2_ardour/ardour_ui.cc34
-rw-r--r--gtk2_ardour/ardour_ui_ed.cc2
-rw-r--r--gtk2_ardour/editor.cc3
-rw-r--r--gtk2_ardour/editor.h2
-rw-r--r--gtk2_ardour/editor_videotimeline.cc4
-rw-r--r--gtk2_ardour/engine_dialog.cc2759
-rw-r--r--gtk2_ardour/engine_dialog.h13
-rw-r--r--gtk2_ardour/export_video_dialog.cc22
-rw-r--r--gtk2_ardour/export_video_dialog.h2
-rw-r--r--gtk2_ardour/plugin_ui.cc3
-rw-r--r--gtk2_ardour/processor_box.cc97
-rw-r--r--gtk2_ardour/processor_box.h12
-rw-r--r--gtk2_ardour/public_editor.h2
-rw-r--r--gtk2_ardour/window_manager.cc35
-rw-r--r--gtk2_ardour/window_manager.h2
-rw-r--r--gtk2_ardour/wscript2
-rw-r--r--libs/ardour/ardour/audio_backend.h40
-rw-r--r--libs/ardour/ardour/audioengine.h8
-rw-r--r--libs/ardour/ardour/processor.h4
-rw-r--r--libs/ardour/audioengine.cc77
-rw-r--r--libs/ardour/processor.cc12
-rw-r--r--libs/ardour/route.cc4
-rwxr-xr-x[-rw-r--r--]libs/ardour/run-session-tests.sh15
-rwxr-xr-xlibs/ardour/run-tests.sh1
-rw-r--r--libs/ardour/test-env.sh1
-rw-r--r--libs/ardour/test/audio_region_read_test.cc1
-rw-r--r--libs/ardour/test/audio_region_test.cc3
-rw-r--r--libs/ardour/test/automation_list_property_test.cc42
-rw-r--r--libs/ardour/test/load_session.cc4
-rw-r--r--libs/ardour/test/playlist_read_test.cc1
-rw-r--r--libs/ardour/test/profiling/load_session.cc4
-rw-r--r--libs/ardour/test/profiling/runpc.cc3
-rw-r--r--libs/ardour/test/session_test.cc16
-rw-r--r--libs/ardour/test/test_common.cc9
-rw-r--r--libs/ardour/test/test_common.h4
-rw-r--r--libs/ardour/test/test_globals.cc3
-rw-r--r--libs/ardour/test/test_globals.h2
-rw-r--r--libs/ardour/test/test_needing_session.cc4
-rw-r--r--libs/ardour/test/test_util.cc9
-rw-r--r--libs/ardour/test/test_util.h2
-rw-r--r--libs/ardour/wscript2
-rw-r--r--libs/backends/jack/jack_audiobackend.cc31
-rw-r--r--libs/backends/jack/jack_audiobackend.h9
-rw-r--r--libs/backends/jack/jack_utils.cc75
-rw-r--r--libs/backends/jack/jack_utils.h7
-rw-r--r--libs/pbd/controllable_descriptor.cc3
-rwxr-xr-xtools/linux_packaging/build5
-rwxr-xr-xtools/osx_packaging/osx_build8
51 files changed, 1934 insertions, 1484 deletions
diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in
index 9694556e56..6068055324 100644
--- a/gtk2_ardour/ardour.menus.in
+++ b/gtk2_ardour/ardour.menus.in
@@ -35,10 +35,9 @@
<menuitem action='addExistingAudioFiles'/>
<!--menuitem action='importFromSession'/-->
-#ifndef NOVIDEOTIMELINE
<menuitem action='OpenVideo'/>
<menuitem action='CloseVideo'/>
-#endif
+
<menu name='Export' action='Export'>
<menuitem action='ExportAudio'/>
<menuitem action='StemExport'/>
@@ -282,9 +281,7 @@
<menuitem action='snap-regions-to-grid'/>
<menuitem action='toggle-region-lock'/>
<menuitem action='toggle-region-lock-style'/>
-#ifndef NOVIDEOTIMELINE
<menuitem action='toggle-region-video-lock'/>
-#endif
<menuitem action='set-region-sync-position'/>
<menuitem action='remove-region-sync'/>
<menuitem action='nudge-forward'/>
@@ -437,9 +434,7 @@
<menuitem action="toggle-cd-marker-ruler"/>
<menuitem action="toggle-marker-ruler"/>
<separator/>
-#ifndef NOVIDEOTIMELINE
<menuitem action="toggle-video-ruler"/>
-#endif
</menu>
<menu action="VideoMonitorMenu">
<menuitem action="zoom-vmon-100"/>
@@ -543,10 +538,8 @@
<menuitem action="toggle-marker-ruler"/>
<menuitem action="toggle-cd-marker-ruler"/>
<menuitem action="toggle-loop-punch-ruler"/>
-#ifndef NOVIDEOTIMELINE
<separator/>
<menuitem action="toggle-video-ruler"/>
-#endif
</popup>
<popup name='ProcessorMenu'>
@@ -642,9 +635,7 @@
<menuitem action='naturalize-region'/>
<menuitem action='toggle-region-lock'/>
<menuitem action='toggle-region-lock-style'/>
-#ifndef NOVIDEOTIMELINE
<menuitem action='toggle-region-video-lock'/>
-#endif
<menuitem action='snap-regions-to-grid'/>
<menuitem action='set-region-sync-position'/>
<menuitem action='remove-region-sync'/>
diff --git a/gtk2_ardour/ardour_button.cc b/gtk2_ardour/ardour_button.cc
index 89e6a20385..3f118921d6 100644
--- a/gtk2_ardour/ardour_button.cc
+++ b/gtk2_ardour/ardour_button.cc
@@ -162,7 +162,7 @@ ArdourButton::set_markup (const std::string& str)
_layout = Pango::Layout::create (get_pango_context());
}
- _layout->set_text (str);
+ _layout->set_markup (str);
queue_resize ();
}
diff --git a/gtk2_ardour/ardour_button.h b/gtk2_ardour/ardour_button.h
index efa956162a..65ea10b201 100644
--- a/gtk2_ardour/ardour_button.h
+++ b/gtk2_ardour/ardour_button.h
@@ -156,7 +156,7 @@ class ArdourButton : public CairoWidget , public Gtkmm2ext::Activatable
bool _fixed_diameter;
bool _distinct_led_click;
bool _hovering;
-
+
static bool _flat_buttons;
void setup_led_rect ();
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index 5f3ef2d31d..b4ea8338dd 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -439,7 +439,7 @@ ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
} else {
msgstr = string_compose (_("\
-`The audio backend 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\
the audio backend and save the session."), PROGRAM_NAME);
@@ -800,7 +800,11 @@ ARDOUR_UI::starting ()
* audio backend end up.
*/
- audio_midi_setup.get (true);
+ try {
+ audio_midi_setup.get (true);
+ } catch (...) {
+ return -1;
+ }
/* go get a session */
@@ -2851,6 +2855,22 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
}
}
+ if (!new_session->writable()) {
+ MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
+ true,
+ Gtk::MESSAGE_INFO,
+ BUTTONS_OK);
+
+ msg.set_keep_above (true);
+ msg.set_title (_("Read-only Session"));
+ msg.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash (msg);
+ msg.present ();
+ (void) msg.run ();
+ msg.hide ();
+ }
+
+
/* Now the session been created, add the transport controls */
new_session->add_controllable(roll_controllable);
new_session->add_controllable(stop_controllable);
@@ -3815,8 +3835,13 @@ int
ARDOUR_UI::reconnect_to_engine ()
{
if (AudioEngine::instance()->start ()) {
- MessageDialog msg (*editor, _("Could not reconnect to the Audio/MIDI engine"));
- msg.run ();
+ if (editor) {
+ MessageDialog msg (*editor, _("Could not reconnect to the Audio/MIDI engine"));
+ msg.run ();
+ } else {
+ MessageDialog msg (_("Could not reconnect to the Audio/MIDI engine"));
+ msg.run ();
+ }
return -1;
}
@@ -4133,6 +4158,7 @@ int
ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
{
audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
+ audio_midi_setup->set_position (WIN_POS_CENTER);
switch (audio_midi_setup->run()) {
case Gtk::RESPONSE_OK:
diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc
index 251fc8f6fc..0ed7a95df3 100644
--- a/gtk2_ardour/ardour_ui_ed.cc
+++ b/gtk2_ardour/ardour_ui_ed.cc
@@ -139,7 +139,7 @@ ARDOUR_UI::install_actions ()
sigc::mem_fun (*this, &ARDOUR_UI::remove_video));
act->set_sensitive (false);
act = ActionManager::register_action (main_actions, X_("ExportVideo"), _("Export To Video File"),
- sigc::mem_fun (*editor, &PublicEditor::export_video));
+ hide_return (sigc::bind (sigc::mem_fun(*editor, &PublicEditor::export_video), false)));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (main_actions, X_("Snapshot"), _("Snapshot..."), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::snapshot_session), false));
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index c7bdfc15da..5da1d09d8f 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -1913,6 +1913,9 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
+ if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
+ edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
+ }
}
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 566586ebe4..c427429897 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -895,7 +895,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void toggle_ruler_video (bool onoff) {ruler_video_action->set_active(onoff);}
int videotl_bar_height; /* in units of timebar_height; default: 4 */
int get_videotl_bar_height () const { return videotl_bar_height; }
- void export_video ();
+ void export_video (bool range = false);
void toggle_region_video_lock ();
Gtk::VBox time_bars_vbox;
diff --git a/gtk2_ardour/editor_videotimeline.cc b/gtk2_ardour/editor_videotimeline.cc
index 1da9fb4f19..2526d7c16a 100644
--- a/gtk2_ardour/editor_videotimeline.cc
+++ b/gtk2_ardour/editor_videotimeline.cc
@@ -111,7 +111,7 @@ Editor::embed_audio_from_video (std::string path, framepos_t n)
}
void
-Editor::export_video ()
+Editor::export_video (bool range)
{
if (ARDOUR::Config->get_show_video_export_info()) {
ExportVideoInfobox infobox (_session);
@@ -127,7 +127,7 @@ Editor::export_video ()
break;
}
}
- ExportVideoDialog dialog (_session, get_selection().time);
+ ExportVideoDialog dialog (_session, get_selection().time, range);
Gtk::ResponseType r = (Gtk::ResponseType) dialog.run();
(void) r; // keep gcc quiet
dialog.hide();
diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc
index dfd24af739..47a2506f92 100644
--- a/gtk2_ardour/engine_dialog.cc
+++ b/gtk2_ardour/engine_dialog.cc
@@ -30,6 +30,7 @@
#include "pbd/error.h"
#include "pbd/xml++.h"
#include "pbd/unwind.h"
+#include "pbd/failed_constructor.h"
#include <gtkmm/alignment.h>
#include <gtkmm/stock.h>
@@ -57,9 +58,14 @@ using namespace Gtkmm2ext;
using namespace PBD;
using namespace Glib;
+static const unsigned int midi_tab = -1; /* not currently in use */
+static const unsigned int latency_tab = 1; /* zero-based, page zero is the main setup page */
+
+static const char* results_markup = X_("<span foreground=\"red\" style=\"italic\" size=\"larger\">%1</span>");
+
EngineControl::EngineControl ()
: ArdourDialog (_("Audio/MIDI Setup"))
- , basic_packer (9, 3)
+ , basic_packer (9, 4)
, input_latency_adjustment (0, 0, 99999, 1)
, input_latency (input_latency_adjustment)
, output_latency_adjustment (0, 0, 99999, 1)
@@ -71,12 +77,14 @@ EngineControl::EngineControl ()
, ports_adjustment (128, 8, 1024, 1, 16)
, ports_spinner (ports_adjustment)
, control_app_button (_("Device Control Panel"))
- , lm_start_stop_label (_("Measure latency"))
+ , lm_measure_button (_("Measure"))
, lm_use_button (_("Use results"))
- , lm_table (5, 2)
+ , lm_back_button (_("Back to settings ... (ignore results)"))
+ , lm_button (_("Calibrate..."))
+ , lm_table (12, 3)
, have_lm_results (false)
+ , lm_running (false)
, midi_refresh_button (_("Refresh list"))
- , aj_button (_("Start MIDI ALSA/JACK bridge"))
, ignore_changes (0)
, _desired_sample_rate (0)
, no_push (true)
@@ -94,6 +102,13 @@ EngineControl::EngineControl ()
*/
vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
+
+ if (backends.empty()) {
+ MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME));
+ msg.run ();
+ throw failed_constructor ();
+ }
+
for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
strings.push_back ((*b)->name);
}
@@ -108,7 +123,7 @@ EngineControl::EngineControl ()
basic_packer.set_spacings (6);
basic_packer.set_border_width (12);
- basic_packer.set_homogeneous (true);
+ basic_packer.set_homogeneous (false);
/* pack it in */
@@ -122,8 +137,10 @@ EngineControl::EngineControl ()
row = 0;
lm_table.set_row_spacings (12);
-
- lm_table.attach (lm_title, 0, 2, row, row+1, xopt, (AttachOptions) 0);
+ lm_table.set_col_spacings (6);
+ lm_table.set_homogeneous (false);
+
+ lm_table.attach (lm_title, 0, 3, row, row+1, xopt, (AttachOptions) 0);
row++;
Gtk::Label* preamble;
@@ -131,17 +148,17 @@ EngineControl::EngineControl ()
preamble = manage (new Label);
preamble->set_width_chars (60);
preamble->set_line_wrap (true);
- preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your hardware to a very low level.</span>"));
+ preamble->set_markup (_("<span weight=\"bold\">Turn down the volume on your audio equipment to a very low level.</span>"));
- lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+ lm_table.attach (*preamble, 0, 3, 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."));
+ preamble->set_markup (_("Select two channels below and connect them using a cable."));
- lm_table.attach (*preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+ lm_table.attach (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
row++;
label = manage (new Label (_("Output channel")));
@@ -149,7 +166,7 @@ EngineControl::EngineControl ()
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);
+ lm_table.attach (*misc_align, 1, 3, row, row+1, xopt, (AttachOptions) 0);
++row;
label = manage (new Label (_("Input channel")));
@@ -157,41 +174,61 @@ EngineControl::EngineControl ()
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);
+ lm_table.attach (*misc_align, 1, 3, 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_measure_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::latency_button_clicked));
lm_use_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::use_latency_button_clicked));
+ lm_back_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), 0));
+
lm_use_button.set_sensitive (false);
+ /* Increase the default spacing around the labels of these three
+ * buttons
+ */
+
+ Gtk::Misc* l;
+
+ if ((l = dynamic_cast<Gtk::Misc*>(lm_measure_button.get_child())) != 0) {
+ l->set_padding (10, 10);
+ }
+
+ if ((l = dynamic_cast<Gtk::Misc*>(lm_use_button.get_child())) != 0) {
+ l->set_padding (10, 10);
+ }
+
+ if ((l = dynamic_cast<Gtk::Misc*>(lm_back_button.get_child())) != 0) {
+ l->set_padding (10, 10);
+ }
+
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);
+ preamble->set_markup (_("Once the channels are connected, click the \"Measure\" button."));
+ lm_table.attach (*preamble, 0, 3, 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 (*preamble, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
- lm_table.attach (lm_use_button, 0, 2, row, row+1, xopt, (AttachOptions) 0);
- ++row;
+ ++row; // skip a row in the table
+ ++row; // skip a row in the table
+
+ lm_table.attach (lm_results, 0, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+
+ ++row; // skip a row in the table
+ ++row; // skip a row in the table
+
+ lm_table.attach (lm_measure_button, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+ lm_table.attach (lm_use_button, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
+ lm_table.attach (lm_back_button, 2, 3, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0);
- lm_results.set_markup ("<i>No measurement results yet</i>");
+ lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
lm_vbox.set_border_width (12);
lm_vbox.pack_start (lm_table, false, false);
@@ -199,11 +236,11 @@ EngineControl::EngineControl ()
/* 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 (midi_vbox, _("MIDI")));
notebook.pages().push_back (TabElem (lm_vbox, _("Latency")));
notebook.set_border_width (12);
- notebook.set_tab_pos (POS_RIGHT);
+ notebook.set_show_tabs (false);
notebook.show_all ();
notebook.set_name ("SettingsNotebook");
@@ -230,7 +267,7 @@ EngineControl::EngineControl ()
/* Pick up any existing audio setup configuration, if appropriate */
XMLNode* audio_setup = ARDOUR::Config->extra_xml ("AudioMIDISetup");
-
+
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());
@@ -247,6 +284,7 @@ EngineControl::EngineControl ()
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));
+ midi_option_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::midi_option_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));
@@ -256,1323 +294,1385 @@ EngineControl::EngineControl ()
notebook.signal_switch_page().connect (sigc::mem_fun (*this, &EngineControl::on_switch_page));
no_push = false;
-}
-
-void
-EngineControl::on_response (int response_id)
-{
- ArdourDialog::on_response (response_id);
-
- switch (response_id) {
- case RESPONSE_APPLY:
- push_state_to_backend (true);
- break;
- case RESPONSE_OK:
- push_state_to_backend (true);
- hide ();
- break;
- case RESPONSE_DELETE_EVENT: {
- GdkEventButton ev;
- ev.type = GDK_BUTTON_PRESS;
- ev.button = 1;
- on_delete_event ((GdkEventAny*) &ev);
- break;
- }
- default:
- hide ();
- }
-}
-
-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<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
- assert (backend);
-
- using namespace Notebook_Helpers;
- Label* label;
- vector<string> strings;
- AttachOptions xopt = AttachOptions (FILL|EXPAND);
- int row = 1; // row zero == backend combo
-
- /* start packing it up */
-
- 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);
- basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
- row++;
-
- 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++;
-
-
- 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++;
-
- input_channels.set_name ("InputChannels");
- input_channels.set_flags(Gtk::CAN_FOCUS);
- input_channels.set_digits(0);
- input_channels.set_wrap(false);
- output_channels.set_editable (true);
-
- label = manage (left_aligned_label (_("Input Channels:")));
- basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
- basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
- ++row;
-
- output_channels.set_name ("OutputChannels");
- output_channels.set_flags(Gtk::CAN_FOCUS);
- output_channels.set_digits(0);
- output_channels.set_wrap(false);
- output_channels.set_editable (true);
-
- label = manage (left_aligned_label (_("Output Channels:")));
- basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
- basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
- ++row;
-
- input_latency.set_name ("InputLatency");
- input_latency.set_flags(Gtk::CAN_FOCUS);
- input_latency.set_digits(0);
- input_latency.set_wrap(false);
- input_latency.set_editable (true);
-
- label = manage (left_aligned_label (_("Hardware input latency:")));
- basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
- basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
- label = manage (left_aligned_label (_("samples")));
- basic_packer.attach (*label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
- ++row;
-
- output_latency.set_name ("OutputLatency");
- output_latency.set_flags(Gtk::CAN_FOCUS);
- output_latency.set_digits(0);
- output_latency.set_wrap(false);
- output_latency.set_editable (true);
-
- label = manage (left_aligned_label (_("Hardware output latency:")));
- basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
- basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
- label = manage (left_aligned_label (_("samples")));
- basic_packer.attach (*label, 2, 3, row, row+1, xopt, (AttachOptions) 0);
- ++row;
-
-}
-
-void
-EngineControl::build_no_control_notebook ()
-{
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
- assert (backend);
-
- using namespace Notebook_Helpers;
- Label* label;
- vector<string> 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());
-
- label = manage (new Label);
- label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
- basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
- row++;
-
- 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++;
- }
-
- 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++;
- }
-
- 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++;
-}
-
-EngineControl::~EngineControl ()
-{
-
-}
-
-void
-EngineControl::disable_latency_tab ()
-{
- vector<string> empty;
- set_popdown_strings (lm_output_channel_combo, empty);
- set_popdown_strings (lm_input_channel_combo, empty);
- lm_measure_button.set_sensitive (false);
- lm_use_button.set_sensitive (false);
-}
-
-void
-EngineControl::enable_latency_tab ()
-{
- vector<string> outputs;
- ARDOUR::AudioEngine::instance()->get_physical_outputs (ARDOUR::DataType::AUDIO, outputs);
- set_popdown_strings (lm_output_channel_combo, outputs);
- lm_output_channel_combo.set_active_text (outputs.front());
-
- vector<string> inputs;
- ARDOUR::AudioEngine::instance()->get_physical_inputs (ARDOUR::DataType::AUDIO, inputs);
- set_popdown_strings (lm_input_channel_combo, inputs);
- lm_input_channel_combo.set_active_text (inputs.front());
-
- lm_measure_button.set_sensitive (true);
-}
-
-void
-EngineControl::setup_midi_tab_for_backend ()
-{
- string backend = backend_combo.get_active_text ();
-
- Gtkmm2ext::container_clear (midi_vbox);
-
- midi_vbox.set_border_width (12);
- midi_device_table.set_border_width (12);
-
- if (backend == "JACK") {
- setup_midi_tab_for_jack ();
- }
-
- midi_vbox.pack_start (midi_device_table, true, true);
- midi_vbox.pack_start (midi_refresh_button, false, false);
- midi_vbox.show_all ();
-
- midi_refresh_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::refresh_midi_display));
-}
-
-void
-EngineControl::setup_midi_tab_for_jack ()
-{
- midi_vbox.pack_start (aj_button, false, false);
-}
-
-void
-EngineControl::refresh_midi_display ()
-{
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
- assert (backend);
-
- vector<string> midi_inputs;
- vector<string> midi_outputs;
- int row = 0;
- AttachOptions xopt = AttachOptions (FILL|EXPAND);
- Gtk::Label* l;
-
- Gtkmm2ext::container_clear (midi_device_table);
-
- backend->get_physical_inputs (ARDOUR::DataType::MIDI, midi_inputs);
- backend->get_physical_outputs (ARDOUR::DataType::MIDI, midi_outputs);
-
- midi_device_table.set_spacings (6);
- midi_device_table.set_homogeneous (true);
- midi_device_table.resize (midi_inputs.size() + midi_outputs.size() + 3, 1);
-
- l = manage (new Label);
- l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Inputs")));
- midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
- l->set_alignment (0, 0.5);
- row++;
- l->show ();
-
- for (vector<string>::iterator p = midi_inputs.begin(); p != midi_inputs.end(); ++p) {
- l = manage (new Label ((*p).substr ((*p).find_last_of (':') + 1)));
- l->set_alignment (0, 0.5);
- midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
- l->show ();
- row++;
- }
-
- row++; // extra row of spacing
-
- l = manage (new Label);
- l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Outputs")));
- midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
- l->set_alignment (0, 0.5);
- row++;
- l->show ();
-
- for (vector<string>::iterator p = midi_outputs.begin(); p != midi_outputs.end(); ++p) {
- l = manage (new Label ((*p).substr ((*p).find_last_of (':') + 1)));
- l->set_alignment (0, 0.5);
- midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
- l->show ();
- row++;
- }
-}
-
-void
-EngineControl::update_sensitivity ()
-{
-}
-
-void
-EngineControl::backend_changed ()
-{
- if (ignore_changes) {
- return;
- }
-
- string backend_name = backend_combo.get_active_text();
- boost::shared_ptr<ARDOUR::AudioBackend> backend;
-
- if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
- /* eh? setting the backend failed... how ? */
- return;
- }
-
- _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
-
- build_notebook ();
- setup_midi_tab_for_backend ();
-
- if (backend->requires_driver_selection()) {
- vector<string> drivers = backend->enumerate_drivers();
-
- if (!drivers.empty()) {
- {
- PBD::Unwinder<uint32_t> 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
+ }
+
+ void
+ EngineControl::on_response (int response_id)
+ {
+ ArdourDialog::on_response (response_id);
+
+ switch (response_id) {
+ case RESPONSE_APPLY:
+ push_state_to_backend (true);
+ break;
+ case RESPONSE_OK:
+ push_state_to_backend (true);
+ hide ();
+ break;
+ case RESPONSE_DELETE_EVENT: {
+ GdkEventButton ev;
+ ev.type = GDK_BUTTON_PRESS;
+ ev.button = 1;
+ on_delete_event ((GdkEventAny*) &ev);
+ break;
+ }
+ default:
+ hide ();
+ }
+ }
+
+ 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);
+
+ lm_button.signal_clicked.connect (sigc::bind (sigc::mem_fun (notebook, &Gtk::Notebook::set_current_page), latency_tab));
+ lm_button.set_name ("record enable button");
+ 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<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+ assert (backend);
+
+ using namespace Notebook_Helpers;
+ Label* label;
+ vector<string> strings;
+ AttachOptions xopt = AttachOptions (FILL|EXPAND);
+ int row = 1; // row zero == backend combo
+
+ /* start packing it up */
+
+ 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);
+ basic_packer.attach (device_combo, 1, 2, row, row + 1, xopt, (AttachOptions) 0);
+ row++;
+
+ 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++;
+
+
+ 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, SHRINK, (AttachOptions) 0);
+ row++;
+
+ input_channels.set_name ("InputChannels");
+ input_channels.set_flags(Gtk::CAN_FOCUS);
+ input_channels.set_digits(0);
+ input_channels.set_wrap(false);
+ output_channels.set_editable (true);
+
+ label = manage (left_aligned_label (_("Input Channels:")));
+ basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+ basic_packer.attach (input_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
+ ++row;
+
+ output_channels.set_name ("OutputChannels");
+ output_channels.set_flags(Gtk::CAN_FOCUS);
+ output_channels.set_digits(0);
+ output_channels.set_wrap(false);
+ output_channels.set_editable (true);
+
+ label = manage (left_aligned_label (_("Output Channels:")));
+ basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+ basic_packer.attach (output_channels, 1, 2, row, row+1, xopt, (AttachOptions) 0);
+ ++row;
+
+ input_latency.set_name ("InputLatency");
+ input_latency.set_flags(Gtk::CAN_FOCUS);
+ input_latency.set_digits(0);
+ input_latency.set_wrap(false);
+ input_latency.set_editable (true);
+
+ label = manage (left_aligned_label (_("Hardware input latency:")));
+ basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+ basic_packer.attach (input_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
+ label = manage (left_aligned_label (_("samples")));
+ basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
+ ++row;
+
+ output_latency.set_name ("OutputLatency");
+ output_latency.set_flags(Gtk::CAN_FOCUS);
+ output_latency.set_digits(0);
+ output_latency.set_wrap(false);
+ output_latency.set_editable (true);
+
+ label = manage (left_aligned_label (_("Hardware output latency:")));
+ basic_packer.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0);
+ basic_packer.attach (output_latency, 1, 2, row, row+1, xopt, (AttachOptions) 0);
+ label = manage (left_aligned_label (_("samples")));
+ basic_packer.attach (*label, 2, 3, row, row+1, SHRINK, (AttachOptions) 0);
+
+ /* button spans 2 rows */
+
+ basic_packer.attach (lm_button, 3, 4, row-1, row+1, xopt, xopt);
+ ++row;
+
+ label = manage (left_aligned_label (_("MIDI System")));
+ basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
+ basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
+ row++;
+ }
+
+ void
+ EngineControl::build_no_control_notebook ()
+ {
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+ assert (backend);
+
+ using namespace Notebook_Helpers;
+ Label* label;
+ vector<string> 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());
+
+ label = manage (new Label);
+ label->set_markup (string_compose ("<span weight=\"bold\" foreground=\"red\">%1</span>", msg));
+ basic_packer.attach (*label, 0, 2, row, row + 1, xopt, (AttachOptions) 0);
+ row++;
+
+ 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++;
+ }
+
+ 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++;
+ }
+
+ 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++;
+ }
+
+ EngineControl::~EngineControl ()
+ {
+ ignore_changes = true;
+ }
+
+ void
+ EngineControl::disable_latency_tab ()
+ {
+ vector<string> empty;
+ set_popdown_strings (lm_output_channel_combo, empty);
+ set_popdown_strings (lm_input_channel_combo, empty);
+ lm_measure_button.set_sensitive (false);
+ lm_use_button.set_sensitive (false);
+ }
+
+ void
+ EngineControl::enable_latency_tab ()
+ {
+ vector<string> outputs;
+ ARDOUR::AudioEngine::instance()->get_physical_outputs (ARDOUR::DataType::AUDIO, outputs);
+ set_popdown_strings (lm_output_channel_combo, outputs);
+ lm_output_channel_combo.set_active_text (outputs.front());
+
+ vector<string> inputs;
+ ARDOUR::AudioEngine::instance()->get_physical_inputs (ARDOUR::DataType::AUDIO, inputs);
+ set_popdown_strings (lm_input_channel_combo, inputs);
+ lm_input_channel_combo.set_active_text (inputs.front());
+
+ lm_measure_button.set_sensitive (true);
+ }
+
+ void
+ EngineControl::setup_midi_tab_for_backend ()
+ {
+ string backend = backend_combo.get_active_text ();
+
+ Gtkmm2ext::container_clear (midi_vbox);
+
+ midi_vbox.set_border_width (12);
+ midi_device_table.set_border_width (12);
+
+ if (backend == "JACK") {
+ setup_midi_tab_for_jack ();
+ }
+
+ midi_vbox.pack_start (midi_device_table, true, true);
+ midi_vbox.pack_start (midi_refresh_button, false, false);
+ midi_vbox.show_all ();
+
+ midi_refresh_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::refresh_midi_display));
+ }
+
+ void
+ EngineControl::setup_midi_tab_for_jack ()
+ {
+ }
+
+ void
+ EngineControl::refresh_midi_display ()
+ {
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+ assert (backend);
+
+ vector<string> midi_inputs;
+ vector<string> midi_outputs;
+ int row = 0;
+ AttachOptions xopt = AttachOptions (FILL|EXPAND);
+ Gtk::Label* l;
+
+ Gtkmm2ext::container_clear (midi_device_table);
+
+ backend->get_physical_inputs (ARDOUR::DataType::MIDI, midi_inputs);
+ backend->get_physical_outputs (ARDOUR::DataType::MIDI, midi_outputs);
+
+ midi_device_table.set_spacings (6);
+ midi_device_table.set_homogeneous (true);
+ midi_device_table.resize (midi_inputs.size() + midi_outputs.size() + 3, 1);
+
+ l = manage (new Label);
+ l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Inputs")));
+ midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
+ l->set_alignment (0, 0.5);
+ row++;
+ l->show ();
+
+ for (vector<string>::iterator p = midi_inputs.begin(); p != midi_inputs.end(); ++p) {
+ l = manage (new Label ((*p).substr ((*p).find_last_of (':') + 1)));
+ l->set_alignment (0, 0.5);
+ midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
+ l->show ();
+ row++;
+ }
+
+ row++; // extra row of spacing
+
+ l = manage (new Label);
+ l->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("MIDI Outputs")));
+ midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
+ l->set_alignment (0, 0.5);
+ row++;
+ l->show ();
+
+ for (vector<string>::iterator p = midi_outputs.begin(); p != midi_outputs.end(); ++p) {
+ l = manage (new Label ((*p).substr ((*p).find_last_of (':') + 1)));
+ l->set_alignment (0, 0.5);
+ midi_device_table.attach (*l, 0, 1, row, row + 1, xopt, AttachOptions (0));
+ l->show ();
+ row++;
+ }
+ }
+
+ void
+ EngineControl::update_sensitivity ()
+ {
+ }
+
+ void
+ EngineControl::backend_changed ()
+ {
+ if (ignore_changes) {
+ return;
+ }
+
+ string backend_name = backend_combo.get_active_text();
+ boost::shared_ptr<ARDOUR::AudioBackend> backend;
+
+ if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
+ /* eh? setting the backend failed... how ? */
+ return;
+ }
+
+ _have_control = ARDOUR::AudioEngine::instance()->setup_required ();
+
+ build_notebook ();
+ setup_midi_tab_for_backend ();
+
+ if (backend->requires_driver_selection()) {
+ vector<string> drivers = backend->enumerate_drivers();
+
+ if (!drivers.empty()) {
+ {
+ PBD::Unwinder<uint32_t> 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 ();
+ }
+
+ vector<string> midi_options = backend->enumerate_midi_options();
+
+ if (midi_options.size() == 1) {
+ /* only contains the "none" option */
+ midi_option_combo.set_sensitive (false);
+ } else {
+ if (_have_control) {
+ set_popdown_strings (midi_option_combo, midi_options);
+ midi_option_combo.set_active_text (midi_options.front());
+ midi_option_combo.set_sensitive (true);
+ } else {
+ midi_option_combo.set_sensitive (false);
+ }
+ }
+
+ maybe_display_saved_state ();
+ }
+
+ bool
+ EngineControl::print_channel_count (Gtk::SpinButton* sb)
+ {
+ uint32_t cnt = (uint32_t) sb->get_value();
+ if (cnt == 0) {
+ sb->set_text (_("all available channels"));
+ } else {
+ char buf[32];
+ snprintf (buf, sizeof (buf), "%d", cnt);
+ sb->set_text (buf);
+ }
+ return true;
+ }
+
+ void
+ EngineControl::list_devices ()
+ {
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+ assert (backend);
+
+ /* now fill out devices, mark sample rates, buffer sizes insensitive */
+
+ vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
+
+ /* NOTE: Ardour currently does not display the "available" field of the
+ * returned devices.
+ *
+ * Doing so would require a different GUI widget than the combo
+ * box/popdown that we currently use, since it has no way to list
+ * items that are not selectable. Something more like a popup menu,
+ * which could have unselectable items, would be appropriate.
+ */
+
+ vector<string> available_devices;
+
+ for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
+ available_devices.push_back (i->name);
+ }
+
+ if (!available_devices.empty()) {
+
+ update_sensitivity ();
+
+ {
+ PBD::Unwinder<uint32_t> 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 (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 ()
+ {
+ if (ignore_changes) {
+ return;
+ }
+
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+ assert (backend);
+
+ backend->set_driver (driver_combo.get_active_text());
+ list_devices ();
+
+ maybe_display_saved_state ();
+ }
+
+ void
+ EngineControl::device_changed ()
+ {
+ if (ignore_changes) {
+ return;
+ }
+
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+ assert (backend);
+ string device_name = device_combo.get_active_text ();
+ vector<string> s;
+
+ {
+ PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
+
+ /* don't allow programmatic change to combos to cause a
+ recursive call to this method.
*/
- list_devices ();
- }
-
- maybe_display_saved_state ();
-}
-bool
-EngineControl::print_channel_count (Gtk::SpinButton* sb)
-{
- uint32_t cnt = (uint32_t) sb->get_value();
- if (cnt == 0) {
- sb->set_text (_("all available channels"));
- } else {
- char buf[32];
- snprintf (buf, sizeof (buf), "%d", cnt);
- sb->set_text (buf);
- }
- return true;
-}
-
-void
-EngineControl::list_devices ()
-{
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
- assert (backend);
-
- /* now fill out devices, mark sample rates, buffer sizes insensitive */
-
- vector<ARDOUR::AudioBackend::DeviceStatus> all_devices = backend->enumerate_devices ();
-
- /* NOTE: Ardour currently does not display the "available" field of the
- * returned devices.
- *
- * Doing so would require a different GUI widget than the combo
- * box/popdown that we currently use, since it has no way to list
- * items that are not selectable. Something more like a popup menu,
- * which could have unselectable items, would be appropriate.
+ /* sample rates */
+
+ string desired;
+
+ vector<float> sr;
+
+ if (_have_control) {
+ sr = backend->available_sample_rates (device_name);
+ } else {
+
+ 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);
+ }
+
+ for (vector<float>::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<uint32_t> 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<uint32_t>::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 ();
+ }
+
+ /* pick up any saved state for this device */
+
+ maybe_display_saved_state ();
+
+ /* and push it to the backend */
+
+ push_state_to_backend (false);
+ }
+
+ string
+ EngineControl::bufsize_as_string (uint32_t sz)
+ {
+ /* Translators: "samples" is always plural here, so no
+ need for plural+singular forms.
*/
-
- vector<string> available_devices;
-
- for (vector<ARDOUR::AudioBackend::DeviceStatus>::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) {
- available_devices.push_back (i->name);
- }
-
- if (!available_devices.empty()) {
-
- update_sensitivity ();
-
- {
- PBD::Unwinder<uint32_t> 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 (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 ()
-{
- if (ignore_changes) {
- return;
- }
-
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
- assert (backend);
-
- backend->set_driver (driver_combo.get_active_text());
- list_devices ();
-
- maybe_display_saved_state ();
-}
-
-void
-EngineControl::device_changed ()
-{
- if (ignore_changes) {
- return;
- }
-
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
- assert (backend);
- string device_name = device_combo.get_active_text ();
- vector<string> s;
-
- {
- PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
-
- /* don't allow programmatic change to combos to cause a
- recursive call to this method.
- */
-
- /* sample rates */
-
- string desired;
-
- vector<float> sr;
-
- if (_have_control) {
- sr = backend->available_sample_rates (device_name);
- } else {
-
- 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);
- }
-
- for (vector<float>::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<uint32_t> 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<uint32_t>::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 ();
- }
-
- /* pick up any saved state for this device */
-
- maybe_display_saved_state ();
-
- /* and push it to the backend */
-
- push_state_to_backend (false);
-}
-
-string
-EngineControl::bufsize_as_string (uint32_t sz)
-{
- /* Translators: "samples" is always plural here, so no
- need for plural+singular forms.
- */
- char buf[32];
- snprintf (buf, sizeof (buf), _("%u samples"), sz);
- return buf;
-}
-
-void
-EngineControl::sample_rate_changed ()
-{
- if (ignore_changes) {
- return;
- }
-
- /* reset the strings for buffer size to show the correct msec value
- (reflecting the new sample rate).
- */
-
- show_buffer_duration ();
- save_state ();
-
-}
-
-void
-EngineControl::buffer_size_changed ()
-{
- if (ignore_changes) {
- return;
- }
-
- show_buffer_duration ();
- save_state ();
-}
-
-void
-EngineControl::show_buffer_duration ()
-{
-
- /* buffer sizes - convert from just samples to samples + msecs for
- * the displayed string
+ char buf[32];
+ snprintf (buf, sizeof (buf), _("%u samples"), sz);
+ return buf;
+ }
+
+ void
+ EngineControl::sample_rate_changed ()
+ {
+ if (ignore_changes) {
+ return;
+ }
+
+ /* reset the strings for buffer size to show the correct msec value
+ (reflecting the new sample rate).
*/
- string bs_text = buffer_size_combo.get_active_text ();
- uint32_t samples = atoi (bs_text); /* will ignore trailing text */
- uint32_t rate = get_rate();
-
- /* Translators: "msecs" is ALWAYS plural here, so we do not
- need singular form as well.
- */
- /* Developers: note the hard-coding of a double buffered model
- in the (2 * samples) computation of latency. we always start
- the audiobackend in this configuration.
- */
- char buf[32];
- snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
- buffer_size_duration_label.set_text (buf);
-}
-
-void
-EngineControl::parameter_changed ()
-{
- if (!ignore_changes) {
- save_state ();
- }
-}
-
-EngineControl::State*
-EngineControl::get_matching_state (const string& backend,
- const string& driver,
- const string& device)
-{
- for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
- if ((*i).backend == backend &&
- (*i).driver == driver &&
- (*i).device == device) {
- return &(*i);
- }
- }
- return 0;
-}
-
-EngineControl::State*
-EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
-{
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
-
- if (backend) {
- return get_matching_state (backend_combo.get_active_text(),
- (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
- device_combo.get_active_text());
- }
-
-
- return get_matching_state (backend_combo.get_active_text(),
- string(),
- device_combo.get_active_text());
-}
-
-EngineControl::State*
-EngineControl::save_state ()
-{
- if (!_have_control) {
- return 0;
- }
-
- bool existing = true;
- State* state = get_saved_state_for_currently_displayed_backend_and_device ();
-
- if (!state) {
- existing = false;
- state = new State;
- }
-
- store_state (*state);
-
- if (!existing) {
- states.push_back (*state);
- }
-
- return state;
-}
-
-void
-EngineControl::store_state (State& state)
-{
- state.backend = get_backend ();
- state.driver = get_driver ();
- state.device = get_device_name ();
- state.sample_rate = get_rate ();
- state.buffer_size = get_buffer_size ();
- state.input_latency = get_input_latency ();
- state.output_latency = get_output_latency ();
- state.input_channels = get_input_channels ();
- state.output_channels = get_output_channels ();
-}
-
-void
-EngineControl::maybe_display_saved_state ()
-{
- if (!_have_control) {
- return;
- }
-
- State* state = get_saved_state_for_currently_displayed_backend_and_device ();
-
- if (state) {
- PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
-
- if (!_desired_sample_rate) {
- sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
- }
- buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
- /* call this explicitly because we're ignoring changes to
- the controls at this point.
- */
- show_buffer_duration ();
- input_latency.set_value (state->input_latency);
- output_latency.set_value (state->output_latency);
- }
-}
-
-XMLNode&
-EngineControl::get_state ()
-{
- XMLNode* root = new XMLNode ("AudioMIDISetup");
- std::string path;
-
- if (!states.empty()) {
- XMLNode* state_nodes = new XMLNode ("EngineStates");
-
- for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
-
- XMLNode* node = new XMLNode ("State");
-
- node->add_property ("backend", (*i).backend);
- node->add_property ("driver", (*i).driver);
- node->add_property ("device", (*i).device);
- node->add_property ("sample-rate", (*i).sample_rate);
- node->add_property ("buffer-size", (*i).buffer_size);
- node->add_property ("input-latency", (*i).input_latency);
- node->add_property ("output-latency", (*i).output_latency);
- node->add_property ("input-channels", (*i).input_channels);
- node->add_property ("output-channels", (*i).output_channels);
- node->add_property ("active", (*i).active ? "yes" : "no");
-
- state_nodes->add_child_nocopy (*node);
- }
-
- root->add_child_nocopy (*state_nodes);
- }
-
- return *root;
-}
-
-void
-EngineControl::set_state (const XMLNode& root)
-{
- XMLNodeList clist, cclist;
- XMLNodeConstIterator citer, cciter;
- XMLNode* child;
- XMLNode* grandchild;
- XMLProperty* prop = NULL;
-
- if (root.name() != "AudioMIDISetup") {
- return;
- }
-
- clist = root.children();
-
- states.clear ();
-
- for (citer = clist.begin(); citer != clist.end(); ++citer) {
-
- child = *citer;
-
- if (child->name() != "EngineStates") {
- continue;
- }
-
- cclist = child->children();
-
- for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
- State state;
-
- grandchild = *cciter;
-
- if (grandchild->name() != "State") {
- continue;
- }
-
- if ((prop = grandchild->property ("backend")) == 0) {
- continue;
- }
- state.backend = prop->value ();
-
- if ((prop = grandchild->property ("driver")) == 0) {
- continue;
- }
- state.driver = prop->value ();
-
- if ((prop = grandchild->property ("device")) == 0) {
- continue;
- }
- state.device = prop->value ();
-
- if ((prop = grandchild->property ("sample-rate")) == 0) {
- continue;
- }
- state.sample_rate = atof (prop->value ());
-
- if ((prop = grandchild->property ("buffer-size")) == 0) {
- continue;
- }
- state.buffer_size = atoi (prop->value ());
-
- if ((prop = grandchild->property ("input-latency")) == 0) {
- continue;
- }
- state.input_latency = atoi (prop->value ());
-
- if ((prop = grandchild->property ("output-latency")) == 0) {
- continue;
- }
- state.output_latency = atoi (prop->value ());
-
- if ((prop = grandchild->property ("input-channels")) == 0) {
- continue;
- }
- state.input_channels = atoi (prop->value ());
-
- if ((prop = grandchild->property ("output-channels")) == 0) {
- continue;
- }
- state.output_channels = atoi (prop->value ());
-
- if ((prop = grandchild->property ("active")) == 0) {
- continue;
- }
- state.active = string_is_affirmative (prop->value ());
-
- states.push_back (state);
- }
- }
-
- /* 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);
- driver_combo.set_active_text ((*i).driver);
- device_combo.set_active_text ((*i).device);
- sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
- buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
- input_latency.set_value ((*i).input_latency);
- output_latency.set_value ((*i).output_latency);
- ignore_changes--;
- break;
- }
- }
-}
-
-
-int
-EngineControl::push_state_to_backend (bool start)
-{
- if (no_push) {
- return 0;
- }
-
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
-
- if (!backend) {
- return 0;
- }
-
- /* figure out what is going to change */
-
- bool restart_required = false;
- bool was_running = ARDOUR::AudioEngine::instance()->running();
- bool change_driver = false;
- bool change_device = false;
- bool change_rate = false;
- bool change_bufsize = false;
- bool change_latency = false;
- bool change_channels = false;
-
- uint32_t ochan = get_output_channels ();
- uint32_t ichan = get_input_channels ();
-
- if (_have_control) {
-
- 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 (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;
- change_rate = true;
- change_bufsize = true;
- change_channels = true;
- change_latency = true;
- }
-
- } else {
-
- /* we have no control over the backend, meaning that we can
- * only possibly change sample rate and buffer size.
- */
-
-
- if (get_rate() != backend->sample_rate()) {
- change_bufsize = true;
- }
-
- if (get_buffer_size() != backend->buffer_size()) {
- change_bufsize = true;
- }
- }
-
- if (!_have_control) {
-
- /* We do not have control over the backend, so the best we can
- * do is try to change the sample rate and/or bufsize and get
- * out of here.
- */
-
- if (change_rate && !backend->can_change_sample_rate_when_running()) {
- return 1;
- }
-
- if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
- return 1;
- }
-
- if (change_rate) {
- backend->set_sample_rate (get_rate());
- }
-
- if (change_bufsize) {
- backend->set_buffer_size (get_buffer_size());
- }
-
- post_push ();
-
- return 0;
- }
-
- /* determine if we need to stop the backend before changing parameters */
-
- if (change_driver || change_device || change_channels || change_latency ||
- (change_rate && !backend->can_change_sample_rate_when_running()) ||
- (change_bufsize && !backend->can_change_buffer_size_when_running())) {
- restart_required = true;
- } else {
- restart_required = false;
- }
+ show_buffer_duration ();
+ save_state ();
- if (was_running) {
+ }
- if (!change_driver && !change_device && !change_channels && !change_latency) {
- /* no changes in any parameters that absolutely require a
- * restart, so check those that might be changeable without a
- * restart
- */
-
- if (change_rate && !backend->can_change_sample_rate_when_running()) {
- /* can't do this while running ... */
- restart_required = true;
- }
-
- if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
- /* can't do this while running ... */
- restart_required = true;
- }
- }
- }
+ void
+ EngineControl::buffer_size_changed ()
+ {
+ if (ignore_changes) {
+ return;
+ }
- if (was_running) {
- if (restart_required) {
- if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
- return -1;
- }
- }
- }
-
+ show_buffer_duration ();
+ save_state ();
+ }
- if (change_driver && backend->set_driver (get_driver())) {
- error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
- return -1;
- }
- if (change_device && backend->set_device_name (get_device_name())) {
- error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
- return -1;
- }
- if (change_rate && backend->set_sample_rate (get_rate())) {
- error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
- return -1;
- }
- if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
- error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
- return -1;
- }
+ void
+ EngineControl::show_buffer_duration ()
+ {
- if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
- if (backend->set_input_channels (get_input_channels())) {
- error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
- return -1;
- }
- if (backend->set_output_channels (get_output_channels())) {
- error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
- return -1;
- }
- }
- if (change_latency) {
- if (backend->set_systemic_input_latency (get_input_latency())) {
- error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
- return -1;
- }
- if (backend->set_systemic_output_latency (get_output_latency())) {
- error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
- return -1;
- }
- }
-
- if (start || (was_running && restart_required)) {
- if (ARDOUR_UI::instance()->reconnect_to_engine()) {
- return -1;
- }
- }
-
- post_push ();
+ /* buffer sizes - convert from just samples to samples + msecs for
+ * the displayed string
+ */
- return 0;
-}
+ string bs_text = buffer_size_combo.get_active_text ();
+ uint32_t samples = atoi (bs_text); /* will ignore trailing text */
+ uint32_t rate = get_rate();
-void
-EngineControl::post_push ()
-{
- /* get a pointer to the current state object, creating one if
- * necessary
+ /* Translators: "msecs" is ALWAYS plural here, so we do not
+ need singular form as well.
*/
-
- 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 ();
- }
-
- /* schedule a redisplay of MIDI ports */
-
- Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
-}
-
-
-float
-EngineControl::get_rate () const
-{
- float r = atof (sample_rate_combo.get_active_text ());
- /* the string may have been translated with an abbreviation for
- * thousands, so use a crude heuristic to fix this.
+ /* Developers: note the hard-coding of a double buffered model
+ in the (2 * samples) computation of latency. we always start
+ the audiobackend in this configuration.
*/
- if (r < 1000.0) {
- r *= 1000.0;
- }
- return r;
-}
-
-
-uint32_t
-EngineControl::get_buffer_size () const
-{
- string txt = buffer_size_combo.get_active_text ();
- uint32_t samples;
-
- if (sscanf (txt.c_str(), "%d", &samples) != 1) {
- throw exception ();
- }
-
- return samples;
-}
-
-uint32_t
-EngineControl::get_input_channels() const
-{
- return (uint32_t) input_channels_adjustment.get_value();
-}
-
-uint32_t
-EngineControl::get_output_channels() const
-{
- return (uint32_t) output_channels_adjustment.get_value();
-}
-
-uint32_t
-EngineControl::get_input_latency() const
-{
- return (uint32_t) input_latency_adjustment.get_value();
-}
-
-uint32_t
-EngineControl::get_output_latency() const
-{
- return (uint32_t) output_latency_adjustment.get_value();
-}
-
-string
-EngineControl::get_backend () const
-{
- return backend_combo.get_active_text ();
-}
-
-string
-EngineControl::get_driver () const
-{
- return driver_combo.get_active_text ();
-}
-
-string
-EngineControl::get_device_name () const
-{
- return device_combo.get_active_text ();
-}
-
-void
-EngineControl::control_app_button_clicked ()
-{
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
-
- if (!backend) {
- return;
- }
-
- backend->launch_control_app ();
-}
-
-void
-EngineControl::manage_control_app_sensitivity ()
-{
- boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
-
- if (!backend) {
- return;
- }
-
- string appname = backend->control_app_name();
-
- if (appname.empty()) {
- control_app_button.set_sensitive (false);
- } else {
- control_app_button.set_sensitive (true);
- }
-}
-
-void
-EngineControl::set_desired_sample_rate (uint32_t sr)
-{
- _desired_sample_rate = sr;
- device_changed ();
-}
-
-void
-EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
-{
- if (page_num == 0) {
- cancel_button->set_sensitive (true);
- ok_button->set_sensitive (true);
- apply_button->set_sensitive (true);
- } else {
- cancel_button->set_sensitive (false);
- ok_button->set_sensitive (false);
- apply_button->set_sensitive (false);
- }
+ char buf[32];
+ snprintf (buf, sizeof (buf), _("(%.1f msecs)"), (2 * samples) / (rate/1000.0));
+ buffer_size_duration_label.set_text (buf);
+ }
+
+ void
+ EngineControl::midi_option_changed ()
+ {
+ if (!ignore_changes) {
+ save_state ();
+ }
+ }
+
+ void
+ EngineControl::parameter_changed ()
+ {
+ if (!ignore_changes) {
+ save_state ();
+ }
+ }
+
+ EngineControl::State*
+ EngineControl::get_matching_state (const string& backend,
+ const string& driver,
+ const string& device)
+ {
+ for (StateList::iterator i = states.begin(); i != states.end(); ++i) {
+ if ((*i).backend == backend &&
+ (*i).driver == driver &&
+ (*i).device == device) {
+ return &(*i);
+ }
+ }
+ return 0;
+ }
+
+ EngineControl::State*
+ EngineControl::get_saved_state_for_currently_displayed_backend_and_device ()
+ {
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+
+ if (backend) {
+ return get_matching_state (backend_combo.get_active_text(),
+ (backend->requires_driver_selection() ? (std::string) driver_combo.get_active_text() : string()),
+ device_combo.get_active_text());
+ }
+
+
+ return get_matching_state (backend_combo.get_active_text(),
+ string(),
+ device_combo.get_active_text());
+ }
+
+ EngineControl::State*
+ EngineControl::save_state ()
+ {
+ if (!_have_control) {
+ return 0;
+ }
+
+ bool existing = true;
+ State* state = get_saved_state_for_currently_displayed_backend_and_device ();
+
+ if (!state) {
+ existing = false;
+ state = new State;
+ }
+
+ store_state (*state);
+
+ if (!existing) {
+ states.push_back (*state);
+ }
+
+ return state;
+ }
+
+ void
+ EngineControl::store_state (State& state)
+ {
+ state.backend = get_backend ();
+ state.driver = get_driver ();
+ state.device = get_device_name ();
+ state.sample_rate = get_rate ();
+ state.buffer_size = get_buffer_size ();
+ state.input_latency = get_input_latency ();
+ state.output_latency = get_output_latency ();
+ state.input_channels = get_input_channels ();
+ state.output_channels = get_output_channels ();
+ state.midi_option = get_midi_option ();
+ }
+
+ void
+ EngineControl::maybe_display_saved_state ()
+ {
+ if (!_have_control) {
+ return;
+ }
+
+ State* state = get_saved_state_for_currently_displayed_backend_and_device ();
+
+ if (state) {
+ PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
+
+ if (!_desired_sample_rate) {
+ sample_rate_combo.set_active_text (rate_as_string (state->sample_rate));
+ }
+ buffer_size_combo.set_active_text (bufsize_as_string (state->buffer_size));
+ /* call this explicitly because we're ignoring changes to
+ the controls at this point.
+ */
+ show_buffer_duration ();
+ input_latency.set_value (state->input_latency);
+ output_latency.set_value (state->output_latency);
+
+ if (!state->midi_option.empty()) {
+ midi_option_combo.set_active_text (state->midi_option);
+ }
+ }
+ }
- if (page_num == 1) {
- /* MIDI tab */
- refresh_midi_display ();
- }
+ XMLNode&
+ EngineControl::get_state ()
+ {
+ XMLNode* root = new XMLNode ("AudioMIDISetup");
+ std::string path;
+
+ if (!states.empty()) {
+ XMLNode* state_nodes = new XMLNode ("EngineStates");
+
+ for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) {
+
+ XMLNode* node = new XMLNode ("State");
+
+ node->add_property ("backend", (*i).backend);
+ node->add_property ("driver", (*i).driver);
+ node->add_property ("device", (*i).device);
+ node->add_property ("sample-rate", (*i).sample_rate);
+ node->add_property ("buffer-size", (*i).buffer_size);
+ node->add_property ("input-latency", (*i).input_latency);
+ node->add_property ("output-latency", (*i).output_latency);
+ node->add_property ("input-channels", (*i).input_channels);
+ node->add_property ("output-channels", (*i).output_channels);
+ node->add_property ("active", (*i).active ? "yes" : "no");
+ node->add_property ("midi-option", (*i).midi_option);
+
+ state_nodes->add_child_nocopy (*node);
+ }
+
+ root->add_child_nocopy (*state_nodes);
+ }
+
+ return *root;
+ }
+
+ void
+ EngineControl::set_state (const XMLNode& root)
+ {
+ XMLNodeList clist, cclist;
+ XMLNodeConstIterator citer, cciter;
+ XMLNode* child;
+ XMLNode* grandchild;
+ XMLProperty* prop = NULL;
+
+ if (root.name() != "AudioMIDISetup") {
+ return;
+ }
+
+ clist = root.children();
+
+ states.clear ();
+
+ for (citer = clist.begin(); citer != clist.end(); ++citer) {
+
+ child = *citer;
+
+ if (child->name() != "EngineStates") {
+ continue;
+ }
+
+ cclist = child->children();
+
+ for (cciter = cclist.begin(); cciter != cclist.end(); ++cciter) {
+ State state;
+
+ grandchild = *cciter;
+
+ if (grandchild->name() != "State") {
+ continue;
+ }
+
+ if ((prop = grandchild->property ("backend")) == 0) {
+ continue;
+ }
+ state.backend = prop->value ();
+
+ if ((prop = grandchild->property ("driver")) == 0) {
+ continue;
+ }
+ state.driver = prop->value ();
+
+ if ((prop = grandchild->property ("device")) == 0) {
+ continue;
+ }
+ state.device = prop->value ();
+
+ if ((prop = grandchild->property ("sample-rate")) == 0) {
+ continue;
+ }
+ state.sample_rate = atof (prop->value ());
+
+ if ((prop = grandchild->property ("buffer-size")) == 0) {
+ continue;
+ }
+ state.buffer_size = atoi (prop->value ());
+
+ if ((prop = grandchild->property ("input-latency")) == 0) {
+ continue;
+ }
+ state.input_latency = atoi (prop->value ());
+
+ if ((prop = grandchild->property ("output-latency")) == 0) {
+ continue;
+ }
+ state.output_latency = atoi (prop->value ());
+
+ if ((prop = grandchild->property ("input-channels")) == 0) {
+ continue;
+ }
+ state.input_channels = atoi (prop->value ());
+
+ if ((prop = grandchild->property ("output-channels")) == 0) {
+ continue;
+ }
+ state.output_channels = atoi (prop->value ());
+
+ if ((prop = grandchild->property ("active")) == 0) {
+ continue;
+ }
+ state.active = string_is_affirmative (prop->value ());
+
+ if ((prop = grandchild->property ("midi-option")) == 0) {
+ continue;
+ }
+ state.midi_option = prop->value ();
- if (page_num == 2) {
- /* latency tab */
+ states.push_back (state);
+ }
+ }
+
+ /* 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);
+ driver_combo.set_active_text ((*i).driver);
+ device_combo.set_active_text ((*i).device);
+ sample_rate_combo.set_active_text (rate_as_string ((*i).sample_rate));
+ buffer_size_combo.set_active_text (bufsize_as_string ((*i).buffer_size));
+ input_latency.set_value ((*i).input_latency);
+ output_latency.set_value ((*i).output_latency);
+ midi_option_combo.set_active_text ((*i).midi_option);
+ ignore_changes--;
+ break;
+ }
+ }
+ }
+
+
+ int
+ EngineControl::push_state_to_backend (bool start)
+ {
+ if (no_push) {
+ return 0;
+ }
+
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+
+ if (!backend) {
+ return 0;
+ }
+
+ /* figure out what is going to change */
+
+ bool restart_required = false;
+ bool was_running = ARDOUR::AudioEngine::instance()->running();
+ bool change_driver = false;
+ bool change_device = false;
+ bool change_rate = false;
+ bool change_bufsize = false;
+ bool change_latency = false;
+ bool change_channels = false;
+ bool change_midi = false;
+
+ uint32_t ochan = get_output_channels ();
+ uint32_t ichan = get_input_channels ();
+
+ if (_have_control) {
+
+ 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;
+ }
+
+ if (get_midi_option() != backend->midi_option()) {
+ change_midi = 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;
+ }
+ } else {
+ /* backend never started, so we have to force a group
+ of settings.
+ */
+ change_driver = true;
+ change_device = true;
+ change_rate = true;
+ change_bufsize = true;
+ change_channels = true;
+ change_latency = true;
+ change_midi = true;
+ }
+
+ } else {
+
+ /* we have no control over the backend, meaning that we can
+ * only possibly change sample rate and buffer size.
+ */
+
+
+ if (get_rate() != backend->sample_rate()) {
+ change_bufsize = true;
+ }
+
+ if (get_buffer_size() != backend->buffer_size()) {
+ change_bufsize = true;
+ }
+ }
+
+ if (!_have_control) {
+
+ /* We do not have control over the backend, so the best we can
+ * do is try to change the sample rate and/or bufsize and get
+ * out of here.
+ */
+
+ if (change_rate && !backend->can_change_sample_rate_when_running()) {
+ return 1;
+ }
+
+ if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
+ return 1;
+ }
+
+ if (change_rate) {
+ backend->set_sample_rate (get_rate());
+ }
+
+ if (change_bufsize) {
+ backend->set_buffer_size (get_buffer_size());
+ }
+
+ post_push ();
+
+ return 0;
+ }
+
+ /* determine if we need to stop the backend before changing parameters */
+
+ if (change_driver || change_device || change_channels || change_latency ||
+ (change_rate && !backend->can_change_sample_rate_when_running()) ||
+ change_midi ||
+ (change_bufsize && !backend->can_change_buffer_size_when_running())) {
+ restart_required = true;
+ } else {
+ restart_required = false;
+ }
+
+ if (was_running) {
+
+ if (!change_driver && !change_device && !change_channels && !change_latency && !change_midi) {
+ /* no changes in any parameters that absolutely require a
+ * restart, so check those that might be changeable without a
+ * restart
+ */
+
+ if (change_rate && !backend->can_change_sample_rate_when_running()) {
+ /* can't do this while running ... */
+ restart_required = true;
+ }
+
+ if (change_bufsize && !backend->can_change_buffer_size_when_running()) {
+ /* can't do this while running ... */
+ restart_required = true;
+ }
+ }
+ }
+
+ if (was_running) {
+ if (restart_required) {
+ if (ARDOUR_UI::instance()->disconnect_from_engine ()) {
+ return -1;
+ }
+ }
+ }
+
+
+ if (change_driver && backend->set_driver (get_driver())) {
+ error << string_compose (_("Cannot set driver to %1"), get_driver()) << endmsg;
+ return -1;
+ }
+ if (change_device && backend->set_device_name (get_device_name())) {
+ error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg;
+ return -1;
+ }
+ if (change_rate && backend->set_sample_rate (get_rate())) {
+ error << string_compose (_("Cannot set sample rate to %1"), get_rate()) << endmsg;
+ return -1;
+ }
+ if (change_bufsize && backend->set_buffer_size (get_buffer_size())) {
+ error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg;
+ return -1;
+ }
+
+ if (change_channels || get_input_channels() == 0 || get_output_channels() == 0) {
+ if (backend->set_input_channels (get_input_channels())) {
+ error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg;
+ return -1;
+ }
+ if (backend->set_output_channels (get_output_channels())) {
+ error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg;
+ return -1;
+ }
+ }
+ if (change_latency) {
+ if (backend->set_systemic_input_latency (get_input_latency())) {
+ error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg;
+ return -1;
+ }
+ if (backend->set_systemic_output_latency (get_output_latency())) {
+ error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg;
+ return -1;
+ }
+ }
+
+ if (change_midi) {
+ backend->set_midi_option (get_midi_option());
+ }
+
+ if (start || (was_running && restart_required)) {
+ if (ARDOUR_UI::instance()->reconnect_to_engine()) {
+ return -1;
+ }
+ }
+
+ post_push ();
+
+ return 0;
+ }
+
+ void
+ EngineControl::post_push ()
+ {
+ /* get a pointer to the current state object, creating one if
+ * necessary
+ */
+
+ 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 ();
+ }
+
+ /* schedule a redisplay of MIDI ports */
+
+ Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &EngineControl::refresh_midi_display), false), 1000);
+ }
+
+
+ float
+ EngineControl::get_rate () const
+ {
+ float r = atof (sample_rate_combo.get_active_text ());
+ /* the string may have been translated with an abbreviation for
+ * thousands, so use a crude heuristic to fix this.
+ */
+ if (r < 1000.0) {
+ r *= 1000.0;
+ }
+ return r;
+ }
+
+
+ uint32_t
+ EngineControl::get_buffer_size () const
+ {
+ string txt = buffer_size_combo.get_active_text ();
+ uint32_t samples;
+
+ if (sscanf (txt.c_str(), "%d", &samples) != 1) {
+ throw exception ();
+ }
+
+ return samples;
+ }
+
+ string
+ EngineControl::get_midi_option () const
+ {
+ return midi_option_combo.get_active_text();
+ }
+
+ uint32_t
+ EngineControl::get_input_channels() const
+ {
+ return (uint32_t) input_channels_adjustment.get_value();
+ }
+
+ uint32_t
+ EngineControl::get_output_channels() const
+ {
+ return (uint32_t) output_channels_adjustment.get_value();
+ }
+
+ uint32_t
+ EngineControl::get_input_latency() const
+ {
+ return (uint32_t) input_latency_adjustment.get_value();
+ }
+
+ uint32_t
+ EngineControl::get_output_latency() const
+ {
+ return (uint32_t) output_latency_adjustment.get_value();
+ }
+
+ string
+ EngineControl::get_backend () const
+ {
+ return backend_combo.get_active_text ();
+ }
+
+ string
+ EngineControl::get_driver () const
+ {
+ return driver_combo.get_active_text ();
+ }
+
+ string
+ EngineControl::get_device_name () const
+ {
+ return device_combo.get_active_text ();
+ }
+
+ void
+ EngineControl::control_app_button_clicked ()
+ {
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+
+ if (!backend) {
+ return;
+ }
+
+ backend->launch_control_app ();
+ }
+
+ void
+ EngineControl::manage_control_app_sensitivity ()
+ {
+ boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
+
+ if (!backend) {
+ return;
+ }
+
+ string appname = backend->control_app_name();
+
+ if (appname.empty()) {
+ control_app_button.set_sensitive (false);
+ } else {
+ control_app_button.set_sensitive (true);
+ }
+ }
+
+ void
+ EngineControl::set_desired_sample_rate (uint32_t sr)
+ {
+ _desired_sample_rate = sr;
+ device_changed ();
+ }
+
+ void
+ EngineControl::on_switch_page (GtkNotebookPage*, guint page_num)
+ {
+ if (page_num == 0) {
+ cancel_button->set_sensitive (true);
+ ok_button->set_sensitive (true);
+ apply_button->set_sensitive (true);
+ } else {
+ cancel_button->set_sensitive (false);
+ ok_button->set_sensitive (false);
+ apply_button->set_sensitive (false);
+ }
+
+ if (page_num == midi_tab) {
+ /* MIDI tab */
+ refresh_midi_display ();
+ }
+
+ if (page_num == latency_tab) {
+ /* latency tab */
+
+ if (!ARDOUR::AudioEngine::instance()->running()) {
+
+ PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
+
+ /* save any existing latency values */
+
+ uint32_t il = (uint32_t) input_latency.get_value ();
+ uint32_t ol = (uint32_t) input_latency.get_value ();
+
+ /* reset to zero so that our new test instance of JACK
+ will be clean of any existing latency measures.
+ */
- if (!ARDOUR::AudioEngine::instance()->running()) {
-
- PBD::Unwinder<uint32_t> protect_ignore_changes (ignore_changes, ignore_changes + 1);
-
- /* save any existing latency values */
-
- uint32_t il = (uint32_t) input_latency.get_value ();
- uint32_t ol = (uint32_t) input_latency.get_value ();
+ input_latency.set_value (0);
+ output_latency.set_value (0);
- /* reset to zero so that our new test instance of JACK
- will be clean of any existing latency measures.
- */
-
- input_latency.set_value (0);
- output_latency.set_value (0);
-
- /* reset control */
+ /* reset control */
- input_latency.set_value (il);
- output_latency.set_value (ol);
+ input_latency.set_value (il);
+ output_latency.set_value (ol);
- }
+ }
- if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
- disable_latency_tab ();
- }
+ if (ARDOUR::AudioEngine::instance()->prepare_for_latency_measurement()) {
+ disable_latency_tab ();
+ }
- enable_latency_tab ();
+ enable_latency_tab ();
- } else {
- ARDOUR::AudioEngine::instance()->stop_latency_detection();
- }
-}
+ } else {
+ ARDOUR::AudioEngine::instance()->stop_latency_detection();
+ }
+ }
-/* latency measurement */
+ /* latency measurement */
-bool
-EngineControl::check_latency_measurement ()
-{
- MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
+ bool
+ EngineControl::check_latency_measurement ()
+ {
+ MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
- if (mtdm->resolve () < 0) {
- lm_results.set_markup (string_compose ("<span foreground=\"red\">%1</span>", _("No signal detected ")));
- return true;
- }
+ if (mtdm->resolve () < 0) {
+ lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
+ return true;
+ }
- if (mtdm->err () > 0.3) {
- mtdm->invert ();
- mtdm->resolve ();
- }
+ if (mtdm->err () > 0.3) {
+ mtdm->invert ();
+ mtdm->resolve ();
+ }
- char buf[128];
- ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
+ char buf[128];
+ ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
- if (sample_rate == 0) {
- lm_results.set_text (_("Disconnected from audio engine"));
- ARDOUR::AudioEngine::instance()->stop_latency_detection ();
- return false;
- }
+ if (sample_rate == 0) {
+ lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
+ ARDOUR::AudioEngine::instance()->stop_latency_detection ();
+ return false;
+ }
- uint32_t frames_total = mtdm->del();
- uint32_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
+ uint32_t frames_total = mtdm->del();
+ uint32_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
- snprintf (buf, sizeof (buf), "%u samples %10.3lf ms", extra, extra * 1000.0f/sample_rate);
+ snprintf (buf, sizeof (buf), "%u samples / %.3lf ms", extra, extra * 1000.0f/sample_rate);
- bool solid = true;
+ bool solid = true;
- if (mtdm->err () > 0.2) {
- strcat (buf, " ??");
- solid = false;
- }
+ if (mtdm->err () > 0.2) {
+ strcat (buf, " ");
+ strcat (buf, _("(signal detection error)"));
+ solid = false;
+ }
- if (mtdm->inv ()) {
- strcat (buf, " (Inv)");
- solid = false;
- }
+ if (mtdm->inv ()) {
+ strcat (buf, " ");
+ strcat (buf, _("(inverted - bad wiring)"));
+ solid = false;
+ }
- if (solid) {
- lm_measure_button.set_active (false);
- lm_use_button.set_sensitive (true);
- strcat (buf, " (set)");
- have_lm_results = true;
+ if (solid) {
+ end_latency_detection ();
+ lm_use_button.set_sensitive (true);
+ have_lm_results = true;
}
- lm_results.set_text (buf);
+ lm_results.set_markup (string_compose (results_markup, string_compose (_("Detected roundtrip latency: %1"), buf)));
return true;
}
@@ -1582,32 +1682,39 @@ EngineControl::start_latency_detection ()
{
ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text());
ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text());
- ARDOUR::AudioEngine::instance()->start_latency_detection ();
- lm_results.set_text (_("Detecting ..."));
- latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_latency_measurement), 250);
- lm_start_stop_label.set_text (_("Cancel measurement"));
- have_lm_results = false;
- lm_input_channel_combo.set_sensitive (false);
- lm_output_channel_combo.set_sensitive (false);
+
+ if (ARDOUR::AudioEngine::instance()->start_latency_detection () == 0) {
+ lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
+ latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_latency_measurement), 100);
+ lm_measure_button.set_label (_("Cancel"));
+ have_lm_results = false;
+ lm_use_button.set_sensitive (false);
+ lm_input_channel_combo.set_sensitive (false);
+ lm_output_channel_combo.set_sensitive (false);
+ lm_running = true;
+ }
}
void
EngineControl::end_latency_detection ()
{
- ARDOUR::AudioEngine::instance()->stop_latency_detection ();
latency_timeout.disconnect ();
- lm_start_stop_label.set_text (_("Measure latency"));
+ ARDOUR::AudioEngine::instance()->stop_latency_detection ();
+ lm_measure_button.set_label (_("Measure"));
if (!have_lm_results) {
- lm_results.set_markup ("<i>No measurement results yet</i>");
+ lm_results.set_markup (string_compose (results_markup, _("No measurement results yet")));
+ } else {
+ lm_use_button.set_sensitive (false);
}
lm_input_channel_combo.set_sensitive (true);
lm_output_channel_combo.set_sensitive (true);
+ lm_running = false;
}
void
-EngineControl::latency_button_toggled ()
+EngineControl::latency_button_clicked ()
{
- if (lm_measure_button.get_active ()) {
+ if (!lm_running) {
start_latency_detection ();
} else {
end_latency_detection ();
@@ -1629,6 +1736,10 @@ EngineControl::use_latency_button_clicked ()
input_latency_adjustment.set_value (one_way);
output_latency_adjustment.set_value (one_way);
+
+ /* back to settings page */
+
+ notebook.set_current_page (0);
}
bool
diff --git a/gtk2_ardour/engine_dialog.h b/gtk2_ardour/engine_dialog.h
index ac17814a5f..0bf1c3a507 100644
--- a/gtk2_ardour/engine_dialog.h
+++ b/gtk2_ardour/engine_dialog.h
@@ -36,6 +36,7 @@
#include "pbd/signals.h"
#include "ardour_dialog.h"
+#include "ardour_button.h"
class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
public:
@@ -62,6 +63,7 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
Gtk::ComboBoxText driver_combo;
Gtk::ComboBoxText device_combo;
Gtk::ComboBoxText sample_rate_combo;
+ Gtk::ComboBoxText midi_option_combo;
Gtk::ComboBoxText buffer_size_combo;
Gtk::Label buffer_size_duration_label;
Gtk::Adjustment input_latency_adjustment;
@@ -84,14 +86,16 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
Gtk::ComboBoxText lm_output_channel_combo;
Gtk::ComboBoxText lm_input_channel_combo;
- Gtk::Label lm_start_stop_label;
- Gtk::ToggleButton lm_measure_button;
+ Gtk::Button lm_measure_button;
Gtk::Button lm_use_button;
+ Gtk::Button lm_back_button;
+ ArdourButton lm_button;
Gtk::Label lm_title;
Gtk::Label lm_results;
Gtk::Table lm_table;
Gtk::VBox lm_vbox;
bool have_lm_results;
+ bool lm_running;
Gtk::Button* cancel_button;
Gtk::Button* ok_button;
@@ -117,6 +121,7 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
void sample_rate_changed ();
void buffer_size_changed ();
void parameter_changed ();
+ void midi_option_changed ();
void setup_midi_tab_for_backend ();
void setup_midi_tab_for_jack ();
@@ -133,6 +138,7 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
std::string get_device_name() const;
std::string get_driver() const;
std::string get_backend() const;
+ std::string get_midi_option () const;
void device_changed ();
void list_devices ();
@@ -149,6 +155,7 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
uint32_t input_channels;
uint32_t output_channels;
bool active;
+ std::string midi_option;
State()
: input_latency (0)
@@ -188,7 +195,7 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
void update_sensitivity ();
/* latency measurement */
- void latency_button_toggled ();
+ void latency_button_clicked ();
bool check_latency_measurement ();
sigc::connection latency_timeout;
void enable_latency_tab ();
diff --git a/gtk2_ardour/export_video_dialog.cc b/gtk2_ardour/export_video_dialog.cc
index 7e84cab122..a9d0f99ad1 100644
--- a/gtk2_ardour/export_video_dialog.cc
+++ b/gtk2_ardour/export_video_dialog.cc
@@ -63,7 +63,7 @@ using namespace PBD;
using namespace ARDOUR;
using namespace VideoUtils;
-ExportVideoDialog::ExportVideoDialog (Session* s, TimeSelection &tme)
+ExportVideoDialog::ExportVideoDialog (Session* s, TimeSelection &tme, bool range)
: ArdourDialog (_("Export Video File "))
, export_range (tme)
, outfn_path_label (_("File:"), Gtk::ALIGN_LEFT)
@@ -154,7 +154,11 @@ ExportVideoDialog::ExportVideoDialog (Session* s, TimeSelection &tme)
if (!export_range.empty()) {
insnd_combo.append_text (_("Selected range")); // TODO show export_range.start() -> export_range.end_frame()
}
- insnd_combo.set_active(0);
+ if (range) {
+ insnd_combo.set_active(2);
+ } else {
+ insnd_combo.set_active(0);
+ }
outfn_path_entry.set_width_chars(38);
outfn_path_entry.set_text (_session->session_directory().export_path() + G_DIR_SEPARATOR +"export.avi");
@@ -512,9 +516,8 @@ ExportVideoDialog::launch_export ()
end += av_offset;
}
else if (insnd_combo.get_active_row_number() == 2) {
- // TODO quantize to video-frame ?!
- start = export_range.start();
- end = export_range.end_frame();
+ start = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv(export_range.start());
+ end = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv(export_range.end_frame());
}
if (end <= 0) {
start = _session->current_start_frame();
@@ -524,6 +527,15 @@ ExportVideoDialog::launch_export ()
printf("audio export-range %lld -> %lld\n", start, end);
#endif
+ const frameoffset_t vstart = ARDOUR_UI::instance()->video_timeline->get_offset();
+ const frameoffset_t vend = vstart + ARDOUR_UI::instance()->video_timeline->get_duration();
+
+ if ( (start >= end) || (end < vstart) || (start > vend)) {
+ warning << _("Export Video: export-range does not include video.") << endmsg;
+ Gtk::Dialog::response(RESPONSE_CANCEL);
+ return;
+ }
+
tsp->set_range (start, end);
tsp->set_name ("mysession");
tsp->set_range_id ("session");
diff --git a/gtk2_ardour/export_video_dialog.h b/gtk2_ardour/export_video_dialog.h
index 7e3cf442a7..5ebcf3258d 100644
--- a/gtk2_ardour/export_video_dialog.h
+++ b/gtk2_ardour/export_video_dialog.h
@@ -41,7 +41,7 @@
class ExportVideoDialog : public ArdourDialog , public PBD::ScopedConnectionList
{
public:
- ExportVideoDialog (ARDOUR::Session*, TimeSelection &tme);
+ ExportVideoDialog (ARDOUR::Session*, TimeSelection &tme, bool range = false);
~ExportVideoDialog ();
std::string get_exported_filename () { return outfn_path_entry.get_text(); }
diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc
index 28ef9b1297..4423e3905d 100644
--- a/gtk2_ardour/plugin_ui.cc
+++ b/gtk2_ardour/plugin_ui.cc
@@ -159,6 +159,7 @@ PluginUIWindow::PluginUIWindow (
PluginUIWindow::~PluginUIWindow ()
{
+ cerr << "PluginWindow deleted for " << this << endl;
delete _pluginui;
}
@@ -403,8 +404,6 @@ PluginUIWindow::plugin_going_away ()
}
death_connection.disconnect ();
-
- delete_when_idle (this);
}
PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi)
diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc
index 1ed7c39312..1749e4dd66 100644
--- a/gtk2_ardour/processor_box.cc
+++ b/gtk2_ardour/processor_box.cc
@@ -1392,7 +1392,7 @@ ProcessorBox::redisplay_processors ()
_route->foreach_processor (sigc::mem_fun (*this, &ProcessorBox::add_processor_to_display));
- for (list<ProcessorWindowProxy*>::iterator i = _processor_window_info.begin(); i != _processor_window_info.end(); ++i) {
+ for (ProcessorWindowProxies::iterator i = _processor_window_info.begin(); i != _processor_window_info.end(); ++i) {
(*i)->marked = false;
}
@@ -1400,16 +1400,43 @@ ProcessorBox::redisplay_processors ()
/* trim dead wood from the processor window proxy list */
- list<ProcessorWindowProxy*>::iterator i = _processor_window_info.begin();
+ ProcessorWindowProxies::iterator i = _processor_window_info.begin();
while (i != _processor_window_info.end()) {
- list<ProcessorWindowProxy*>::iterator j = i;
+ ProcessorWindowProxies::iterator j = i;
++j;
- if (!(*i)->marked) {
+ if (!(*i)->valid()) {
+
WM::Manager::instance().remove (*i);
delete *i;
_processor_window_info.erase (i);
- }
+
+ } else if (!(*i)->marked) {
+
+ /* this processor is no longer part of this processor
+ * box.
+ *
+ * that could be because it was deleted or it could be
+ * because the route being displayed in the parent
+ * strip changed.
+ *
+ * The latter only happens with the editor mixer strip.
+ */
+
+ if (is_editor_mixer_strip()) {
+
+ /* editor mixer strip .. DO NOTHING
+ *
+ * note: the processor window stays visible if
+ * it is already visible
+ */
+ } else {
+ (*i)->hide ();
+ WM::Manager::instance().remove (*i);
+ delete *i;
+ _processor_window_info.erase (i);
+ }
+ }
i = j;
}
@@ -1428,7 +1455,7 @@ ProcessorBox::maybe_add_processor_to_ui_list (boost::weak_ptr<Processor> w)
return;
}
- list<ProcessorWindowProxy*>::iterator i = _processor_window_info.begin ();
+ ProcessorWindowProxies::iterator i = _processor_window_info.begin ();
while (i != _processor_window_info.end()) {
boost::shared_ptr<Processor> t = (*i)->processor().lock ();
@@ -2077,6 +2104,18 @@ ProcessorBox::get_editor_window (boost::shared_ptr<Processor> processor, bool us
boost::shared_ptr<PortInsert> port_insert;
Window* gidget = 0;
+ /* This method may or may not return a Window, but if it does not it
+ * will modify the parent mixer strip appearance layout to allow
+ * "editing" the @param processor that was passed in.
+ *
+ * So for example, if the processor is an Amp (gain), the parent strip
+ * will be forced back into a model where the fader controls the main gain.
+ * If the processor is a send, then we map the send controls onto the
+ * strip.
+ *
+ * Plugins and others will return a window for control.
+ */
+
if (boost::dynamic_pointer_cast<AudioTrack>(_route) != 0) {
if (boost::dynamic_pointer_cast<AudioTrack> (_route)->freeze_state() == AudioTrack::Frozen) {
@@ -2554,7 +2593,13 @@ ProcessorBox::generate_processor_title (boost::shared_ptr<PluginInsert> pi)
maker += " ...";
}
- return string_compose(_("%1: %2 (by %3)"), _route->name(), pi->name(), maker);
+ SessionObject* owner = pi->owner();
+
+ if (owner) {
+ return string_compose(_("%1: %2 (by %3)"), owner->name(), pi->name(), maker);
+ } else {
+ return string_compose(_("%2 (by %3)"), pi->name(), maker);
+ }
}
/** @param p Processor.
@@ -2667,6 +2712,12 @@ ProcessorBox::update_gui_object_state (ProcessorEntry* entry)
entry->add_control_state (proc);
}
+bool
+ProcessorBox::is_editor_mixer_strip() const
+{
+ return _parent_strip && !_parent_strip->mixer_owned();
+}
+
ProcessorWindowProxy::ProcessorWindowProxy (string const & name, ProcessorBox* box, boost::weak_ptr<Processor> processor)
: WM::ProxyBase (name, string())
, marked (false)
@@ -2674,8 +2725,34 @@ ProcessorWindowProxy::ProcessorWindowProxy (string const & name, ProcessorBox* b
, _processor (processor)
, is_custom (false)
, want_custom (false)
+ , _valid (true)
{
+ boost::shared_ptr<Processor> p = _processor.lock ();
+ if (!p) {
+ return;
+ }
+ p->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&ProcessorWindowProxy::processor_going_away, this), gui_context());
+}
+
+ProcessorWindowProxy::~ProcessorWindowProxy()
+{
+ /* processor window proxies do not own the windows they create with
+ * ::get(), so set _window to null before the normal WindowProxy method
+ * deletes it.
+ */
+ _window = 0;
+}
+void
+ProcessorWindowProxy::processor_going_away ()
+{
+ delete _window;
+ _window = 0;
+ _valid = false;
+ /* should be no real reason to do this, since the object that would
+ send DropReferences is about to be deleted, but lets do it anyway.
+ */
+ going_away_connection.disconnect();
}
ARDOUR::SessionHandlePtr*
@@ -2685,6 +2762,12 @@ ProcessorWindowProxy::session_handle()
return 0;
}
+bool
+ProcessorWindowProxy::valid() const
+{
+ return _valid;
+}
+
XMLNode&
ProcessorWindowProxy::get_state () const
{
diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h
index a72eb3223d..41bc68281f 100644
--- a/gtk2_ardour/processor_box.h
+++ b/gtk2_ardour/processor_box.h
@@ -79,6 +79,7 @@ class ProcessorWindowProxy : public WM::ProxyBase
{
public:
ProcessorWindowProxy (std::string const &, ProcessorBox *, boost::weak_ptr<ARDOUR::Processor>);
+ ~ProcessorWindowProxy();
Gtk::Window* get (bool create = false);
@@ -91,6 +92,7 @@ class ProcessorWindowProxy : public WM::ProxyBase
void set_custom_ui_mode(bool use_custom) { want_custom = use_custom; }
bool marked;
+ bool valid () const;
void set_state (const XMLNode&);
XMLNode& get_state () const;
@@ -100,6 +102,10 @@ class ProcessorWindowProxy : public WM::ProxyBase
boost::weak_ptr<ARDOUR::Processor> _processor;
bool is_custom;
bool want_custom;
+ bool _valid;
+
+ void processor_going_away ();
+ PBD::ScopedConnection going_away_connection;
};
class ProcessorEntry : public Gtkmm2ext::DnDVBoxChild, public sigc::trackable
@@ -303,6 +309,8 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
void route_going_away ();
+ bool is_editor_mixer_strip() const;
+
Gtkmm2ext::DnDVBox<ProcessorEntry> processor_display;
Gtk::ScrolledWindow processor_scroller;
@@ -404,7 +412,9 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
void route_property_changed (const PBD::PropertyChange&);
std::string generate_processor_title (boost::shared_ptr<ARDOUR::PluginInsert> pi);
- std::list<ProcessorWindowProxy*> _processor_window_info;
+ typedef std::list<ProcessorWindowProxy*> ProcessorWindowProxies;
+ ProcessorWindowProxies _processor_window_info;
+
ProcessorWindowProxy* find_window_proxy (boost::shared_ptr<ARDOUR::Processor>) const;
void set_processor_ui (boost::shared_ptr<ARDOUR::Processor>, Gtk::Window *);
diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h
index 3fc2b878b0..a99dcdd253 100644
--- a/gtk2_ardour/public_editor.h
+++ b/gtk2_ardour/public_editor.h
@@ -296,7 +296,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi
virtual int get_videotl_bar_height () const = 0;
virtual void set_video_timeline_height (const int h) = 0;
virtual void embed_audio_from_video (std::string, framepos_t n = 0) = 0;
- virtual void export_video () = 0;
+ virtual void export_video (bool range = false) = 0;
virtual RouteTimeAxisView* get_route_view_by_route_id (const PBD::ID& id) const = 0;
diff --git a/gtk2_ardour/window_manager.cc b/gtk2_ardour/window_manager.cc
index 4a44dc4691..01baf3e1fd 100644
--- a/gtk2_ardour/window_manager.cc
+++ b/gtk2_ardour/window_manager.cc
@@ -349,7 +349,7 @@ ProxyBase::setup ()
assert (_window);
vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
- _window->signal_delete_event().connect (sigc::mem_fun (*this, &ProxyBase::handle_win_event));
+ _window->signal_delete_event().connect (sigc::mem_fun (*this, &ProxyBase::delete_event_handler));
if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
/* cancel any mouse-based positioning */
@@ -369,8 +369,9 @@ ProxyBase::setup ()
void
ProxyBase::show ()
{
- Gtk::Window* win = get (true);
- win->show ();
+ get (true);
+ assert (_window);
+ _window->show ();
}
void
@@ -384,17 +385,19 @@ ProxyBase::maybe_show ()
void
ProxyBase::show_all ()
{
- Gtk::Window* win = get (true);
- win->show_all ();
+ get (true);
+ assert (_window);
+ _window->show_all ();
}
-
void
ProxyBase::present ()
{
- Gtk::Window* win = get (true);
- win->show_all ();
- win->present ();
+ get (true);
+ assert (_window);
+
+ _window->show_all ();
+ _window->present ();
/* turn off any mouse-based positioning */
_window->set_position (Gtk::WIN_POS_NONE);
@@ -403,15 +406,14 @@ ProxyBase::present ()
void
ProxyBase::hide ()
{
- Gtk::Window* win = get (false);
- if (win) {
+ if (_window) {
save_pos_and_size();
- win->hide ();
+ _window->hide ();
}
}
bool
-ProxyBase::handle_win_event (GdkEventAny* /*ev*/)
+ProxyBase::delete_event_handler (GdkEventAny* /*ev*/)
{
hide();
return true;
@@ -420,10 +422,9 @@ ProxyBase::handle_win_event (GdkEventAny* /*ev*/)
void
ProxyBase::save_pos_and_size ()
{
- Gtk::Window* win = get (false);
- if (win) {
- win->get_position (_x_off, _y_off);
- win->get_size (_width, _height);
+ if (_window) {
+ _window->get_position (_x_off, _y_off);
+ _window->get_size (_width, _height);
}
}
/*-----------------------*/
diff --git a/gtk2_ardour/window_manager.h b/gtk2_ardour/window_manager.h
index 135f72c3ee..2dd6a2262e 100644
--- a/gtk2_ardour/window_manager.h
+++ b/gtk2_ardour/window_manager.h
@@ -122,7 +122,7 @@ class ProxyBase : public ARDOUR::SessionHandlePtr, public sigc::trackable {
Gtkmm2ext::VisibilityTracker* vistracker;
void save_pos_and_size ();
- bool handle_win_event (GdkEventAny *ev);
+ bool delete_event_handler (GdkEventAny *ev);
void setup ();
};
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index 8e1a136931..011126da64 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -640,7 +640,7 @@ def build(bld):
# Menus
menus_argv = []
if bld.is_defined('GTKOSX'):
- menus_argv = [ '-E', '-P', '-DGTKOSX', '-DNOVIDEOTIMELINE' ]
+ menus_argv = [ '-E', '-P', '-DGTKOSX' ]
else:
menus_argv = [ '-E', '-P' ]
diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h
index 0e39625e8c..cbe0bfce50 100644
--- a/libs/ardour/ardour/audio_backend.h
+++ b/libs/ardour/ardour/audio_backend.h
@@ -239,7 +239,38 @@ class AudioBackend : public PortEngine {
* app is undefined or cannot be launched.
*/
virtual void launch_control_app () = 0;
- /* Basic state control */
+
+ /* @return a vector of strings that describe the available
+ * MIDI options.
+ *
+ * These can be presented to the user to decide which
+ * MIDI drivers, options etc. can be used. The returned strings
+ * should be thought of as the key to a map of possible
+ * approaches to handling MIDI within the backend. Ensure that
+ * the strings will make sense to the user.
+ */
+ virtual std::vector<std::string> enumerate_midi_options () const = 0;
+
+ /* Request the use of the MIDI option named @param option, which
+ * should be one of the strings returned by enumerate_midi_options()
+ *
+ * @return zero if successful, non-zero otherwise
+ */
+ virtual int set_midi_option (const std::string& option) = 0;
+
+ virtual std::string midi_option () const = 0;
+
+ /* State Control */
+
+ /* non-virtual method to avoid possible overrides of default
+ * parameters. See Scott Meyers or other books on C++ to
+ * understand this pattern, or possibly just this:
+ *
+ * http://stackoverflow.com/questions/12139786/good-pratice-default-arguments-for-pure-virtual-method
+ */
+ int start (bool for_latency_measurement=false) {
+ return _start (for_latency_measurement);
+ }
/** Start using the device named in the most recent call
* to set_device(), with the parameters set by various
@@ -250,9 +281,14 @@ class AudioBackend : public PortEngine {
* the AudioEngine referenced by @param engine. These calls will
* occur in a thread created by and/or under the control of the backend.
*
+ * @param for_latency_measurement if true, the device is being started
+ * to carry out latency measurements and the backend should this
+ * take care to return latency numbers that do not reflect
+ * any existing systemic latency settings.
+ *
* Return zero if successful, negative values otherwise.
*/
- virtual int start () = 0;
+ virtual int _start (bool for_latency_measurement) = 0;
/** Stop using the device currently in use.
*
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index ddffd1d5c0..d5dcbffe2b 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -70,6 +70,7 @@ public:
int discover_backends();
std::vector<const AudioBackendInfo*> available_backends() const;
std::string current_backend_name () const;
+ boost::shared_ptr<AudioBackend> set_default_backend ();
boost::shared_ptr<AudioBackend> set_backend (const std::string&, const std::string& arg1, const std::string& arg2);
boost::shared_ptr<AudioBackend> current_backend() const { return _backend; }
bool setup_required () const;
@@ -82,8 +83,8 @@ public:
* just forward to a backend implementation.
*/
- int start ();
- int stop ();
+ int start (bool for_latency_measurement=false);
+ int stop (bool for_latency_measurement=false);
int pause ();
int freewheel (bool start_stop);
float get_cpu_load() const ;
@@ -193,7 +194,7 @@ public:
MTDM* mtdm();
int prepare_for_latency_measurement ();
- void start_latency_detection ();
+ int start_latency_detection ();
void stop_latency_detection ();
void set_latency_input_port (const std::string&);
void set_latency_output_port (const std::string&);
@@ -228,6 +229,7 @@ public:
std::string _latency_input_name;
std::string _latency_output_name;
framecnt_t _latency_signal_latency;
+ bool _stopped_for_latency;
bool _started_for_latency;
bool _in_destructor;
diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h
index 772ae3520d..18f13dbc78 100644
--- a/libs/ardour/ardour/processor.h
+++ b/libs/ardour/ardour/processor.h
@@ -113,6 +113,9 @@ class Processor : public SessionObject, public Automatable, public Latent
void set_ui (void*);
void* get_ui () const { return _ui_pointer; }
+ void set_owner (SessionObject*);
+ SessionObject* owner() const;
+
protected:
virtual int set_state_2X (const XMLNode&, int version);
@@ -125,6 +128,7 @@ protected:
bool _display_to_user;
bool _pre_fader; ///< true if this processor is currently placed before the Amp, otherwise false
void* _ui_pointer;
+ SessionObject* _owner;
};
} // namespace ARDOUR
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 570fe1bee5..ae40b089db 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -78,7 +78,7 @@ AudioEngine::AudioEngine ()
, _latency_output_port (0)
, _latency_flush_frames (0)
, _latency_signal_latency (0)
- , _started_for_latency (false)
+ , _stopped_for_latency (false)
, _in_destructor (false)
{
g_atomic_int_set (&m_meter_exit, 0);
@@ -565,6 +565,16 @@ AudioEngine::drop_backend ()
}
boost::shared_ptr<AudioBackend>
+AudioEngine::set_default_backend ()
+{
+ if (_backends.empty()) {
+ return boost::shared_ptr<AudioBackend>();
+ }
+
+ return set_backend (_backends.begin()->first, "", "");
+}
+
+boost::shared_ptr<AudioBackend>
AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
{
BackendMap::iterator b = _backends.find (name);
@@ -593,7 +603,7 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons
/* BACKEND PROXY WRAPPERS */
int
-AudioEngine::start ()
+AudioEngine::start (bool for_latency)
{
if (!_backend) {
return -1;
@@ -606,7 +616,7 @@ AudioEngine::start ()
_processed_frames = 0;
last_monitor_check = 0;
- if (_backend->start()) {
+ if (_backend->start (for_latency)) {
return -1;
}
@@ -622,7 +632,7 @@ AudioEngine::start ()
start_metering_thread ();
- if (!_started_for_latency) {
+ if (!for_latency) {
Running(); /* EMIT SIGNAL */
}
@@ -630,7 +640,7 @@ AudioEngine::start ()
}
int
-AudioEngine::stop ()
+AudioEngine::stop (bool for_latency)
{
if (!_backend) {
return 0;
@@ -651,7 +661,10 @@ AudioEngine::stop ()
stop_metering_thread ();
Port::PortDrop ();
- Stopped (); /* EMIT SIGNAL */
+
+ if (!for_latency) {
+ Stopped (); /* EMIT SIGNAL */
+ }
return 0;
}
@@ -1015,7 +1028,10 @@ AudioEngine::halted_callback (const char* why)
_running = false;
Port::PortDrop (); /* EMIT SIGNAL */
- Halted (why); /* EMIT SIGNAL */
+
+ if (!_started_for_latency) {
+ Halted (why); /* EMIT SIGNAL */
+ }
}
bool
@@ -1044,23 +1060,26 @@ AudioEngine::mtdm()
int
AudioEngine::prepare_for_latency_measurement ()
{
- if (!running()) {
- _started_for_latency = true;
+ if (running()) {
+ _stopped_for_latency = true;
+ stop (true);
+ }
- if (start()) {
- _started_for_latency = false;
- return -1;
- }
+ if (start (true)) {
+ _started_for_latency = true;
+ return -1;
}
return 0;
}
-void
+int
AudioEngine::start_latency_detection ()
{
- if (prepare_for_latency_measurement ()) {
- return;
+ if (!running()) {
+ if (prepare_for_latency_measurement ()) {
+ return -1;
+ }
}
PortEngine& pe (port_engine());
@@ -1074,27 +1093,32 @@ AudioEngine::start_latency_detection ()
PortEngine::PortHandle* in = pe.get_port_by_name (_latency_input_name);
if (!out || !in) {
- return;
+ stop (true);
+ return -1;
}
/* create the ports we will use to read/write data */
if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
- return;
+ stop (true);
+ return -1;
}
if (pe.connect (_latency_output_port, _latency_output_name)) {
pe.unregister_port (_latency_output_port);
- return;
+ stop (true);
+ return -1;
}
const string portname ("latency_in");
if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
pe.unregister_port (_latency_output_port);
- return;
+ stop (true);
+ return -1;
}
if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
pe.unregister_port (_latency_output_port);
- return;
+ stop (true);
+ return -1;
}
LatencyRange lr;
@@ -1110,6 +1134,7 @@ AudioEngine::start_latency_detection ()
_measuring_latency = true;
_latency_flush_frames = samples_per_cycle();
+ return 0;
}
void
@@ -1125,9 +1150,15 @@ AudioEngine::stop_latency_detection ()
port_engine().unregister_port (_latency_input_port);
_latency_input_port = 0;
}
- if (_started_for_latency) {
- stop ();
+
+ stop (true);
+
+ if (_stopped_for_latency) {
+ start ();
}
+
+ _stopped_for_latency = false;
+ _started_for_latency = false;
}
void
diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc
index 3f8fdf509d..f9590bee11 100644
--- a/libs/ardour/processor.cc
+++ b/libs/ardour/processor.cc
@@ -269,3 +269,15 @@ Processor::set_ui (void* p)
{
_ui_pointer = p;
}
+
+void
+Processor::set_owner (SessionObject* o)
+{
+ _owner = o;
+}
+
+SessionObject*
+Processor::owner() const
+{
+ return _owner;
+}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 026ee4ec5c..25ee527e2c 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -149,6 +149,7 @@ Route::init ()
*/
_meter.reset (new PeakMeter (_session, _name));
+ _meter->set_owner (this);
_meter->set_display_to_user (false);
_meter->activate ();
@@ -1011,6 +1012,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
}
_processors.insert (loc, processor);
+ processor->set_owner (this);
// Set up processor list channels. This will set processor->[input|output]_streams(),
// configure redirect ports properly, etc.
@@ -1161,6 +1163,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
}
_processors.insert (loc, *i);
+ (*i)->set_owner (this);
if ((*i)->active()) {
(*i)->activate ();
@@ -2620,6 +2623,7 @@ Route::set_processor_state (const XMLNode& node)
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+ (*i)->set_owner (this);
(*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
boost::shared_ptr<PluginInsert> pi;
diff --git a/libs/ardour/run-session-tests.sh b/libs/ardour/run-session-tests.sh
index 63218d8887..034f8b5a7f 100644..100755
--- a/libs/ardour/run-session-tests.sh
+++ b/libs/ardour/run-session-tests.sh
@@ -8,20 +8,7 @@ if [ ! -f './tempo.cc' ]; then
exit 1;
fi
-cd ../..
-top=`pwd`
-cd build
-
-libs='libs'
-
-export LD_LIBRARY_PATH=$libs/audiographer:$libs/vamp-sdk:$libs/surfaces:$libs/surfaces/control_protocol:$libs/ardour:$libs/midi++2:$libs/pbd:$libs/rubberband:$libs/soundtouch:$libs/gtkmm2ext:$libs/appleutility:$libs/taglib:$libs/evoral:$libs/evoral/src/libsmf:$libs/timecode:/usr/local/lib:/usr/local/lib64:$LD_LIBRARY_PATH
-
-export ARDOUR_CONFIG_PATH=$top:$top/gtk2_ardour:$libs/..:$libs/../gtk2_ardour
-export ARDOUR_PANNER_PATH=$libs/panners/2in2out:$libs/panners/1in2out:$libs/panners/vbap
-export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie
-export ARDOUR_MCP_PATH="../mcp"
-export ARDOUR_DLL_PATH=$libs
-export ARDOUR_DATA_PATH=$top/gtk2_ardour:$top/build/gtk2_ardour:.
+. test-env.sh
f=""
if [ "$1" == "--debug" -o "$1" == "--valgrind" ]; then
diff --git a/libs/ardour/run-tests.sh b/libs/ardour/run-tests.sh
index fc7d68a8a5..e894fecb63 100755
--- a/libs/ardour/run-tests.sh
+++ b/libs/ardour/run-tests.sh
@@ -2,6 +2,7 @@
#
# Run libardour test suite.
#
+. test-env.sh
if [ "$1" == "--single" ] || [ "$2" == "--single" ]; then
if [ "$1" == "--single" ]; then
diff --git a/libs/ardour/test-env.sh b/libs/ardour/test-env.sh
index aa2cff9219..561f54d694 100644
--- a/libs/ardour/test-env.sh
+++ b/libs/ardour/test-env.sh
@@ -22,3 +22,4 @@ export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/generic_midi:$libs
export ARDOUR_MCP_PATH="../mcp"
export ARDOUR_DLL_PATH=$libs
export ARDOUR_DATA_PATH=$top/gtk2_ardour:$top/build/gtk2_ardour:.
+export ARDOUR_BACKEND_PATH=$libs/backends/jack
diff --git a/libs/ardour/test/audio_region_read_test.cc b/libs/ardour/test/audio_region_read_test.cc
index dc3127ea2e..6a8e3600f1 100644
--- a/libs/ardour/test/audio_region_read_test.cc
+++ b/libs/ardour/test/audio_region_read_test.cc
@@ -20,7 +20,6 @@
#include "ardour/region.h"
#include "ardour/audioregion.h"
#include "audio_region_read_test.h"
-#include "test_globals.h"
CPPUNIT_TEST_SUITE_REGISTRATION (AudioRegionReadTest);
diff --git a/libs/ardour/test/audio_region_test.cc b/libs/ardour/test/audio_region_test.cc
index df3fa72d10..a25a78a40b 100644
--- a/libs/ardour/test/audio_region_test.cc
+++ b/libs/ardour/test/audio_region_test.cc
@@ -27,7 +27,6 @@
#include "ardour/audioregion.h"
#include "ardour/audioplaylist.h"
#include "audio_region_test.h"
-#include "test_globals.h"
#include "test_common.h"
using namespace std;
@@ -42,7 +41,7 @@ AudioRegionTest::setUp ()
std::string const test_wav_path = Glib::build_filename (new_test_output_dir(), "test.wav");
_playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
_audio_playlist = boost::dynamic_pointer_cast<AudioPlaylist> (_playlist);
- _source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, Fs);
+ _source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, false, get_test_sample_rate ());
/* Write a staircase to the source */
diff --git a/libs/ardour/test/automation_list_property_test.cc b/libs/ardour/test/automation_list_property_test.cc
index 90e2e22989..e5a74cad2f 100644
--- a/libs/ardour/test/automation_list_property_test.cc
+++ b/libs/ardour/test/automation_list_property_test.cc
@@ -16,11 +16,15 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
+
#include "pbd/properties.h"
#include "pbd/stateful_diff_command.h"
#include "ardour/automation_list.h"
#include "automation_list_property_test.h"
#include "test_util.h"
+#include "test_common.h"
CPPUNIT_TEST_SUITE_REGISTRATION (AutomationListPropertyTest);
@@ -29,6 +33,16 @@ using namespace PBD;
using namespace ARDOUR;
void
+write_automation_list_xml (XMLNode* node, std::string filename)
+{
+ // use the same output dir for all of them
+ static std::string test_output_dir = new_test_output_dir ("automation_list_property");
+ std::string output_file = Glib::build_filename (test_output_dir, filename);
+
+ CPPUNIT_ASSERT (write_ref (node, output_file));
+}
+
+void
AutomationListPropertyTest::basicTest ()
{
list<string> ignore_properties;
@@ -52,9 +66,18 @@ AutomationListPropertyTest::basicTest ()
/* Now it has changed */
CPPUNIT_ASSERT_EQUAL (true, property.changed());
+ std::string test_data_filename = "automation_list_property_test1.ref";
+ std::string test_data_file1 = Glib::build_filename (test_search_path().front(), test_data_filename);
+ CPPUNIT_ASSERT (Glib::file_test (test_data_file1, Glib::FILE_TEST_EXISTS));
+
XMLNode* foo = new XMLNode ("test");
property.get_changes_as_xml (foo);
- check_xml (foo, "../libs/ardour/test/data/automation_list_property_test1.ref", ignore_properties);
+ write_automation_list_xml (foo, test_data_filename);
+ check_xml (foo, test_data_file1, ignore_properties);
+
+ test_data_filename = "automation_list_property_test2.ref";
+ std::string test_data_file2 = Glib::build_filename (test_search_path().front(), test_data_filename);
+ CPPUNIT_ASSERT (Glib::file_test (test_data_file2, Glib::FILE_TEST_EXISTS));
/* Do some more */
property.clear_changes ();
@@ -64,7 +87,8 @@ AutomationListPropertyTest::basicTest ()
CPPUNIT_ASSERT_EQUAL (true, property.changed());
foo = new XMLNode ("test");
property.get_changes_as_xml (foo);
- check_xml (foo, "../libs/ardour/test/data/automation_list_property_test2.ref", ignore_properties);
+ write_automation_list_xml (foo, test_data_filename);
+ check_xml (foo, test_data_file2, ignore_properties);
}
/** Here's a StatefulDestructible class that has a AutomationListProperty */
@@ -119,11 +143,21 @@ AutomationListPropertyTest::undoTest ()
sheila->_jim->add (7, 8);
StatefulDiffCommand sdc (sheila);
+ std::string test_data_filename = "automation_list_property_test3.ref";
+ std::string test_data_file3 = Glib::build_filename (test_search_path().front(), test_data_filename);
+ CPPUNIT_ASSERT (Glib::file_test (test_data_file3, Glib::FILE_TEST_EXISTS));
+
/* Undo */
sdc.undo ();
- check_xml (&sheila->get_state(), "../libs/ardour/test/data/automation_list_property_test3.ref", ignore_properties);
+ write_automation_list_xml (&sheila->get_state(), test_data_filename);
+ check_xml (&sheila->get_state(), test_data_file3, ignore_properties);
+
+ test_data_filename = "automation_list_property_test4.ref";
+ std::string test_data_file4 = Glib::build_filename (test_search_path().front(), test_data_filename);
+ CPPUNIT_ASSERT (Glib::file_test (test_data_file4, Glib::FILE_TEST_EXISTS));
/* Redo */
sdc.redo ();
- check_xml (&sheila->get_state(), "../libs/ardour/test/data/automation_list_property_test4.ref", ignore_properties);
+ write_automation_list_xml (&sheila->get_state(), test_data_filename);
+ check_xml (&sheila->get_state(), test_data_file4, ignore_properties);
}
diff --git a/libs/ardour/test/load_session.cc b/libs/ardour/test/load_session.cc
index 3f56e63577..f2a2a6922e 100644
--- a/libs/ardour/test/load_session.cc
+++ b/libs/ardour/test/load_session.cc
@@ -3,7 +3,6 @@
#include "ardour/ardour.h"
#include "ardour/audioengine.h"
#include "ardour/session.h"
-#include "midi++/manager.h"
#include <iostream>
#include <cstdlib>
@@ -41,9 +40,8 @@ int main (int argc, char* argv[])
AudioEngine::instance()->remove_session ();
delete s;
- AudioEngine::instance()->stop (true);
+ AudioEngine::instance()->stop ();
- MIDI::Manager::destroy ();
AudioEngine::destroy ();
return 0;
diff --git a/libs/ardour/test/playlist_read_test.cc b/libs/ardour/test/playlist_read_test.cc
index 54b0bc4fd5..78b2e4eadd 100644
--- a/libs/ardour/test/playlist_read_test.cc
+++ b/libs/ardour/test/playlist_read_test.cc
@@ -22,7 +22,6 @@
#include "ardour/audioregion.h"
#include "ardour/session.h"
#include "playlist_read_test.h"
-#include "test_globals.h"
CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistReadTest);
diff --git a/libs/ardour/test/profiling/load_session.cc b/libs/ardour/test/profiling/load_session.cc
index 3f56e63577..f2a2a6922e 100644
--- a/libs/ardour/test/profiling/load_session.cc
+++ b/libs/ardour/test/profiling/load_session.cc
@@ -3,7 +3,6 @@
#include "ardour/ardour.h"
#include "ardour/audioengine.h"
#include "ardour/session.h"
-#include "midi++/manager.h"
#include <iostream>
#include <cstdlib>
@@ -41,9 +40,8 @@ int main (int argc, char* argv[])
AudioEngine::instance()->remove_session ();
delete s;
- AudioEngine::instance()->stop (true);
+ AudioEngine::instance()->stop ();
- MIDI::Manager::destroy ();
AudioEngine::destroy ();
return 0;
diff --git a/libs/ardour/test/profiling/runpc.cc b/libs/ardour/test/profiling/runpc.cc
index ddbd463234..6538fcf88a 100644
--- a/libs/ardour/test/profiling/runpc.cc
+++ b/libs/ardour/test/profiling/runpc.cc
@@ -1,5 +1,4 @@
#include <iostream>
-#include "midi++/manager.h"
#include "pbd/textreceiver.h"
#include "pbd/compose.h"
#include "pbd/enumwriter.h"
@@ -31,7 +30,7 @@ main (int argc, char* argv[])
cout << "INFO: " << session->get_routes()->size() << " routes.\n";
for (int i = 0; i < 32768; ++i) {
- session->process (session->engine().frames_per_cycle ());
+ session->process (session->engine().samples_per_cycle ());
}
return 0;
diff --git a/libs/ardour/test/session_test.cc b/libs/ardour/test/session_test.cc
index 83273b5a2e..ba57b4bd63 100644
--- a/libs/ardour/test/session_test.cc
+++ b/libs/ardour/test/session_test.cc
@@ -3,7 +3,7 @@
#include <glibmm/miscutils.h>
#include <stdexcept>
-#include "midi++/manager.h"
+
#include "pbd/textreceiver.h"
#include "pbd/file_utils.h"
#include "ardour/session.h"
@@ -33,17 +33,12 @@ SessionTest::setUp ()
text_receiver.listen_to (fatal);
text_receiver.listen_to (warning);
- // this is not a good singleton constructor pattern
- AudioEngine* engine = 0;
-
- try {
- engine = new AudioEngine ("session_test", "");
- } catch (const AudioEngine::NoBackendAvailable& engine_exception) {
- cerr << engine_exception.what ();
- }
+ AudioEngine* engine = AudioEngine::create ();
CPPUNIT_ASSERT (engine);
+ CPPUNIT_ASSERT (engine->set_default_backend());
+
init_post_engine ();
CPPUNIT_ASSERT (engine->start () == 0);
@@ -53,9 +48,8 @@ void
SessionTest::tearDown ()
{
// this is needed or there is a crash in MIDI::Manager::destroy
- AudioEngine::instance()->stop (true);
+ AudioEngine::instance()->stop ();
- MIDI::Manager::destroy ();
AudioEngine::destroy ();
}
diff --git a/libs/ardour/test/test_common.cc b/libs/ardour/test/test_common.cc
index 5f802fbf5a..71eba65bbb 100644
--- a/libs/ardour/test/test_common.cc
+++ b/libs/ardour/test/test_common.cc
@@ -37,13 +37,14 @@ test_search_path ()
}
std::string
-new_test_output_dir ()
+new_test_output_dir (std::string prefix)
{
std::string tmp_dir = Glib::build_filename (g_get_tmp_dir(), "ardour_test");
std::string dir_name;
std::string new_test_dir;
do {
ostringstream oss;
+ oss << prefix;
oss << g_random_int ();
dir_name = oss.str();
new_test_dir = Glib::build_filename (tmp_dir, dir_name);
@@ -51,3 +52,9 @@ new_test_output_dir ()
} while (g_mkdir_with_parents (new_test_dir.c_str(), 0755) != 0);
return new_test_dir;
}
+
+int
+get_test_sample_rate ()
+{
+ return 44100;
+}
diff --git a/libs/ardour/test/test_common.h b/libs/ardour/test/test_common.h
index 10bfdbc694..bfda543508 100644
--- a/libs/ardour/test/test_common.h
+++ b/libs/ardour/test/test_common.h
@@ -23,6 +23,8 @@
PBD::Searchpath test_search_path ();
-std::string new_test_output_dir ();
+std::string new_test_output_dir (std::string prefix = "");
+
+int get_test_sample_rate ();
#endif
diff --git a/libs/ardour/test/test_globals.cc b/libs/ardour/test/test_globals.cc
deleted file mode 100644
index e40f951d75..0000000000
--- a/libs/ardour/test/test_globals.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "test_globals.h"
-
-int const Fs = 44100;
diff --git a/libs/ardour/test/test_globals.h b/libs/ardour/test/test_globals.h
deleted file mode 100644
index ccd5c27384..0000000000
--- a/libs/ardour/test/test_globals.h
+++ /dev/null
@@ -1,2 +0,0 @@
-
-extern int const Fs;
diff --git a/libs/ardour/test/test_needing_session.cc b/libs/ardour/test/test_needing_session.cc
index 181d391e01..4525a758b3 100644
--- a/libs/ardour/test/test_needing_session.cc
+++ b/libs/ardour/test/test_needing_session.cc
@@ -1,6 +1,5 @@
#include <glibmm/miscutils.h>
-#include "midi++/manager.h"
#include "pbd/compose.h"
#include "pbd/enumwriter.h"
#include "ardour/session.h"
@@ -26,8 +25,7 @@ TestNeedingSession::tearDown ()
{
AudioEngine::instance()->remove_session ();
delete _session;
- AudioEngine::instance()->stop (true);
+ AudioEngine::instance()->stop ();
- MIDI::Manager::destroy ();
AudioEngine::destroy ();
}
diff --git a/libs/ardour/test/test_util.cc b/libs/ardour/test/test_util.cc
index 1514012d97..dfbf40d351 100644
--- a/libs/ardour/test/test_util.cc
+++ b/libs/ardour/test/test_util.cc
@@ -60,12 +60,12 @@ check_xml (XMLNode* node, string ref_file, list<string> const & ignore_propertie
check_nodes (p, q, ignore_properties);
}
-void
+bool
write_ref (XMLNode* node, string ref_file)
{
XMLTree ref;
ref.set_root (node);
- ref.write (ref_file);
+ return ref.write (ref_file);
}
class TestReceiver : public Receiver
@@ -124,7 +124,10 @@ load_session (string dir, string state)
*/
Config->set_use_lxvst (false);
- AudioEngine* engine = new AudioEngine ("test", "");
+ AudioEngine* engine = AudioEngine::create ();
+
+ CPPUNIT_ASSERT (engine->set_default_backend ());
+
init_post_engine ();
CPPUNIT_ASSERT (engine->start () == 0);
diff --git a/libs/ardour/test/test_util.h b/libs/ardour/test/test_util.h
index fea74a2ea8..dd4b078e9f 100644
--- a/libs/ardour/test/test_util.h
+++ b/libs/ardour/test/test_util.h
@@ -8,5 +8,5 @@ namespace ARDOUR {
}
extern void check_xml (XMLNode *, std::string, std::list<std::string> const &);
-extern void write_ref (XMLNode *, std::string);
+extern bool write_ref (XMLNode *, std::string);
extern ARDOUR::Session* load_session (std::string, std::string);
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index d0c8eeb877..39584c6390 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -402,7 +402,7 @@ def build(bld):
# only build these common sources once
testcommon = bld(features = 'cxx')
testcommon.includes = obj.includes + ['test', '../pbd', '..']
- testcommon.source = ['test/test_globals.cc', 'test/testrunner.cc', 'test/test_needing_session.cc',
+ testcommon.source = ['test/testrunner.cc', 'test/test_needing_session.cc',
'test/test_common.cc', 'test/dummy_lxvst.cc', 'test/audio_region_test.cc', 'test/test_util.cc']
testcommon.uselib = ['CPPUNIT','SIGCPP','GLIBMM','GTHREAD',
'SAMPLERATE','XML','LRDF','COREAUDIO']
diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc
index a9bbe4b35a..ff76486bad 100644
--- a/libs/backends/jack/jack_audiobackend.cc
+++ b/libs/backends/jack/jack_audiobackend.cc
@@ -409,6 +409,12 @@ JACKAudioBackend::interleaved () const
return false;
}
+string
+JACKAudioBackend::midi_option () const
+{
+ return _target_midi_option;
+}
+
uint32_t
JACKAudioBackend::input_channels () const
{
@@ -465,7 +471,7 @@ JACKAudioBackend::raw_buffer_size(DataType t)
}
void
-JACKAudioBackend::setup_jack_startup_command ()
+JACKAudioBackend::setup_jack_startup_command (bool for_latency_measurement)
{
/* first we map the parameters that have been set onto a
* JackCommandLineOptions object.
@@ -490,6 +496,8 @@ JACKAudioBackend::setup_jack_startup_command ()
options.realtime = true;
options.ports_max = 2048;
+ ARDOUR::set_midi_option (options, _target_midi_option);
+
/* this must always be true for any server instance we start ourselves
*/
@@ -497,7 +505,7 @@ JACKAudioBackend::setup_jack_startup_command ()
string cmdline;
- if (!get_jack_command_line_string (options, cmdline)) {
+ if (!get_jack_command_line_string (options, cmdline, for_latency_measurement)) {
/* error, somehow - we will still try to start JACK
* automatically but it will be without our preferred options
*/
@@ -512,7 +520,7 @@ JACKAudioBackend::setup_jack_startup_command ()
/* ---- BASIC STATE CONTROL API: start/stop/pause/freewheel --- */
int
-JACKAudioBackend::start ()
+JACKAudioBackend::_start (bool for_latency_measurement)
{
if (!available()) {
@@ -520,7 +528,7 @@ JACKAudioBackend::start ()
/* we will be starting JACK, so set up the
command that JACK will use when it (auto-)starts
*/
- setup_jack_startup_command ();
+ setup_jack_startup_command (for_latency_measurement);
}
if (_jack_connection->open ()) {
@@ -597,7 +605,7 @@ JACKAudioBackend::freewheel (bool onoff)
}
if (jack_set_freewheel (_priv_jack, onoff) == 0) {
- _freewheeling = true;
+ _freewheeling = onoff;
return 0;
}
@@ -1110,3 +1118,16 @@ JACKAudioBackend::launch_control_app ()
args.push_back (appname);
Glib::spawn_async ("", args, Glib::SPAWN_SEARCH_PATH);
}
+
+vector<string>
+JACKAudioBackend::enumerate_midi_options () const
+{
+ return ARDOUR::enumerate_midi_options ();
+}
+
+int
+JACKAudioBackend::set_midi_option (const string& opt)
+{
+ _target_midi_option = opt;
+ return 0;
+}
diff --git a/libs/backends/jack/jack_audiobackend.h b/libs/backends/jack/jack_audiobackend.h
index cb24835d5b..3c48be5ead 100644
--- a/libs/backends/jack/jack_audiobackend.h
+++ b/libs/backends/jack/jack_audiobackend.h
@@ -89,7 +89,7 @@ class JACKAudioBackend : public AudioBackend {
std::string control_app_name () const;
void launch_control_app ();
- int start ();
+ int _start (bool for_latency_measurement);
int stop ();
int pause ();
int freewheel (bool);
@@ -149,6 +149,10 @@ class JACKAudioBackend : public AudioBackend {
/* MIDI */
+ std::vector<std::string> enumerate_midi_options () const;
+ int set_midi_option (const std::string&);
+ std::string midi_option () const;
+
int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index);
int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size);
uint32_t get_midi_event_count (void* port_buffer);
@@ -221,7 +225,7 @@ class JACKAudioBackend : public AudioBackend {
void* process_thread ();
static void* _start_process_thread (void*);
- void setup_jack_startup_command ();
+ void setup_jack_startup_command (bool for_latency_measurement);
/* pffooo */
@@ -237,6 +241,7 @@ class JACKAudioBackend : public AudioBackend {
uint32_t _target_systemic_output_latency;
uint32_t _current_sample_rate;
uint32_t _current_buffer_size;
+ std::string _target_midi_option;
typedef std::set<std::string> DeviceList;
typedef std::map<std::string,DeviceList> DriverDeviceMap;
diff --git a/libs/backends/jack/jack_utils.cc b/libs/backends/jack/jack_utils.cc
index a78c6491c7..83919eadb6 100644
--- a/libs/backends/jack/jack_utils.cc
+++ b/libs/backends/jack/jack_utils.cc
@@ -83,6 +83,7 @@ namespace {
const char * const dummy_driver_command_line_name = X_("dummy");
// should we provide more "pretty" names like above?
+ const char * const alsaint_midi_driver_name = X_("alsa");
const char * const alsaseq_midi_driver_name = X_("seq");
const char * const alsaraw_midi_driver_name = X_("raw");
const char * const winmme_midi_driver_name = X_("winmme");
@@ -92,6 +93,8 @@ namespace {
const char * const default_device_name = X_("Default");
}
+static ARDOUR::MidiOptions midi_options;
+
std::string
get_none_string ()
{
@@ -682,7 +685,7 @@ ARDOUR::JackCommandLineOptions::JackCommandLineOptions ()
}
bool
-ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& command_line)
+ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& command_line, bool for_latency_measurement)
{
vector<string> args;
@@ -740,6 +743,13 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c
}
#endif
+ if (options.driver == alsa_driver_name) {
+ if (options.midi_driver == alsaint_midi_driver_name) {
+ args.push_back ("-I");
+ args.push_back ("alsa_midi");
+ }
+ }
+
string command_line_driver_name;
if (!get_jack_command_line_audio_driver_name (options.driver, command_line_driver_name)) {
@@ -811,7 +821,7 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c
args.push_back ("-p");
args.push_back (to_string (options.period_size, std::dec));
- if (get_jack_audio_driver_supports_latency_adjustment (options.driver)) {
+ if (!for_latency_measurement && get_jack_audio_driver_supports_latency_adjustment (options.driver)) {
if (options.input_latency) {
args.push_back ("-I");
args.push_back (to_string (options.input_latency, std::dec));
@@ -846,10 +856,15 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c
if (options.soft_mode) {
args.push_back ("-s");
}
+ }
- if (!options.midi_driver.empty() && options.midi_driver != get_none_string ()) {
- args.push_back ("-X");
- args.push_back (options.midi_driver);
+ if (options.driver == alsa_driver_name || options.driver == coreaudio_driver_name) {
+
+ if (options.midi_driver != alsaint_midi_driver_name) {
+ if (!options.midi_driver.empty() && options.midi_driver != get_none_string ()) {
+ args.push_back ("-X");
+ args.push_back (options.midi_driver);
+ }
}
}
@@ -900,3 +915,53 @@ ARDOUR::write_jack_config_file (const std::string& config_file_path, const strin
jackdrc.close ();
return true;
}
+
+vector<string>
+ARDOUR::enumerate_midi_options ()
+{
+ if (midi_options.empty()) {
+#ifdef HAVE_ALSA
+ midi_options.push_back (make_pair (_("ALSA"), alsaint_midi_driver_name));
+ midi_options.push_back (make_pair (_("(legacy) ALSA raw devices"), alsaraw_midi_driver_name));
+ midi_options.push_back (make_pair (_("(legacy) ALSA sequencer"), alsaseq_midi_driver_name));
+#endif
+#ifdef HAVE_PORTAUDIO
+ /* Windows folks: what name makes sense here? Are there other
+ choices as well ?
+ */
+ midi_options.push_back (make_pair (_("Multimedia Extension"), winmme_midi_driver_name));
+#endif
+#ifdef __APPLE__
+ midi_options.push_back (make_pair (_("CoreMIDI"), coremidi_midi_driver_name));
+#endif
+ }
+
+ vector<string> v;
+
+ v.push_back (get_none_string());
+
+ for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) {
+ v.push_back (i->first);
+ }
+
+ return v;
+}
+
+int
+ARDOUR::set_midi_option (ARDOUR::JackCommandLineOptions& options, const string& opt)
+{
+ if (opt.empty() || opt == get_none_string()) {
+ options.midi_driver = "";
+ return 0;
+ }
+
+ for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) {
+ if (i->first == opt) {
+ options.midi_driver = i->second;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
diff --git a/libs/backends/jack/jack_utils.h b/libs/backends/jack/jack_utils.h
index a7521ad1c4..ee8575c5c8 100644
--- a/libs/backends/jack/jack_utils.h
+++ b/libs/backends/jack/jack_utils.h
@@ -180,6 +180,8 @@ namespace ARDOUR {
*/
bool get_jack_default_server_path (std::string& server_path);
+ typedef std::vector<std::pair<std::string,std::string> > MidiOptions;
+
/**
* @return The name of the jack server config file
*/
@@ -228,8 +230,11 @@ namespace ARDOUR {
std::string midi_driver;
};
+ std::vector<std::string> enumerate_midi_options ();
+ int set_midi_option (ARDOUR::JackCommandLineOptions&, const std::string& opt);
+
/**
* @return true if able to build a valid command line based on options
*/
- bool get_jack_command_line_string (JackCommandLineOptions& options, std::string& command_line);
+ bool get_jack_command_line_string (JackCommandLineOptions& options, std::string& command_line, bool for_latency_measurement);
}
diff --git a/libs/pbd/controllable_descriptor.cc b/libs/pbd/controllable_descriptor.cc
index 9c930e4dbd..392b917ec8 100644
--- a/libs/pbd/controllable_descriptor.cc
+++ b/libs/pbd/controllable_descriptor.cc
@@ -104,11 +104,10 @@ ControllableDescriptor::set (const std::string& str)
}
} else if (path[1] == "send") {
- if (path.size() == 3 && rest.size() == 3) {
+ if (path.size() == 3 && rest.size() == 2) {
if (path[2] == "gain") {
_subtype = SendGain;
_target.push_back (atoi (rest[1]));
- _target.push_back (atoi (rest[2]));
} else {
return -1;
}
diff --git a/tools/linux_packaging/build b/tools/linux_packaging/build
index 72e60257f0..d24aec4f8e 100755
--- a/tools/linux_packaging/build
+++ b/tools/linux_packaging/build
@@ -150,6 +150,7 @@ Shared=$APPDIR/share
Plugins=$APPLIB/plugins
Surfaces=$APPLIB/surfaces
Panners=$APPLIB/panners
+Backends=$APPLIB/backends
Modules=$Libraries/modules
Loaders=$Libraries/loaders
@@ -197,6 +198,7 @@ mkdir -p $PatchFiles
mkdir -p $MackieControl
mkdir -p $ExportFormats
mkdir -p $Panners
+mkdir -p $Backends
mkdir -p $Templates
mkdir -p $Shared/doc
@@ -382,6 +384,9 @@ done
# Panners
cp $BUILD_ROOT/libs/panners/*/lib*.so* $Panners
+# Backends
+cp $BUILD_ROOT/libs/backends/*/lib*.so* $Backends
+
# VAMP plugins that we use
cp $BUILD_ROOT/libs/vamp-plugins/libardourvampplugins.so* $Libraries
diff --git a/tools/osx_packaging/osx_build b/tools/osx_packaging/osx_build
index 96ed165832..0afb984d73 100755
--- a/tools/osx_packaging/osx_build
+++ b/tools/osx_packaging/osx_build
@@ -13,7 +13,7 @@ fi
SAE=
MIXBUS=
-WITH_HARVID=
+WITH_HARVID=1
WITH_LADSPA=1
STRIP=1
PRINT_SYSDEPS=
@@ -61,7 +61,7 @@ while [ $# -gt 0 ] ; do
# specific build flags
#
- --harvid) WITH_HARVID=1 ; shift ;;
+ --noharvid) WITH_HARVID= ; shift ;;
--noladspa) WITH_LADSPA= ; shift ;;
--nostrip) STRIP= ; shift ;;
--sysdeps) PRINT_SYSDEPS=1; shift ;;
@@ -99,6 +99,7 @@ Locale=$Resources/locale
Plugins=$APPROOT/Plugins
Surfaces=$Frameworks/surfaces
Panners=$Frameworks/panners
+Backends=$Frameworks/backends
MidiMaps=$Shared/midi_maps
ExportFormats=$Shared/export
Templates=$Shared/templates
@@ -132,6 +133,7 @@ mkdir -p $APPROOT/Resources
mkdir -p $Plugins
mkdir -p $Surfaces
mkdir -p $Panners
+mkdir -p $Backends
mkdir -p $MidiMaps
mkdir -p $ExportFormats
mkdir -p $Templates
@@ -308,6 +310,8 @@ cp $BUILD_ROOT/libs/surfaces/control_protocol/libardourcp*.dylib $Frameworks
# Panners
cp $BUILD_ROOT/libs/panners/*/lib*.dylib $Panners
+# Backends
+cp $BUILD_ROOT/libs/backends/*/lib*.dylib $Backends
# Export Formats/Presets
for f in $BUILD_ROOT/../export/*.preset $BUILD_ROOT/../export/*.format ; do