mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 06:44:57 +01:00
start work on the changes to EngineControl (dialog) to integrate with new backend design, and add "requires-driver" concept to AudioBackend to handle JACK specifically
This commit is contained in:
parent
333a3c9d02
commit
7218bd91de
10 changed files with 250 additions and 882 deletions
|
|
@ -17,6 +17,7 @@ export ARDOUR_DATA_PATH=$TOP:$TOP/build:$TOP/gtk2_ardour:$TOP/build/gtk2_ardour:
|
|||
export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:.
|
||||
export ARDOUR_MCP_PATH=$TOP/mcp:.
|
||||
export ARDOUR_EXPORT_FORMATS_PATH=$TOP/export:.
|
||||
export ARDOUR_BACKEND_PATH=$TOP/build/libs/ardour
|
||||
|
||||
#
|
||||
# even though we set the above variables, ardour requires that these
|
||||
|
|
|
|||
|
|
@ -397,7 +397,6 @@ ARDOUR_UI::attach_to_engine ()
|
|||
engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
|
||||
|
||||
engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
|
||||
engine->BackendAvailable.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::post_engine, this));
|
||||
|
||||
ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
|
||||
|
||||
|
|
|
|||
|
|
@ -66,33 +66,25 @@ using namespace PBD;
|
|||
using namespace Glib;
|
||||
|
||||
EngineControl::EngineControl ()
|
||||
: periods_adjustment (2, 2, 16, 1, 2),
|
||||
periods_spinner (periods_adjustment),
|
||||
ports_adjustment (128, 8, 1024, 1, 16),
|
||||
ports_spinner (ports_adjustment),
|
||||
input_latency_adjustment (0, 0, 99999, 1),
|
||||
input_latency (input_latency_adjustment),
|
||||
output_latency_adjustment (0, 0, 99999, 1),
|
||||
output_latency (output_latency_adjustment),
|
||||
realtime_button (_("Realtime")),
|
||||
no_memory_lock_button (_("Do not lock memory")),
|
||||
unlock_memory_button (_("Unlock memory")),
|
||||
soft_mode_button (_("No zombies")),
|
||||
monitor_button (_("Provide monitor ports")),
|
||||
force16bit_button (_("Force 16 bit")),
|
||||
hw_monitor_button (_("H/W monitoring")),
|
||||
hw_meter_button (_("H/W metering")),
|
||||
verbose_output_button (_("Verbose output")),
|
||||
start_button (_("Start")),
|
||||
stop_button (_("Stop")),
|
||||
: input_latency_adjustment (0, 0, 99999, 1)
|
||||
, input_latency (input_latency_adjustment)
|
||||
, output_latency_adjustment (0, 0, 99999, 1)
|
||||
, output_latency (output_latency_adjustment)
|
||||
, input_channels_adjustment (2, 0, 256, 1)
|
||||
, input_channels (input_channels_adjustment)
|
||||
, output_channels_adjustment (2, 0, 256, 1)
|
||||
, output_channels (output_channels_adjustment)
|
||||
, ports_adjustment (128, 8, 1024, 1, 16)
|
||||
, ports_spinner (ports_adjustment)
|
||||
, realtime_button (_("Realtime"))
|
||||
#ifdef __APPLE___
|
||||
basic_packer (5, 2),
|
||||
options_packer (4, 2),
|
||||
device_packer (4, 2)
|
||||
, basic_packer (6, 2)
|
||||
, options_packer (4, 2)
|
||||
, device_packer (4, 2)
|
||||
#else
|
||||
basic_packer (8, 2),
|
||||
options_packer (14, 2),
|
||||
device_packer (6, 2)
|
||||
, basic_packer (9, 2)
|
||||
, options_packer (14, 2)
|
||||
, device_packer (6, 2)
|
||||
#endif
|
||||
{
|
||||
using namespace Notebook_Helpers;
|
||||
|
|
@ -102,59 +94,24 @@ EngineControl::EngineControl ()
|
|||
|
||||
_used = false;
|
||||
|
||||
strings.push_back (_("8000Hz"));
|
||||
strings.push_back (_("22050Hz"));
|
||||
strings.push_back (_("44100Hz"));
|
||||
strings.push_back (_("48000Hz"));
|
||||
strings.push_back (_("88200Hz"));
|
||||
strings.push_back (_("96000Hz"));
|
||||
strings.push_back (_("192000Hz"));
|
||||
set_popdown_strings (sample_rate_combo, strings);
|
||||
sample_rate_combo.set_active_text ("48000Hz");
|
||||
|
||||
strings.clear ();
|
||||
strings.push_back ("32");
|
||||
strings.push_back ("64");
|
||||
strings.push_back ("128");
|
||||
strings.push_back ("256");
|
||||
strings.push_back ("512");
|
||||
strings.push_back ("1024");
|
||||
strings.push_back ("2048");
|
||||
strings.push_back ("4096");
|
||||
strings.push_back ("8192");
|
||||
set_popdown_strings (period_size_combo, strings);
|
||||
period_size_combo.set_active_text ("1024");
|
||||
|
||||
strings.clear ();
|
||||
strings.push_back (_("None"));
|
||||
strings.push_back (_("Triangular"));
|
||||
strings.push_back (_("Rectangular"));
|
||||
strings.push_back (_("Shaped"));
|
||||
set_popdown_strings (dither_mode_combo, strings);
|
||||
dither_mode_combo.set_active_text (_("None"));
|
||||
|
||||
/* basic parameters */
|
||||
|
||||
basic_packer.set_spacings (6);
|
||||
|
||||
strings.clear ();
|
||||
#ifdef __APPLE__
|
||||
strings.push_back (X_("CoreAudio"));
|
||||
#else
|
||||
#ifndef __FreeBSD__
|
||||
strings.push_back (X_("ALSA"));
|
||||
#endif
|
||||
strings.push_back (X_("OSS"));
|
||||
strings.push_back (X_("FreeBoB"));
|
||||
strings.push_back (X_("FFADO"));
|
||||
#endif
|
||||
strings.push_back (X_("NetJACK"));
|
||||
strings.push_back (X_("Dummy"));
|
||||
set_popdown_strings (driver_combo, strings);
|
||||
driver_combo.set_active_text (strings.front());
|
||||
|
||||
vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends();
|
||||
for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) {
|
||||
strings.push_back ((*b)->name);
|
||||
}
|
||||
|
||||
set_popdown_strings (backend_combo, strings);
|
||||
backend_combo.set_active_text (strings.front());
|
||||
|
||||
backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed));
|
||||
backend_changed ();
|
||||
|
||||
driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
|
||||
driver_changed ();
|
||||
|
||||
strings.clear ();
|
||||
strings.push_back (_("Playback/recording on 1 device"));
|
||||
|
|
@ -176,6 +133,11 @@ EngineControl::EngineControl ()
|
|||
|
||||
row = 0;
|
||||
|
||||
label = manage (left_aligned_label (_("Audio Driver:")));
|
||||
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
basic_packer.attach (backend_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
row++;
|
||||
|
||||
label = manage (left_aligned_label (_("Driver:")));
|
||||
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
|
|
@ -193,25 +155,16 @@ EngineControl::EngineControl ()
|
|||
|
||||
label = manage (left_aligned_label (_("Buffer size:")));
|
||||
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
row++;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||
label = manage (left_aligned_label (_("Number of buffers:")));
|
||||
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
periods_spinner.set_value (2);
|
||||
row++;
|
||||
#endif
|
||||
|
||||
label = manage (left_aligned_label (_("Approximate latency:")));
|
||||
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
row++;
|
||||
|
||||
sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
|
||||
periods_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
|
||||
period_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
|
||||
buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency));
|
||||
redisplay_latency();
|
||||
row++;
|
||||
/* no audio mode with CoreAudio, its duplex or nuthin' */
|
||||
|
|
@ -227,22 +180,7 @@ EngineControl::EngineControl ()
|
|||
input_device_combo.set_size_request (250, -1);
|
||||
output_device_combo.set_size_request (250, -1);
|
||||
|
||||
/*
|
||||
|
||||
if (engine_running()) {
|
||||
start_button.set_sensitive (false);
|
||||
} else {
|
||||
stop_button.set_sensitive (false);
|
||||
}
|
||||
|
||||
start_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::start_engine));
|
||||
stop_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::start_engine));
|
||||
*/
|
||||
|
||||
button_box.pack_start (start_button, false, false);
|
||||
button_box.pack_start (stop_button, false, false);
|
||||
|
||||
// basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0);
|
||||
interface_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::interface_changed));
|
||||
|
||||
/* options */
|
||||
|
||||
|
|
@ -254,46 +192,6 @@ EngineControl::EngineControl ()
|
|||
|
||||
realtime_button.set_active (true);
|
||||
|
||||
#if PROVIDE_TOO_MANY_OPTIONS
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||
options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
#else
|
||||
options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
#endif
|
||||
|
||||
strings.clear ();
|
||||
strings.push_back (_("Ignore"));
|
||||
strings.push_back ("500 msec");
|
||||
strings.push_back ("1 sec");
|
||||
strings.push_back ("2 sec");
|
||||
strings.push_back ("10 sec");
|
||||
set_popdown_strings (timeout_combo, strings);
|
||||
timeout_combo.set_active_text (strings.front ());
|
||||
|
||||
label = manage (new Label (_("Client timeout")));
|
||||
label->set_alignment (1.0, 0.5);
|
||||
options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
|
||||
options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
|
||||
#endif /* PROVIDE_TOO_MANY_OPTIONS */
|
||||
label = manage (left_aligned_label (_("Number of ports:")));
|
||||
options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
|
||||
options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
|
|
@ -311,23 +209,6 @@ EngineControl::EngineControl ()
|
|||
++row;
|
||||
#endif
|
||||
|
||||
find_jack_servers (server_strings);
|
||||
|
||||
if (server_strings.empty()) {
|
||||
fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg;
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
set_popdown_strings (serverpath_combo, server_strings);
|
||||
serverpath_combo.set_active_text (server_strings.front());
|
||||
|
||||
if (server_strings.size() > 1) {
|
||||
label = manage (left_aligned_label (_("Server:")));
|
||||
options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
|
||||
++row;
|
||||
}
|
||||
|
||||
/* device settings */
|
||||
|
||||
device_packer.set_spacings (6);
|
||||
|
|
@ -386,513 +267,92 @@ EngineControl::~EngineControl ()
|
|||
}
|
||||
|
||||
void
|
||||
EngineControl::build_command_line (vector<string>& cmd)
|
||||
EngineControl::backend_changed ()
|
||||
{
|
||||
string str;
|
||||
string driver;
|
||||
bool using_alsa = false;
|
||||
bool using_coreaudio = false;
|
||||
bool using_dummy = false;
|
||||
bool using_ffado = false;
|
||||
string backend_name = backend_combo.get_active_text();
|
||||
boost::shared_ptr<ARDOUR::AudioBackend> backend;
|
||||
|
||||
/* first, path to jackd */
|
||||
|
||||
cmd.push_back (serverpath_combo.get_active_text ());
|
||||
|
||||
/* now jackd arguments */
|
||||
|
||||
str = timeout_combo.get_active_text ();
|
||||
|
||||
if (str != _("Ignore")) {
|
||||
|
||||
double secs = 0;
|
||||
uint32_t msecs;
|
||||
secs = atof (str);
|
||||
msecs = (uint32_t) floor (secs * 1000.0);
|
||||
|
||||
if (msecs > 0) {
|
||||
cmd.push_back ("-t");
|
||||
cmd.push_back (to_string (msecs, std::dec));
|
||||
}
|
||||
if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) {
|
||||
/* eh? */
|
||||
return;
|
||||
}
|
||||
|
||||
if (no_memory_lock_button.get_active()) {
|
||||
cmd.push_back ("-m"); /* no munlock */
|
||||
}
|
||||
|
||||
cmd.push_back ("-p"); /* port max */
|
||||
cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec));
|
||||
|
||||
if (realtime_button.get_active()) {
|
||||
cmd.push_back ("-R");
|
||||
if (backend->requires_driver_selection()) {
|
||||
vector<string> drivers = backend->enumerate_drivers();
|
||||
set_popdown_strings (driver_combo, drivers);
|
||||
driver_combo.set_active_text (drivers.front());
|
||||
driver_changed ();
|
||||
} else {
|
||||
cmd.push_back ("-r"); /* override jackd's default --realtime */
|
||||
list_devices ();
|
||||
}
|
||||
|
||||
if (unlock_memory_button.get_active()) {
|
||||
cmd.push_back ("-u");
|
||||
}
|
||||
|
||||
if (verbose_output_button.get_active()) {
|
||||
cmd.push_back ("-v");
|
||||
}
|
||||
|
||||
/* now add fixed arguments (not user-selectable) */
|
||||
|
||||
cmd.push_back ("-T"); // temporary */
|
||||
|
||||
/* next the driver */
|
||||
|
||||
cmd.push_back ("-d");
|
||||
|
||||
driver = driver_combo.get_active_text ();
|
||||
|
||||
if (driver == X_("ALSA")) {
|
||||
using_alsa = true;
|
||||
cmd.push_back ("alsa");
|
||||
} else if (driver == X_("OSS")) {
|
||||
cmd.push_back ("oss");
|
||||
} else if (driver == X_("CoreAudio")) {
|
||||
using_coreaudio = true;
|
||||
cmd.push_back ("coreaudio");
|
||||
} else if (driver == X_("NetJACK")) {
|
||||
cmd.push_back ("netjack");
|
||||
} else if (driver == X_("FreeBoB")) {
|
||||
cmd.push_back ("freebob");
|
||||
} else if (driver == X_("FFADO")) {
|
||||
using_ffado = true;
|
||||
cmd.push_back ("firewire");
|
||||
} else if ( driver == X_("Dummy")) {
|
||||
using_dummy = true;
|
||||
cmd.push_back ("dummy");
|
||||
}
|
||||
|
||||
/* driver arguments */
|
||||
|
||||
if (!using_coreaudio) {
|
||||
str = audio_mode_combo.get_active_text();
|
||||
|
||||
if (str == _("Playback/recording on 1 device")) {
|
||||
|
||||
/* relax */
|
||||
|
||||
} else if (str == _("Playback/recording on 2 devices")) {
|
||||
|
||||
string input_device = get_device_name (driver, input_device_combo.get_active_text());
|
||||
string output_device = get_device_name (driver, output_device_combo.get_active_text());
|
||||
|
||||
if (input_device.empty() || output_device.empty()) {
|
||||
cmd.clear ();
|
||||
return;
|
||||
}
|
||||
|
||||
cmd.push_back ("-C");
|
||||
cmd.push_back (input_device);
|
||||
|
||||
cmd.push_back ("-P");
|
||||
cmd.push_back (output_device);
|
||||
|
||||
} else if (str == _("Playback only")) {
|
||||
cmd.push_back ("-P");
|
||||
} else if (str == _("Recording only")) {
|
||||
cmd.push_back ("-C");
|
||||
}
|
||||
|
||||
if (!using_dummy) {
|
||||
cmd.push_back ("-n");
|
||||
cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
|
||||
}
|
||||
}
|
||||
|
||||
cmd.push_back ("-r");
|
||||
cmd.push_back (to_string (get_rate(), std::dec));
|
||||
|
||||
cmd.push_back ("-p");
|
||||
cmd.push_back (period_size_combo.get_active_text());
|
||||
|
||||
if (using_alsa || using_ffado || using_coreaudio) {
|
||||
|
||||
double val = input_latency_adjustment.get_value();
|
||||
|
||||
if (val) {
|
||||
cmd.push_back ("-I");
|
||||
cmd.push_back (to_string ((uint32_t) val, std::dec));
|
||||
}
|
||||
|
||||
val = output_latency_adjustment.get_value();
|
||||
|
||||
if (val) {
|
||||
cmd.push_back ("-O");
|
||||
cmd.push_back (to_string ((uint32_t) val, std::dec));
|
||||
}
|
||||
}
|
||||
|
||||
if (using_alsa) {
|
||||
|
||||
if (audio_mode_combo.get_active_text() != _("Playback/recording on 2 devices")) {
|
||||
|
||||
string device = get_device_name (driver, interface_combo.get_active_text());
|
||||
if (device.empty()) {
|
||||
cmd.clear ();
|
||||
return;
|
||||
}
|
||||
|
||||
cmd.push_back ("-d");
|
||||
cmd.push_back (device);
|
||||
}
|
||||
|
||||
if (hw_meter_button.get_active()) {
|
||||
cmd.push_back ("-M");
|
||||
}
|
||||
|
||||
if (hw_monitor_button.get_active()) {
|
||||
cmd.push_back ("-H");
|
||||
}
|
||||
|
||||
str = dither_mode_combo.get_active_text();
|
||||
|
||||
if (str == _("None")) {
|
||||
} else if (str == _("Triangular")) {
|
||||
cmd.push_back ("-z triangular");
|
||||
} else if (str == _("Rectangular")) {
|
||||
cmd.push_back ("-z rectangular");
|
||||
} else if (str == _("Shaped")) {
|
||||
cmd.push_back ("-z shaped");
|
||||
}
|
||||
|
||||
if (force16bit_button.get_active()) {
|
||||
cmd.push_back ("-S");
|
||||
}
|
||||
|
||||
if (soft_mode_button.get_active()) {
|
||||
cmd.push_back ("-s");
|
||||
}
|
||||
|
||||
str = midi_driver_combo.get_active_text ();
|
||||
|
||||
if (str == _("seq")) {
|
||||
cmd.push_back ("-X seq");
|
||||
} else if (str == _("raw")) {
|
||||
cmd.push_back ("-X raw");
|
||||
}
|
||||
} else if (using_coreaudio) {
|
||||
|
||||
#ifdef __APPLE__
|
||||
// note: older versions of the CoreAudio JACK backend use -n instead of -d here
|
||||
|
||||
string device = get_device_name (driver, interface_combo.get_active_text());
|
||||
if (device.empty()) {
|
||||
cmd.clear ();
|
||||
return;
|
||||
}
|
||||
|
||||
cmd.push_back ("-d");
|
||||
cmd.push_back (device);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EngineControl::setup_engine ()
|
||||
{
|
||||
vector<string> args;
|
||||
std::string cwd = "/tmp";
|
||||
|
||||
build_command_line (args);
|
||||
|
||||
if (args.empty()) {
|
||||
return 1; // try again
|
||||
}
|
||||
|
||||
std::string jackdrc_path = Glib::get_home_dir();
|
||||
jackdrc_path += "/.jackdrc";
|
||||
|
||||
ofstream jackdrc (jackdrc_path.c_str());
|
||||
if (!jackdrc) {
|
||||
error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
|
||||
jackdrc << (*i) << ' ';
|
||||
}
|
||||
|
||||
jackdrc << endl;
|
||||
jackdrc.close ();
|
||||
|
||||
_used = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
EngineControl::enumerate_devices (const string& driver)
|
||||
EngineControl::list_devices ()
|
||||
{
|
||||
/* note: case matters for the map keys */
|
||||
boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
|
||||
assert (backend);
|
||||
|
||||
if (driver == "CoreAudio") {
|
||||
#ifdef __APPLE__
|
||||
devices[driver] = enumerate_coreaudio_devices ();
|
||||
#endif
|
||||
/* now fill out devices, mark sample rates, buffer sizes insensitive */
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||
} else if (driver == "ALSA") {
|
||||
devices[driver] = enumerate_alsa_devices ();
|
||||
} else if (driver == "FreeBOB") {
|
||||
devices[driver] = enumerate_freebob_devices ();
|
||||
} else if (driver == "FFADO") {
|
||||
devices[driver] = enumerate_ffado_devices ();
|
||||
} else if (driver == "OSS") {
|
||||
devices[driver] = enumerate_oss_devices ();
|
||||
} else if (driver == "Dummy") {
|
||||
devices[driver] = enumerate_dummy_devices ();
|
||||
} else if (driver == "NetJACK") {
|
||||
devices[driver] = enumerate_netjack_devices ();
|
||||
}
|
||||
#else
|
||||
}
|
||||
#endif
|
||||
vector<string> devices = backend->enumerate_devices ();
|
||||
|
||||
set_popdown_strings (interface_combo, devices);
|
||||
interface_combo.set_active_text (devices.front());
|
||||
set_popdown_strings (input_device_combo, devices);
|
||||
input_device_combo.set_active_text (devices.front());
|
||||
set_popdown_strings (output_device_combo, devices);
|
||||
output_device_combo.set_active_text (devices.front());
|
||||
|
||||
interface_changed ();
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
static OSStatus
|
||||
getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
|
||||
{
|
||||
UInt32 size = sizeof(CFStringRef);
|
||||
CFStringRef UI;
|
||||
OSStatus res = AudioDeviceGetProperty(id, 0, false,
|
||||
kAudioDevicePropertyDeviceUID, &size, &UI);
|
||||
if (res == noErr)
|
||||
CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
|
||||
CFRelease(UI);
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<string>
|
||||
EngineControl::enumerate_coreaudio_devices ()
|
||||
{
|
||||
vector<string> devs;
|
||||
|
||||
// Find out how many Core Audio devices are there, if any...
|
||||
// (code snippet gently "borrowed" from St?hane Letz jackdmp;)
|
||||
OSStatus err;
|
||||
Boolean isWritable;
|
||||
UInt32 outSize = sizeof(isWritable);
|
||||
|
||||
backend_devs.clear ();
|
||||
|
||||
err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
|
||||
&outSize, &isWritable);
|
||||
if (err == noErr) {
|
||||
// Calculate the number of device available...
|
||||
int numCoreDevices = outSize / sizeof(AudioDeviceID);
|
||||
// Make space for the devices we are about to get...
|
||||
AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
|
||||
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
|
||||
&outSize, (void *) coreDeviceIDs);
|
||||
if (err == noErr) {
|
||||
// Look for the CoreAudio device name...
|
||||
char coreDeviceName[256];
|
||||
UInt32 nameSize;
|
||||
|
||||
for (int i = 0; i < numCoreDevices; i++) {
|
||||
|
||||
nameSize = sizeof (coreDeviceName);
|
||||
|
||||
/* enforce duplex devices only */
|
||||
|
||||
err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
|
||||
0, true, kAudioDevicePropertyStreams,
|
||||
&outSize, &isWritable);
|
||||
|
||||
if (err != noErr || outSize == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
|
||||
0, false, kAudioDevicePropertyStreams,
|
||||
&outSize, &isWritable);
|
||||
|
||||
if (err != noErr || outSize == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
|
||||
0, true, kAudioDevicePropertyDeviceName,
|
||||
&outSize, &isWritable);
|
||||
if (err == noErr) {
|
||||
err = AudioDeviceGetProperty(coreDeviceIDs[i],
|
||||
0, true, kAudioDevicePropertyDeviceName,
|
||||
&nameSize, (void *) coreDeviceName);
|
||||
if (err == noErr) {
|
||||
char drivername[128];
|
||||
|
||||
// this returns the unique id for the device
|
||||
// that must be used on the commandline for jack
|
||||
|
||||
if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
|
||||
devs.push_back (coreDeviceName);
|
||||
backend_devs.push_back (drivername);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] coreDeviceIDs;
|
||||
}
|
||||
|
||||
|
||||
if (devs.size() == 0) {
|
||||
MessageDialog msg (string_compose (_("\
|
||||
You do not have any audio devices capable of\n\
|
||||
simultaneous playback and recording.\n\n\
|
||||
Please use Applications -> Utilities -> Audio MIDI Setup\n\
|
||||
to create an \"aggregrate\" device, or install a suitable\n\
|
||||
audio interface.\n\n\
|
||||
Please send email to Apple and ask them why new Macs\n\
|
||||
have no duplex audio device.\n\n\
|
||||
Alternatively, if you really want just playback\n\
|
||||
or recording but not both, start JACK before running\n\
|
||||
%1 and choose the relevant device then."
|
||||
), PROGRAM_NAME),
|
||||
true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
|
||||
msg.set_title (_("No suitable audio devices"));
|
||||
msg.set_position (Gtk::WIN_POS_MOUSE);
|
||||
msg.run ();
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
return devs;
|
||||
}
|
||||
#else
|
||||
|
||||
#if !defined(__FreeBSD__)
|
||||
vector<string>
|
||||
EngineControl::enumerate_alsa_devices ()
|
||||
{
|
||||
vector<string> devs;
|
||||
|
||||
snd_ctl_t *handle;
|
||||
snd_ctl_card_info_t *info;
|
||||
snd_pcm_info_t *pcminfo;
|
||||
snd_ctl_card_info_alloca(&info);
|
||||
snd_pcm_info_alloca(&pcminfo);
|
||||
string devname;
|
||||
int cardnum = -1;
|
||||
int device = -1;
|
||||
|
||||
backend_devs.clear ();
|
||||
|
||||
while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
|
||||
|
||||
devname = "hw:";
|
||||
devname += to_string (cardnum, std::dec);
|
||||
|
||||
if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
|
||||
|
||||
while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
|
||||
|
||||
snd_pcm_info_set_device (pcminfo, device);
|
||||
snd_pcm_info_set_subdevice (pcminfo, 0);
|
||||
snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
|
||||
|
||||
if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
|
||||
devs.push_back (snd_pcm_info_get_name (pcminfo));
|
||||
devname += ',';
|
||||
devname += to_string (device, std::dec);
|
||||
backend_devs.push_back (devname);
|
||||
}
|
||||
}
|
||||
|
||||
snd_ctl_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
return devs;
|
||||
}
|
||||
#endif
|
||||
|
||||
vector<string>
|
||||
EngineControl::enumerate_ffado_devices ()
|
||||
{
|
||||
vector<string> devs;
|
||||
backend_devs.clear ();
|
||||
return devs;
|
||||
}
|
||||
|
||||
vector<string>
|
||||
EngineControl::enumerate_freebob_devices ()
|
||||
{
|
||||
vector<string> devs;
|
||||
return devs;
|
||||
}
|
||||
|
||||
vector<string>
|
||||
EngineControl::enumerate_oss_devices ()
|
||||
{
|
||||
vector<string> devs;
|
||||
return devs;
|
||||
}
|
||||
vector<string>
|
||||
EngineControl::enumerate_dummy_devices ()
|
||||
{
|
||||
vector<string> devs;
|
||||
return devs;
|
||||
}
|
||||
vector<string>
|
||||
EngineControl::enumerate_netjack_devices ()
|
||||
{
|
||||
vector<string> devs;
|
||||
return devs;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
EngineControl::driver_changed ()
|
||||
{
|
||||
string driver = driver_combo.get_active_text();
|
||||
string::size_type maxlen = 0;
|
||||
int n = 0;
|
||||
boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
|
||||
assert (backend);
|
||||
|
||||
enumerate_devices (driver);
|
||||
backend->set_driver (driver_combo.get_active_text());
|
||||
list_devices ();
|
||||
}
|
||||
|
||||
vector<string>& strings = devices[driver];
|
||||
void
|
||||
EngineControl::interface_changed ()
|
||||
{
|
||||
boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
|
||||
assert (backend);
|
||||
string device_name = interface_combo.get_active_text ();
|
||||
vector<string> s;
|
||||
|
||||
if (strings.empty() && driver != "FreeBoB" && driver != "FFADO" && driver != "Dummy") {
|
||||
return;
|
||||
}
|
||||
/* sample rates */
|
||||
|
||||
for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
|
||||
if ((*i).length() > maxlen) {
|
||||
maxlen = (*i).length();
|
||||
vector<float> sr = backend->available_sample_rates (device_name);
|
||||
for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
|
||||
char buf[32];
|
||||
if (fmod (*x, 1000.0f)) {
|
||||
snprintf (buf, sizeof (buf), "%.1f kHz", (*x)/1000.0);
|
||||
} else {
|
||||
snprintf (buf, sizeof (buf), "%.0f kHz", (*x)/1000.0);
|
||||
}
|
||||
s.push_back (buf);
|
||||
}
|
||||
|
||||
set_popdown_strings (interface_combo, strings);
|
||||
set_popdown_strings (input_device_combo, strings);
|
||||
set_popdown_strings (output_device_combo, strings);
|
||||
set_popdown_strings (sample_rate_combo, s);
|
||||
sample_rate_combo.set_active_text (s.front());
|
||||
|
||||
if (!strings.empty()) {
|
||||
interface_combo.set_active_text (strings.front());
|
||||
input_device_combo.set_active_text (strings.front());
|
||||
output_device_combo.set_active_text (strings.front());
|
||||
/* buffer sizes */
|
||||
|
||||
s.clear ();
|
||||
vector<uint32_t> bs = backend->available_buffer_sizes(device_name);
|
||||
for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) {
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof (buf), "%u", *x);
|
||||
s.push_back (buf);
|
||||
}
|
||||
|
||||
if (driver == "ALSA") {
|
||||
soft_mode_button.set_sensitive (true);
|
||||
force16bit_button.set_sensitive (true);
|
||||
hw_monitor_button.set_sensitive (true);
|
||||
hw_meter_button.set_sensitive (true);
|
||||
monitor_button.set_sensitive (true);
|
||||
} else {
|
||||
soft_mode_button.set_sensitive (false);
|
||||
force16bit_button.set_sensitive (false);
|
||||
hw_monitor_button.set_sensitive (false);
|
||||
hw_meter_button.set_sensitive (false);
|
||||
monitor_button.set_sensitive (false);
|
||||
}
|
||||
set_popdown_strings (buffer_size_combo, s);
|
||||
buffer_size_combo.set_active_text (s.front());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
|
@ -912,15 +372,10 @@ void
|
|||
EngineControl::redisplay_latency ()
|
||||
{
|
||||
uint32_t rate = get_rate();
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
float periods = 2;
|
||||
#else
|
||||
float periods = periods_adjustment.get_value();
|
||||
#endif
|
||||
float period_size = atof (period_size_combo.get_active_text());
|
||||
float period_size = atof (buffer_size_combo.get_active_text());
|
||||
|
||||
char buf[32];
|
||||
snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
|
||||
snprintf (buf, sizeof(buf), "%.1fmsec", (2 * period_size) / (rate/1000.0));
|
||||
|
||||
latency_label.set_text (buf);
|
||||
latency_label.set_alignment (0, 0.5);
|
||||
|
|
@ -946,127 +401,6 @@ EngineControl::audio_mode_changed ()
|
|||
}
|
||||
}
|
||||
|
||||
static bool jack_server_filter(const string& str, void */*arg*/)
|
||||
{
|
||||
return str == "jackd" || str == "jackdmp";
|
||||
}
|
||||
|
||||
void
|
||||
EngineControl::find_jack_servers (vector<string>& strings)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
/* this magic lets us finds the path to the OSX bundle, and then
|
||||
we infer JACK's location from there
|
||||
*/
|
||||
|
||||
char execpath[MAXPATHLEN+1];
|
||||
uint32_t pathsz = sizeof (execpath);
|
||||
|
||||
_NSGetExecutablePath (execpath, &pathsz);
|
||||
|
||||
string path (Glib::path_get_dirname (execpath));
|
||||
path += "/jackd";
|
||||
|
||||
if (Glib::file_test (path, FILE_TEST_EXISTS)) {
|
||||
strings.push_back (path);
|
||||
}
|
||||
|
||||
if (getenv ("ARDOUR_WITH_JACK")) {
|
||||
/* no other options - only use the JACK we supply */
|
||||
if (strings.empty()) {
|
||||
fatal << string_compose (_("JACK appears to be missing from the %1 bundle"), PROGRAM_NAME) << endmsg;
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
return;
|
||||
}
|
||||
#else
|
||||
string path;
|
||||
#endif
|
||||
|
||||
PathScanner scanner;
|
||||
vector<string *> *jack_servers;
|
||||
std::map<string,int> un;
|
||||
char *p;
|
||||
bool need_minimal_path = false;
|
||||
|
||||
p = getenv ("PATH");
|
||||
|
||||
if (p && *p) {
|
||||
path = p;
|
||||
} else {
|
||||
need_minimal_path = true;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// many mac users don't have PATH set up to include
|
||||
// likely installed locations of JACK
|
||||
need_minimal_path = true;
|
||||
#endif
|
||||
|
||||
if (need_minimal_path) {
|
||||
if (path.empty()) {
|
||||
path = "/usr/bin:/bin:/usr/local/bin:/opt/local/bin";
|
||||
} else {
|
||||
path += ":/usr/local/bin:/opt/local/bin";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// push it back into the environment so that auto-started JACK can find it.
|
||||
// XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
|
||||
setenv ("PATH", path.c_str(), 1);
|
||||
#endif
|
||||
|
||||
jack_servers = scanner (path, jack_server_filter, 0, false, true);
|
||||
if (!jack_servers) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector<string *>::iterator iter;
|
||||
|
||||
for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) {
|
||||
string p = **iter;
|
||||
|
||||
if (un[p]++ == 0) {
|
||||
strings.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string
|
||||
EngineControl::get_device_name (const string& driver, const string& human_readable)
|
||||
{
|
||||
vector<string>::iterator n;
|
||||
vector<string>::iterator i;
|
||||
|
||||
if (human_readable.empty()) {
|
||||
/* this can happen if the user's .ardourrc file has a device name from
|
||||
another computer system in it
|
||||
*/
|
||||
MessageDialog msg (_("You need to choose an audio device first."));
|
||||
msg.set_position (WIN_POS_MOUSE);
|
||||
msg.run ();
|
||||
return string();
|
||||
}
|
||||
|
||||
if (backend_devs.empty()) {
|
||||
return human_readable;
|
||||
}
|
||||
|
||||
for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
|
||||
if (human_readable == (*i)) {
|
||||
return (*n);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == devices[driver].end()) {
|
||||
warning << string_compose (_("Audio device \"%1\" not known on this computer."), human_readable) << endmsg;
|
||||
}
|
||||
|
||||
return string();
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
EngineControl::get_state ()
|
||||
{
|
||||
|
|
@ -1074,6 +408,7 @@ EngineControl::get_state ()
|
|||
XMLNode* child;
|
||||
std::string path;
|
||||
|
||||
#if 0
|
||||
child = new XMLNode ("periods");
|
||||
child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
|
||||
root->add_child_nocopy (*child);
|
||||
|
|
@ -1165,7 +500,7 @@ EngineControl::get_state ()
|
|||
child = new XMLNode ("mididriver");
|
||||
child->add_property ("val", midi_driver_combo.get_active_text());
|
||||
root->add_child_nocopy (*child);
|
||||
|
||||
#endif
|
||||
return *root;
|
||||
}
|
||||
|
||||
|
|
@ -1181,7 +516,7 @@ EngineControl::set_state (const XMLNode& root)
|
|||
|
||||
int val;
|
||||
string strval;
|
||||
|
||||
#if 0
|
||||
if ( (child = root.child ("driver"))){
|
||||
prop = child->property("val");
|
||||
|
||||
|
|
@ -1316,4 +651,10 @@ EngineControl::set_state (const XMLNode& root)
|
|||
midi_driver_combo.set_active_text(strval);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
EngineControl::setup_engine ()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,80 +47,67 @@ class EngineControl : public Gtk::VBox {
|
|||
void set_state (const XMLNode&);
|
||||
|
||||
private:
|
||||
Gtk::Adjustment periods_adjustment;
|
||||
Gtk::SpinButton periods_spinner;
|
||||
Gtk::Adjustment ports_adjustment;
|
||||
Gtk::SpinButton ports_spinner;
|
||||
Gtk::Adjustment input_latency_adjustment;
|
||||
Gtk::SpinButton input_latency;
|
||||
Gtk::Adjustment output_latency_adjustment;
|
||||
Gtk::SpinButton output_latency;
|
||||
Gtk::Label latency_label;
|
||||
/* core fields used by all backends */
|
||||
|
||||
Gtk::CheckButton realtime_button;
|
||||
Gtk::CheckButton no_memory_lock_button;
|
||||
Gtk::CheckButton unlock_memory_button;
|
||||
Gtk::CheckButton soft_mode_button;
|
||||
Gtk::CheckButton monitor_button;
|
||||
Gtk::CheckButton force16bit_button;
|
||||
Gtk::CheckButton hw_monitor_button;
|
||||
Gtk::CheckButton hw_meter_button;
|
||||
Gtk::CheckButton verbose_output_button;
|
||||
Gtk::ComboBoxText backend_combo;
|
||||
Gtk::ComboBoxText input_device_combo;
|
||||
Gtk::ComboBoxText output_device_combo;
|
||||
Gtk::ComboBoxText sample_rate_combo;
|
||||
Gtk::ComboBoxText buffer_size_combo;
|
||||
Gtk::Adjustment input_latency_adjustment;
|
||||
Gtk::SpinButton input_latency;
|
||||
Gtk::Adjustment output_latency_adjustment;
|
||||
Gtk::SpinButton output_latency;
|
||||
Gtk::Adjustment input_channels_adjustment;
|
||||
Gtk::SpinButton input_channels;
|
||||
Gtk::Adjustment output_channels_adjustment;
|
||||
Gtk::SpinButton output_channels;
|
||||
Gtk::Adjustment ports_adjustment;
|
||||
Gtk::SpinButton ports_spinner;
|
||||
Gtk::Label latency_label;
|
||||
|
||||
Gtk::Button start_button;
|
||||
Gtk::Button stop_button;
|
||||
Gtk::HButtonBox button_box;
|
||||
/* JACK specific */
|
||||
|
||||
Gtk::ComboBoxText sample_rate_combo;
|
||||
Gtk::ComboBoxText period_size_combo;
|
||||
Gtk::CheckButton realtime_button;
|
||||
Gtk::CheckButton no_memory_lock_button;
|
||||
Gtk::CheckButton unlock_memory_button;
|
||||
Gtk::CheckButton soft_mode_button;
|
||||
Gtk::CheckButton monitor_button;
|
||||
Gtk::CheckButton force16bit_button;
|
||||
Gtk::CheckButton hw_monitor_button;
|
||||
Gtk::CheckButton hw_meter_button;
|
||||
Gtk::CheckButton verbose_output_button;
|
||||
|
||||
Gtk::ComboBoxText preset_combo;
|
||||
Gtk::ComboBoxText serverpath_combo;
|
||||
Gtk::ComboBoxText driver_combo;
|
||||
Gtk::ComboBoxText interface_combo;
|
||||
Gtk::ComboBoxText timeout_combo;
|
||||
Gtk::ComboBoxText dither_mode_combo;
|
||||
Gtk::ComboBoxText audio_mode_combo;
|
||||
Gtk::ComboBoxText input_device_combo;
|
||||
Gtk::ComboBoxText output_device_combo;
|
||||
Gtk::ComboBoxText midi_driver_combo;
|
||||
|
||||
Gtk::Table basic_packer;
|
||||
Gtk::Table options_packer;
|
||||
Gtk::Table device_packer;
|
||||
Gtk::HBox basic_hbox;
|
||||
Gtk::HBox options_hbox;
|
||||
Gtk::HBox device_hbox;
|
||||
Gtk::Notebook notebook;
|
||||
Gtk::ComboBoxText preset_combo;
|
||||
Gtk::ComboBoxText serverpath_combo;
|
||||
Gtk::ComboBoxText driver_combo;
|
||||
Gtk::ComboBoxText interface_combo;
|
||||
Gtk::ComboBoxText timeout_combo;
|
||||
Gtk::ComboBoxText dither_mode_combo;
|
||||
Gtk::ComboBoxText audio_mode_combo;
|
||||
Gtk::ComboBoxText midi_driver_combo;
|
||||
|
||||
bool _used;
|
||||
Gtk::Table basic_packer;
|
||||
Gtk::Table options_packer;
|
||||
Gtk::Table device_packer;
|
||||
Gtk::HBox basic_hbox;
|
||||
Gtk::HBox options_hbox;
|
||||
Gtk::HBox device_hbox;
|
||||
Gtk::Notebook notebook;
|
||||
|
||||
static bool engine_running ();
|
||||
bool _used;
|
||||
|
||||
void driver_changed ();
|
||||
void build_command_line (std::vector<std::string>&);
|
||||
static bool engine_running ();
|
||||
|
||||
std::map<std::string,std::vector<std::string> > devices;
|
||||
std::vector<std::string> backend_devs;
|
||||
void enumerate_devices (const std::string& driver);
|
||||
void driver_changed ();
|
||||
void backend_changed ();
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::vector<std::string> enumerate_coreaudio_devices ();
|
||||
#else
|
||||
std::vector<std::string> enumerate_alsa_devices ();
|
||||
std::vector<std::string> enumerate_oss_devices ();
|
||||
std::vector<std::string> enumerate_netjack_devices ();
|
||||
std::vector<std::string> enumerate_freebob_devices ();
|
||||
std::vector<std::string> enumerate_ffado_devices ();
|
||||
std::vector<std::string> enumerate_dummy_devices ();
|
||||
#endif
|
||||
|
||||
void redisplay_latency ();
|
||||
uint32_t get_rate();
|
||||
void audio_mode_changed ();
|
||||
std::vector<std::string> server_strings;
|
||||
void find_jack_servers (std::vector<std::string>&);
|
||||
std::string get_device_name (const std::string& driver, const std::string& human_readable_name);
|
||||
void redisplay_latency ();
|
||||
uint32_t get_rate();
|
||||
void audio_mode_changed ();
|
||||
void interface_changed ();
|
||||
void list_devices ();
|
||||
};
|
||||
|
||||
#endif /* __gtk2_ardour_engine_dialog_h__ */
|
||||
|
|
|
|||
|
|
@ -68,6 +68,33 @@ class AudioBackend {
|
|||
|
||||
/* Discovering devices and parameters */
|
||||
|
||||
/** Return true if this backend requires the selection of a "driver"
|
||||
* before any device can be selected. Return false otherwise.
|
||||
*
|
||||
* Intended mainly to differentiate between meta-APIs like JACK
|
||||
* which can still expose different backends (such as ALSA or CoreAudio
|
||||
* or FFADO or netjack) and those like ASIO or CoreAudio which
|
||||
* do not.
|
||||
*/
|
||||
virtual bool requires_driver_selection() const { return false; }
|
||||
|
||||
/** If the return value of requires_driver_selection() is true,
|
||||
* then this function can return the list of known driver names.
|
||||
*
|
||||
* If the return value of requires_driver_selection() is false,
|
||||
* then this function should not be called. If it is called
|
||||
* its return value is an empty vector of strings.
|
||||
*/
|
||||
virtual std::vector<std::string> enumerate_drivers() const { return std::vector<std::string>(); }
|
||||
|
||||
/** Returns zero if the backend can successfully use @param name as the
|
||||
* driver, non-zero otherwise.
|
||||
*
|
||||
* Should not be used unless the backend returns true from
|
||||
* requires_driver_selection()
|
||||
*/
|
||||
virtual int set_driver (const std::string& /*drivername*/) { return 0; }
|
||||
|
||||
/** Returns a collection of strings identifying devices known
|
||||
* to this backend. Any of these strings may be used to identify a
|
||||
* device in other calls to the backend, though any of them may become
|
||||
|
|
@ -358,8 +385,8 @@ struct AudioBackendInfo {
|
|||
* configured and does not need (re)configuration in order
|
||||
* to be usable. Return false otherwise.
|
||||
*
|
||||
* Note that this may return true if (re)configuration is possible,
|
||||
* but not required.
|
||||
* Note that this may return true if (re)configuration, even though
|
||||
* not currently required, is still possible.
|
||||
*/
|
||||
bool (*already_configured)();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ public:
|
|||
int discover_backends();
|
||||
std::vector<const AudioBackendInfo*> available_backends() const;
|
||||
std::string current_backend_name () const;
|
||||
int set_backend (const std::string&, const std::string& arg1, const std::string& arg2);
|
||||
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;
|
||||
|
||||
ProcessThread* main_thread() const { return _main_thread; }
|
||||
|
|
@ -172,13 +173,6 @@ public:
|
|||
PBD::Signal0<void> Running;
|
||||
PBD::Signal0<void> Stopped;
|
||||
|
||||
/* these two are emitted as we create backends that
|
||||
can actually be used to do stuff (e.g. register ports)
|
||||
*/
|
||||
|
||||
PBD::Signal0<void> BackendAvailable;
|
||||
PBD::Signal0<void> BackendRemoved;
|
||||
|
||||
static AudioEngine* instance() { return _instance; }
|
||||
static void destroy();
|
||||
void died ();
|
||||
|
|
|
|||
|
|
@ -49,7 +49,12 @@ class JACKAudioBackend : public AudioBackend {
|
|||
bool connected() const;
|
||||
bool is_realtime () const;
|
||||
|
||||
bool requires_driver_selection() const;
|
||||
std::vector<std::string> enumerate_drivers () const;
|
||||
int set_driver (const std::string&);
|
||||
|
||||
std::vector<std::string> enumerate_devices () const;
|
||||
|
||||
std::vector<float> available_sample_rates (const std::string& device) const;
|
||||
std::vector<uint32_t> available_buffer_sizes (const std::string& device) const;
|
||||
uint32_t available_input_channel_count (const std::string& device) const;
|
||||
|
|
@ -151,6 +156,7 @@ class JACKAudioBackend : public AudioBackend {
|
|||
|
||||
/* pffooo */
|
||||
|
||||
std::string _target_driver;
|
||||
std::string _target_device;
|
||||
float _target_sample_rate;
|
||||
uint32_t _target_buffer_size;
|
||||
|
|
|
|||
|
|
@ -561,18 +561,16 @@ AudioEngine::drop_backend ()
|
|||
if (_backend) {
|
||||
_backend->stop ();
|
||||
_backend.reset ();
|
||||
|
||||
BackendRemoved(); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
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);
|
||||
|
||||
if (b == _backends.end()) {
|
||||
return -1;
|
||||
return boost::shared_ptr<AudioBackend>();
|
||||
}
|
||||
|
||||
drop_backend ();
|
||||
|
|
@ -590,12 +588,10 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons
|
|||
|
||||
} catch (exception& e) {
|
||||
error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
|
||||
return -1;
|
||||
return boost::shared_ptr<AudioBackend>();
|
||||
}
|
||||
|
||||
BackendAvailable (); /* EMIT SIGNAL */
|
||||
|
||||
return 0;
|
||||
return _backend;
|
||||
}
|
||||
|
||||
/* BACKEND PROXY WRAPPERS */
|
||||
|
|
|
|||
|
|
@ -90,16 +90,13 @@ extern "C" {
|
|||
* must be non-mangled.
|
||||
*/
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
||||
AudioBackendInfo descriptor = {
|
||||
ARDOUR::AudioBackendInfo descriptor = {
|
||||
"JACK",
|
||||
instantiate,
|
||||
deinstantiate,
|
||||
backend_factory,
|
||||
portengine_factory,
|
||||
already_configured
|
||||
already_configured,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,11 +88,31 @@ JACKAudioBackend::is_realtime () const
|
|||
return jack_is_realtime (_priv_jack);
|
||||
}
|
||||
|
||||
bool
|
||||
JACKAudioBackend::requires_driver_selection() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<string>
|
||||
JACKAudioBackend::enumerate_drivers () const
|
||||
{
|
||||
vector<string> s;
|
||||
get_jack_audio_driver_names (s);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
JACKAudioBackend::set_driver (const std::string& name)
|
||||
{
|
||||
_target_driver = name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vector<string>
|
||||
JACKAudioBackend::enumerate_devices () const
|
||||
{
|
||||
vector<string> devices;
|
||||
return devices;
|
||||
return get_jack_device_names_for_audio_driver (_target_driver);
|
||||
}
|
||||
|
||||
vector<float>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue