#include <vector>
#include <cmath>
#include <fstream>
+#include <map>
#include <glibmm.h>
+#include <gtkmm/messagedialog.h>
#include <pbd/xml++.h>
#ifdef __APPLE__
#include <pbd/convert.h>
#include <pbd/error.h>
+#include <pbd/pathscanner.h>
#ifdef __APPLE
#include <CFBundle.h>
strings.push_back (X_("ALSA"));
strings.push_back (X_("OSS"));
strings.push_back (X_("FFADO"));
- strings.push_back (X_("FreeBoB"));
#endif
strings.push_back (X_("NetJACK"));
strings.push_back (X_("Dummy"));
set_popdown_strings (driver_combo, strings);
driver_combo.set_active_text (strings.front());
- /* figure out available devices and set up interface_combo */
-
- enumerate_devices ();
driver_combo.signal_changed().connect (mem_fun (*this, &EngineControl::driver_changed));
driver_changed ();
bool using_coreaudio = false;
bool using_netjack = false;
bool using_ffado = false;
- bool using_freebob = false;
+ bool using_dummy = false;
/* first, path to jackd */
str = timeout_combo.get_active_text ();
if (str != _("Ignore")) {
- double secs;
+ double secs = 0;
uint32_t msecs;
atof (str);
msecs = (uint32_t) floor (secs * 1000.0);
cmd.push_back ("netjack");
} else if (driver == X_("FFADO")) {
using_ffado = true;
- cmd.push_back ("firewire");
- } else if (driver == X_("FreeBoB")) {
- using_freebob = true;
- cmd.push_back ("freebob");
+
+ /* do this until FFADO becomes the standard */
+
+ char* hack = getenv ("ARDOUR_FIREWIRE_DRIVER_NAME");
+
+ if (hack) {
+ cmd.push_back (hack);
+ } else {
+ cmd.push_back ("freebob");
+ }
+
+ } else if ( driver == X_("Dummy")) {
+ using_dummy = true;
+ cmd.push_back ("dummy");
}
/* driver arguments */
} 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 (get_device_name (driver, input_device_combo.get_active_text()));
+ cmd.push_back (input_device);
cmd.push_back ("-P");
- cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
-
+ cmd.push_back (output_device);
+
} else if (str == _("Playback only")) {
cmd.push_back ("-P");
} else if (str == _("Recording only")) {
cmd.push_back ("-C");
}
- cmd.push_back ("-n");
- cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
+ 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");
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 (get_device_name (driver, interface_combo.get_active_text()));
+ cmd.push_back (device);
}
if (hw_meter_button.get_active()) {
#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 (get_device_name (driver, interface_combo.get_active_text()));
+ cmd.push_back (device);
#endif
} else if (using_oss) {
std::string cwd = "/tmp";
build_command_line (args);
+
+ if (args.empty()) {
+ return 1; // try again
+ }
Glib::ustring jackdrc_path = Glib::get_home_dir();
jackdrc_path += "/.jackdrc";
error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
return -1;
}
-
+ cerr << "JACK COMMAND: ";
for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
+ cerr << (*i) << ' ';
jackdrc << (*i) << ' ';
}
+ cerr << endl;
jackdrc << endl;
jackdrc.close ();
}
void
-EngineControl::enumerate_devices ()
+EngineControl::enumerate_devices (const string& driver)
{
/* note: case matters for the map keys */
-#ifdef __APPLE__
- devices["CoreAudio"] = enumerate_coreaudio_devices ();
+ if (driver == "CoreAudio") {
+#ifdef __APPLE__
+ devices[driver] = enumerate_coreaudio_devices ();
+#endif
+
+#ifndef __APPLE__
+ } else if (driver == "ALSA") {
+ devices[driver] = enumerate_alsa_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
- devices["ALSA"] = enumerate_alsa_devices ();
- devices["FFADO"] = enumerate_ffado_devices ();
- devices["FreeBoB"] = enumerate_freebob_devices ();
- devices["OSS"] = enumerate_oss_devices ();
- devices["Dummy"] = enumerate_dummy_devices ();
- devices["NetJACK"] = enumerate_netjack_devices ();
+ }
#endif
}
// Look for the CoreAudio device name...
char coreDeviceName[256];
size_t 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);
delete [] coreDeviceIDs;
}
+
+ if (devs.size() == 0) {
+ MessageDialog msg (_("\
+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\
+Ardour and choose the relevant device then."
+ ),
+ 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
EngineControl::enumerate_ffado_devices ()
{
vector<string> devs;
+ backend_devs.clear ();
return devs;
}
+
vector<string>
EngineControl::enumerate_freebob_devices ()
{
EngineControl::driver_changed ()
{
string driver = driver_combo.get_active_text();
- vector<string>& strings = devices[driver];
string::size_type maxlen = 0;
int maxindex = -1;
int n = 0;
+ enumerate_devices (driver);
+
+ vector<string>& strings = devices[driver];
+
+ if (strings.empty() && driver != "FFADO" && driver != "Dummy") {
+ error << string_compose (_("No devices found for driver \"%1\""), driver) << endmsg;
+ return;
+ }
+
for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
if ((*i).length() > maxlen) {
maxlen = (*i).length();
interface_combo.set_active_text (strings.front());
input_device_combo.set_active_text (strings.front());
output_device_combo.set_active_text (strings.front());
- }
+ }
if (driver == "ALSA") {
soft_mode_button.set_sensitive (true);
}
}
+static bool jack_server_filter(const string& str, void *arg)
+{
+ return str == "jackd" || str == "jackdmp";
+}
+
void
EngineControl::find_jack_servers (vector<string>& strings)
{
_NSGetExecutablePath (execpath, &pathsz);
- cerr << " execpath = " << execpath << endl;
-
- Glib::ustring path (Glib::path_get_dirname (execpath));
+ string path (Glib::path_get_dirname (execpath));
path += "/jackd";
if (Glib::file_test (path, FILE_TEST_EXISTS)) {
strings.push_back (path);
- cerr << "Found jack in " << path << endl;
}
if (getenv ("ARDOUR_WITH_JACK")) {
}
return;
}
+#else
+ string path;
#endif
- if (Glib::file_test ("/usr/bin/jackd", FILE_TEST_EXISTS)) {
- strings.push_back ("/usr/bin/jackd");
- }
- if (Glib::file_test ("/usr/local/bin/jackd", FILE_TEST_EXISTS)) {
- strings.push_back ("/usr/local/bin/jackd");
- }
- if (Glib::file_test ("/opt/bin/jackd", FILE_TEST_EXISTS)) {
- strings.push_back ("/opt/bin/jackd");
- }
- if (Glib::file_test ("/usr/bin/jackdmp", FILE_TEST_EXISTS)) {
- strings.push_back ("/usr/bin/jackd");
- }
- if (Glib::file_test ("/usr/local/bin/jackdmp", FILE_TEST_EXISTS)) {
- strings.push_back ("/usr/local/bin/jackd");
+ 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;
}
- if (Glib::file_test ("/opt/bin/jackdmp", FILE_TEST_EXISTS)) {
- strings.push_back ("/opt/bin/jackd");
+
+#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);
+
+ 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.run ();
+ return string();
+ }
+
if (backend_devs.empty()) {
return human_readable;
}
}
if (i == devices[driver].end()) {
- fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
- /*NOTREACHED*/
+ warning << string_compose (_("Audio device \"%1\" not known on this computer."), human_readable) << endmsg;
}
- /* keep gcc happy */
-
return string();
}
XMLNodeList clist;
XMLNodeConstIterator citer;
XMLNode* child;
- XMLProperty* prop;
-
+ XMLProperty* prop = NULL;
+ bool using_dummy = false;
+
int val;
string strval;
-
+
+ if ( (child = root.child ("driver"))){
+ prop = child->property("val");
+ if (prop && (prop->value() == "Dummy") ) {
+ using_dummy = true;
+ }
+ }
+
clist = root.children();
for (citer = clist.begin(); citer != clist.end(); ++citer) {
-
+ if ( prop && (prop->value() == "FFADO" ))
+ continue;
child = *citer;
prop = child->property ("val");
if (!prop || prop->value().empty()) {
+
+ if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
+ continue;
error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
continue;
}