+/*
+ Copyright (C) 2010 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
#include <vector>
#include <cmath>
#include <fstream>
#include <map>
+#include <boost/scoped_ptr.hpp>
+
#include <glibmm.h>
#include <gtkmm/messagedialog.h>
-#include <pbd/xml++.h>
+
+#include "pbd/epa.h"
+#include "pbd/xml++.h"
#ifdef __APPLE__
#include <CoreAudio/CoreAudio.h>
#include <alsa/asoundlib.h>
#endif
-#include <ardour/profile.h>
#include <jack/jack.h>
#include <gtkmm/stock.h>
#include <gtkmm2ext/utils.h>
-#include <pbd/convert.h>
-#include <pbd/error.h>
-#include <pbd/pathscanner.h>
+#include "pbd/convert.h"
+#include "pbd/error.h"
+#include "pbd/pathscanner.h"
#ifdef __APPLE
#include <CFBundle.h>
priority_spinner (priority_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")),
basic_packer (8, 2),
options_packer (14, 2),
device_packer (6, 2)
-#endif
+#endif
{
using namespace Notebook_Helpers;
Label* label;
#else
strings.push_back (X_("ALSA"));
strings.push_back (X_("OSS"));
+ strings.push_back (X_("FreeBoB"));
strings.push_back (X_("FFADO"));
#endif
strings.push_back (X_("NetJACK"));
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_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed));
driver_changed ();
strings.clear ();
- strings.push_back (_("Playback/Recording on 1 Device"));
- strings.push_back (_("Playback/Recording on 2 Devices"));
+ strings.push_back (_("Playback/recording on 1 device"));
+ strings.push_back (_("Playback/recording on 2 devices"));
strings.push_back (_("Playback only"));
strings.push_back (_("Recording only"));
set_popdown_strings (audio_mode_combo, strings);
audio_mode_combo.set_active_text (strings.front());
- audio_mode_combo.signal_changed().connect (mem_fun (*this, &EngineControl::audio_mode_changed));
+ audio_mode_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::audio_mode_changed));
audio_mode_changed ();
+ strings.clear ();
+ strings.push_back (_("None"));
+ strings.push_back (_("seq"));
+ strings.push_back (_("raw"));
+ set_popdown_strings (midi_driver_combo, strings);
+ midi_driver_combo.set_active_text (strings.front ());
+
row = 0;
- label = manage (new Label (_("Driver")));
+ 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);
row++;
- label = manage (new Label (_("Interface")));
+ label = manage (left_aligned_label (_("Audio Interface:")));
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
row++;
- label = manage (new Label (_("Sample Rate")));
+ label = manage (left_aligned_label (_("Sample rate:")));
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
row++;
- label = manage (new Label (_("Buffer size")));
+ 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);
row++;
#ifndef __APPLE__
- label = manage (new Label (_("Number of buffers")));
+ 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 (new Label (_("Approximate latency")));
- label->set_alignment (0.0, 0.5);
+ 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 (mem_fun (*this, &EngineControl::redisplay_latency));
- periods_adjustment.signal_value_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
- period_size_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
+ 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));
redisplay_latency();
row++;
/* no audio mode with CoreAudio, its duplex or nuthin' */
#ifndef __APPLE__
- label = manage (new Label (_("Audio Mode")));
+ label = manage (left_aligned_label (_("Audio mode:")));
basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
row++;
#endif
- interface_combo.set_size_request (125, -1);
- input_device_combo.set_size_request (125, -1);
- output_device_combo.set_size_request (125, -1);
+ interface_combo.set_size_request (250, -1);
+ input_device_combo.set_size_request (250, -1);
+ output_device_combo.set_size_request (250, -1);
/*
stop_button.set_sensitive (false);
}
- start_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
- stop_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
+ 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);
options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
++row;
- realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed));
+ realtime_button.set_active (true);
+ realtime_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::realtime_changed));
realtime_changed ();
+#if PROVIDE_TOO_MANY_OPTIONS
+
#ifndef __APPLE__
label = manage (new Label (_("Realtime Priority")));
label->set_alignment (1.0, 0.5);
++row;
options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
++row;
-#else
+#else
options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
++row;
#endif
options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
++row;
- label = manage (new Label (_("Number of ports")));
- label->set_alignment (1.0, 0.5);
+#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);
++row;
+ label = manage (left_aligned_label (_("MIDI driver:")));
+ options_packer.attach (midi_driver_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
+ options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+ ++row;
+
#ifndef __APPLE__
- label = manage (new Label (_("Dither")));
- label->set_alignment (1.0, 0.5);
+ label = manage (left_aligned_label (_("Dither:")));
options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
++row;
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 (new Label (_("Server:")));
+ label = manage (left_aligned_label (_("Server:")));
options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
- label->set_alignment (0.0, 0.5);
options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
++row;
}
row = 0;
#ifndef __APPLE__
- label = manage (new Label (_("Input device")));
- label->set_alignment (1.0, 0.5);
+ label = manage (left_aligned_label (_("Input device:")));
device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
++row;
- label = manage (new Label (_("Output device")));
- label->set_alignment (1.0, 0.5);
+ label = manage (left_aligned_label (_("Output device:")));
device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
- device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+ device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
++row;
#endif
- label = manage (new Label (_("Input channels")));
- label->set_alignment (1.0, 0.5);
- device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
- device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
- ++row;
- label = manage (new Label (_("Output channels")));
- label->set_alignment (1.0, 0.5);
- device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
- device_packer.attach (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
- ++row;
- label = manage (new Label (_("Hardware input latency (samples)")));
- label->set_alignment (1.0, 0.5);
+ label = manage (left_aligned_label (_("Hardware input latency:")));
device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+ label = manage (left_aligned_label (_("samples")));
+ device_packer.attach (*label, 2, 3, row, row+1, FILL|EXPAND, (AttachOptions) 0);
++row;
- label = manage (new Label (_("Hardware output latency (samples)")));
- label->set_alignment (1.0, 0.5);
+ label = manage (left_aligned_label (_("Hardware output latency:")));
device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+ label = manage (left_aligned_label (_("samples")));
+ device_packer.attach (*label, 2, 3, row, row+1, FILL|EXPAND, (AttachOptions) 0);
++row;
basic_hbox.pack_start (basic_packer, false, false);
{
string str;
string driver;
- bool using_oss = false;
bool using_alsa = false;
bool using_coreaudio = false;
- bool using_netjack = false;
- bool using_ffado = false;
bool using_dummy = false;
+ bool using_ffado = false;
/* 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;
+
+ double secs = 0;
uint32_t msecs;
- atof (str);
+ secs = atof (str);
msecs = (uint32_t) floor (secs * 1000.0);
- cmd.push_back ("-t");
- cmd.push_back (to_string (msecs, std::dec));
+
+ if (msecs > 0) {
+ cmd.push_back ("-t");
+ cmd.push_back (to_string (msecs, std::dec));
+ }
}
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));
cmd.push_back ("-R");
cmd.push_back ("-P");
cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
+ } else {
+ cmd.push_back ("-r"); /* override jackd's default --realtime */
}
if (unlock_memory_button.get_active()) {
if (verbose_output_button.get_active()) {
cmd.push_back ("-v");
}
-
+
/* now add fixed arguments (not user-selectable) */
cmd.push_back ("-T"); // temporary */
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")) {
- using_oss = true;
cmd.push_back ("oss");
} else if (driver == X_("CoreAudio")) {
using_coreaudio = true;
cmd.push_back ("coreaudio");
} else if (driver == X_("NetJACK")) {
- using_netjack = true;
cmd.push_back ("netjack");
+ } else if (driver == X_("FreeBoB")) {
+ cmd.push_back ("freebob");
} else if (driver == X_("FFADO")) {
using_ffado = true;
- cmd.push_back ("ffado");
+ cmd.push_back ("firewire");
} else if ( driver == X_("Dummy")) {
- using_dummy = true;
- cmd.push_back ("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 (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");
}
- if (! using_dummy ) {
- 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");
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 (get_device_name (driver, interface_combo.get_active_text()));
- }
+ cmd.push_back (device);
+ }
if (hw_meter_button.get_active()) {
cmd.push_back ("-M");
}
-
+
if (hw_monitor_button.get_active()) {
cmd.push_back ("-H");
}
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
- cmd.push_back ("-d");
- cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
-#endif
- } else if (using_oss) {
+ string device = get_device_name (driver, interface_combo.get_active_text());
+ if (device.empty()) {
+ cmd.clear ();
+ return;
+ }
- } else if (using_netjack) {
+ cmd.push_back ("-d");
+ cmd.push_back (device);
+#endif
}
}
bool
EngineControl::engine_running ()
{
+ EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
+ boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
+
+ /* revert all environment settings back to whatever they were when ardour started
+ */
+
+ if (global_epa) {
+ current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
+ global_epa->restore ();
+ }
+
jack_status_t status;
jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
build_command_line (args);
- Glib::ustring jackdrc_path = Glib::get_home_dir();
+ if (args.empty()) {
+ return 1; // try again
+ }
+
+ std::string jackdrc_path = Glib::get_home_dir();
jackdrc_path += "/.jackdrc";
ofstream jackdrc (jackdrc_path.c_str());
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 */
+ if (driver == "CoreAudio") {
#ifdef __APPLE__
- devices["CoreAudio"] = enumerate_coreaudio_devices ();
+ devices[driver] = enumerate_coreaudio_devices ();
+#endif
+
+#ifndef __APPLE__
+ } 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
- devices["ALSA"] = enumerate_alsa_devices ();
- devices["FFADO"] = enumerate_ffado_devices ();
- devices["OSS"] = enumerate_oss_devices ();
- devices["Dummy"] = enumerate_dummy_devices ();
- devices["NetJACK"] = enumerate_netjack_devices ();
+ }
#endif
}
#ifdef __APPLE__
-static OSStatus
+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)
+ if (res == noErr)
CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
CFRelease(UI);
return res;
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;
- size_t outSize = sizeof(isWritable);
+ UInt32 outSize = sizeof(isWritable);
backend_devs.clear ();
if (err == noErr) {
// Look for the CoreAudio device name...
char coreDeviceName[256];
- size_t nameSize;
+ UInt32 nameSize;
for (int i = 0; i < numCoreDevices; i++) {
// 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 (_("\
You do not have any audio devices capable of\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);
exit (1);
}
+
return devs;
}
#else
while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
- bool have_playback = false;
- bool have_capture = false;
-
- /* find duplex devices only */
-
- snd_pcm_info_set_device (pcminfo, device);
- snd_pcm_info_set_subdevice (pcminfo, 0);
- snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
-
- if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
- have_capture = true;
- }
-
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) {
- have_playback = true;
- }
-
- if (have_capture && have_playback) {
devs.push_back (snd_pcm_info_get_name (pcminfo));
devname += ',';
devname += to_string (device, std::dec);
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 ()
{
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 != "FreeBoB" && driver != "FFADO" && driver != "Dummy") {
+ return;
+ }
+
for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
if ((*i).length() > maxlen) {
maxlen = (*i).length();
- maxindex = n;
}
}
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);
force16bit_button.set_sensitive (true);
uint32_t
EngineControl::get_rate ()
{
- return atoi (sample_rate_combo.get_active_text ());
+ double 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 lrint (r);
}
void
snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
latency_label.set_text (buf);
+ latency_label.set_alignment (0, 0.5);
}
void
EngineControl::audio_mode_changed ()
{
- Glib::ustring str = audio_mode_combo.get_active_text();
+ std::string str = audio_mode_combo.get_active_text();
if (str == _("Playback/Recording on 1 Device")) {
input_device_combo.set_sensitive (false);
output_device_combo.set_sensitive (true);
} else if (str == _("Playback only")) {
output_device_combo.set_sensitive (true);
+ input_device_combo.set_sensitive (false);
} else if (str == _("Recording only")) {
input_device_combo.set_sensitive (true);
+ output_device_combo.set_sensitive (false);
}
}
-static bool jack_server_filter(const string& str, void *arg)
+static bool jack_server_filter(const string& str, void */*arg*/)
{
return str == "jackd" || str == "jackdmp";
}
/* 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);
-
- 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);
- }
+ }
if (getenv ("ARDOUR_WITH_JACK")) {
/* no other options - only use the JACK we supply */
if (strings.empty()) {
- fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
+ 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;
-
- path = getenv ("PATH");
+ 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);
}
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;
}
-
+
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()) {
- 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();
}
{
XMLNode* root = new XMLNode ("AudioSetup");
XMLNode* child;
- Glib::ustring path;
+ std::string path;
child = new XMLNode ("periods");
child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
root->add_child_nocopy (*child);
- child = new XMLNode ("inchannels");
- child->add_property ("val", to_string (input_channels.get_value(), std::dec));
- root->add_child_nocopy (*child);
-
- child = new XMLNode ("outchannels");
- child->add_property ("val", to_string (output_channels.get_value(), std::dec));
- root->add_child_nocopy (*child);
-
child = new XMLNode ("inlatency");
child->add_property ("val", to_string (input_latency.get_value(), std::dec));
root->add_child_nocopy (*child);
child = new XMLNode ("outputdevice");
child->add_property ("val", output_device_combo.get_active_text());
root->add_child_nocopy (*child);
-
+
+ child = new XMLNode ("mididriver");
+ child->add_property ("val", midi_driver_combo.get_active_text());
+ root->add_child_nocopy (*child);
+
return *root;
}
XMLNodeList clist;
XMLNodeConstIterator citer;
XMLNode* child;
- XMLProperty* prop;
-
- bool using_dummy = false;
+ XMLProperty* prop = NULL;
+ bool using_dummy = false;
+ bool using_ffado = false;
int val;
string strval;
- if ( (child = root.child("driver"))){
- prop = child->property("val");
- if (prop && (prop->value() == "Dummy") ) {
- using_dummy = true;
- }
- }
+ if ( (child = root.child ("driver"))){
+ prop = child->property("val");
+
+ if (prop && (prop->value() == "Dummy") ) {
+ using_dummy = true;
+ }
+ if (prop && (prop->value() == "FFADO") ) {
+ using_ffado = true;
+ }
+
+ }
clist = root.children();
prop = child->property ("val");
if (!prop || prop->value().empty()) {
- if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
- continue;
+
+ if (((using_dummy || using_ffado)
+ && ( child->name() == "interface"
+ || child->name() == "inputdevice"
+ || child->name() == "outputdevice"))
+ || child->name() == "timeout")
+ {
+ continue;
+ }
+
error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
continue;
}
-
+
strval = prop->value();
/* adjustments/spinners */
} else if (child->name() == "ports") {
val = atoi (strval);
ports_adjustment.set_value(val);
- } else if (child->name() == "inchannels") {
- val = atoi (strval);
- input_channels.set_value(val);
- } else if (child->name() == "outchannels") {
- val = atoi (strval);
- output_channels.set_value(val);
} else if (child->name() == "inlatency") {
val = atoi (strval);
input_latency.set_value(val);
} else if (child->name() == "periodsize") {
period_size_combo.set_active_text(strval);
} else if (child->name() == "serverpath") {
- /* do not allow us to use a server path that doesn't
- exist on this system. this handles cases where
- the user has an RC file listing a serverpath
- from some other machine.
- */
- vector<string>::iterator x;
- for (x = server_strings.begin(); x != server_strings.end(); ++x) {
- if (*x == strval) {
- break;
- }
- }
- if (x != server_strings.end()) {
- serverpath_combo.set_active_text (strval);
- } else {
- warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
- strval)
- << endmsg;
- }
+
+ /* only attempt to set this if we have bothered to look
+ up server names already. otherwise this is all
+ redundant (actually, all of this dialog/widget
+ is redundant in that case ...)
+ */
+
+ if (!server_strings.empty()) {
+ /* do not allow us to use a server path that doesn't
+ exist on this system. this handles cases where
+ the user has an RC file listing a serverpath
+ from some other machine.
+ */
+ vector<string>::iterator x;
+ for (x = server_strings.begin(); x != server_strings.end(); ++x) {
+ if (*x == strval) {
+ break;
+ }
+ }
+ if (x != server_strings.end()) {
+ serverpath_combo.set_active_text (strval);
+ } else {
+ warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
+ strval)
+ << endmsg;
+ }
+ }
+
} else if (child->name() == "driver") {
driver_combo.set_active_text(strval);
} else if (child->name() == "interface") {
input_device_combo.set_active_text(strval);
} else if (child->name() == "outputdevice") {
output_device_combo.set_active_text(strval);
+ } else if (child->name() == "mididriver") {
+ midi_driver_combo.set_active_text(strval);
}
}
}