, _systemic_audio_output_latency (0)
, _dsp_load (0)
, _processed_samples (0)
+ , _midi_ins (0)
+ , _midi_outs (0)
, _port_change_flag (false)
{
_instance_name = s_instance_name;
return 128;
}
+std::vector<uint32_t>
+AlsaAudioBackend::available_period_sizes (const std::string& driver) const
+{
+ std::vector<uint32_t> ps;
+ ps.push_back (2);
+ ps.push_back (3);
+ return ps;
+}
+
bool
AlsaAudioBackend::can_change_sample_rate_when_running () const
{
return 0;
}
+int
+AlsaAudioBackend::set_peridod_size (uint32_t n)
+{
+ if (n == 0 || n > 3) {
+ return -1;
+ }
+ if (_run) {
+ return -1;
+ }
+ _periods_per_cycle = n;
+ return 0;
+}
+
int
AlsaAudioBackend::set_buffer_size (uint32_t bs)
{
AlsaAudioBackend::set_systemic_input_latency (uint32_t sl)
{
_systemic_audio_input_latency = sl;
+ if (_run) {
+ update_systemic_audio_latencies();
+ }
return 0;
}
AlsaAudioBackend::set_systemic_output_latency (uint32_t sl)
{
_systemic_audio_output_latency = sl;
+ if (_run) {
+ update_systemic_audio_latencies();
+ }
return 0;
}
struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
if (!nfo) return -1;
nfo->systemic_input_latency = sl;
+ if (_run && nfo->enabled) {
+ update_systemic_midi_latencies ();
+ }
return 0;
}
struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
if (!nfo) return -1;
nfo->systemic_output_latency = sl;
+ if (_run && nfo->enabled) {
+ update_systemic_midi_latencies ();
+ }
return 0;
}
+void
+AlsaAudioBackend::update_systemic_audio_latencies ()
+{
+ const uint32_t lcpp = (_periods_per_cycle - 2) * _samples_per_period;
+ LatencyRange lr;
+
+ lr.min = lr.max = lcpp + (_measure_latency ? 0 : _systemic_audio_input_latency);
+ for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
+ set_latency_range (*it, true, lr);
+ }
+
+ lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_output_latency);
+ for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
+ set_latency_range (*it, false, lr);
+ }
+ update_latencies ();
+}
+
+void
+AlsaAudioBackend::update_systemic_midi_latencies ()
+{
+ uint32_t i = 0;
+ for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
+ assert (_rmidi_out.size() > i);
+ AlsaMidiOut *rm = _rmidi_out.at(i);
+ struct AlsaMidiDeviceInfo * nfo = midi_device_info (rm->name());
+ assert (nfo);
+ LatencyRange lr;
+ lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_output_latency);
+ set_latency_range (*it, false, lr);
+ }
+
+ i = 0;
+ for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
+ assert (_rmidi_in.size() > i);
+ AlsaMidiIO *rm = _rmidi_in.at(i);
+ struct AlsaMidiDeviceInfo * nfo = midi_device_info (rm->name());
+ assert (nfo);
+ LatencyRange lr;
+ lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
+ set_latency_range (*it, true, lr);
+ }
+ update_latencies ();
+}
+
/* Retrieving parameters */
std::string
AlsaAudioBackend::device_name () const
return _samples_per_period;
}
+uint32_t
+AlsaAudioBackend::period_size () const
+{
+ return _periods_per_cycle;
+}
+
bool
AlsaAudioBackend::interleaved () const
{
if (opt != get_standard_device_name(DeviceNone) && opt != _("ALSA raw devices") && opt != _("ALSA sequencer")) {
return -1;
}
+ if (_run && _midi_driver_option != opt) {
+ return -1;
+ }
_midi_driver_option = opt;
return 0;
}
{
struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
if (!nfo) return -1;
+ const bool prev_enabled = nfo->enabled;
nfo->enabled = enable;
+
+ if (_run && prev_enabled != enable) {
+ if (enable) {
+ // add ports for the given device
+ register_system_midi_ports(device);
+ } else {
+ // remove all ports provided by the given device
+ uint32_t i = 0;
+ for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end ();) {
+ assert (_rmidi_out.size() > i);
+ AlsaMidiOut *rm = _rmidi_out.at(i);
+ if (rm->name () != device) { ++it; ++i; continue; }
+ it = _system_midi_out.erase (it);
+ unregister_port (*it);
+ rm->stop();
+ _rmidi_out.erase (_rmidi_out.begin() + i);
+ delete rm;
+ }
+
+ i = 0;
+ for (std::vector<AlsaPort*>::iterator it = _system_midi_in.begin (); it != _system_midi_in.end ();) {
+ assert (_rmidi_in.size() > i);
+ AlsaMidiIn *rm = _rmidi_in.at(i);
+ if (rm->name () != device) { ++it; ++i; continue; }
+ it = _system_midi_in.erase (it);
+ unregister_port (*it);
+ rm->stop();
+ _rmidi_in.erase (_rmidi_in.begin() + i);
+ delete rm;
+ }
+ }
+ update_systemic_midi_latencies ();
+ }
return 0;
}
if (_active || _run) {
PBD::error << _("AlsaAudioBackend: already active.") << endmsg;
- return -1;
+ return BackendReinitializationError;
}
if (_ports.size()) {
if (_input_audio_device == get_standard_device_name(DeviceNone) && _output_audio_device == get_standard_device_name(DeviceNone)) {
PBD::error << _("AlsaAudioBackend: At least one of input or output device needs to be set.");
- return -1;
+ return AudioDeviceInvalidError;
}
if (_input_audio_device != _output_audio_device) {
if (_input_audio_device != get_standard_device_name(DeviceNone) && _output_audio_device != get_standard_device_name(DeviceNone)) {
PBD::error << _("AlsaAudioBackend: Cannot use two different devices.");
- return -1;
+ return AudioDeviceInvalidError;
}
if (_input_audio_device != get_standard_device_name(DeviceNone)) {
get_alsa_audio_device_names(devices, HalfDuplexIn);
}
if (alsa_device == "") {
PBD::error << _("AlsaAudioBackend: Cannot find configured device. Is it still connected?");
- return -1;
+ return AudioDeviceNotAvailableError;
}
acquire_device(alsa_device.c_str());
_pcmi = new Alsa_pcmi (
(duplex & 2) ? alsa_device.c_str() : NULL,
(duplex & 1) ? alsa_device.c_str() : NULL,
- 0, _samplerate, _samples_per_period, _periods_per_cycle, 0);
- switch (_pcmi->state ()) {
- case 0: /* OK */ break;
- case -1: PBD::error << _("AlsaAudioBackend: failed to open device.") << endmsg; break;
- case -2: PBD::error << _("AlsaAudioBackend: failed to allocate parameters.") << endmsg; break;
- case -3: PBD::error << _("AlsaAudioBackend: cannot set requested sample rate.") << endmsg; break;
- case -4: PBD::error << _("AlsaAudioBackend: cannot set requested period size.") << endmsg; break;
- case -5: PBD::error << _("AlsaAudioBackend: cannot set requested number of periods.") << endmsg; break;
- case -6: PBD::error << _("AlsaAudioBackend: unsupported sample format.") << endmsg; break;
- default: PBD::error << _("AlsaAudioBackend: initialization failed.") << endmsg; break;
+ /* ctrl name */ 0,
+ _samplerate, _samples_per_period,
+ _periods_per_cycle, /* _periods_per_cycle */ 2,
+ /* debug */ 0);
+
+ AudioBackend::ErrorCode error_code = NoError;
+ switch (_pcmi->state()) {
+ case 0: /* OK */
+ break;
+ case -1:
+ PBD::error << _("AlsaAudioBackend: failed to open device.") << endmsg;
+ error_code = AudioDeviceOpenError;
+ break;
+ case -2:
+ PBD::error << _("AlsaAudioBackend: failed to allocate parameters.") << endmsg;
+ error_code = AudioDeviceOpenError;
+ break;
+ case -3:
+ PBD::error << _("AlsaAudioBackend: cannot set requested sample rate.")
+ << endmsg;
+ error_code = SampleRateNotSupportedError;
+ break;
+ case -4:
+ PBD::error << _("AlsaAudioBackend: cannot set requested period size.")
+ << endmsg;
+ error_code = PeriodSizeNotSupportedError;
+ break;
+ case -5:
+ PBD::error << _("AlsaAudioBackend: cannot set requested number of periods.")
+ << endmsg;
+ error_code = PeriodCountNotSupportedError;
+ break;
+ case -6:
+ PBD::error << _("AlsaAudioBackend: unsupported sample format.") << endmsg;
+ error_code = SampleFormatNotSupportedError;
+ break;
+ default:
+ PBD::error << _("AlsaAudioBackend: initialization failed.") << endmsg;
+ error_code = AudioDeviceOpenError;
+ break;
}
+
if (_pcmi->state ()) {
delete _pcmi; _pcmi = 0;
release_device();
- return -1;
+ return error_code;
}
#ifndef NDEBUG
_measure_latency = for_latency_measurement;
+ _midi_ins = _midi_outs = 0;
register_system_midi_ports();
if (register_system_audio_ports()) {
PBD::error << _("AlsaAudioBackend: failed to register system ports.") << endmsg;
delete _pcmi; _pcmi = 0;
release_device();
- return -1;
+ return PortRegistrationError;
}
engine.sample_rate_change (_samplerate);
engine.buffer_size_change (_samples_per_period);
- _dsp_load_calc.set_max_time(_samplerate, _samples_per_period);
-
if (engine.reestablish_ports ()) {
PBD::error << _("AlsaAudioBackend: Could not re-establish ports.") << endmsg;
delete _pcmi; _pcmi = 0;
release_device();
- return -1;
+ return PortReconnectError;
}
engine.reconnect_ports ();
delete _pcmi; _pcmi = 0;
release_device();
_run = false;
- return -1;
+ return ProcessThreadStartError;
} else {
PBD::warning << _("AlsaAudioBackend: cannot acquire realtime permissions.") << endmsg;
}
delete _pcmi; _pcmi = 0;
release_device();
_run = false;
- return -1;
+ return ProcessThreadStartError;
}
- return 0;
+ return NoError;
}
int
unregister_ports();
delete _pcmi; _pcmi = 0;
+ _midi_ins = _midi_outs = 0;
release_device();
return (_active == false) ? 0 : -1;
float
AlsaAudioBackend::dsp_load () const
{
- return std::min(100.f, 100.f * _dsp_load);
+ return 100.f * _dsp_load;
}
size_t
AlsaAudioBackend::get_port_name (PortEngine::PortHandle port) const
{
if (!valid_port (port)) {
- PBD::error << _("AlsaBackend::get_port_name: Invalid Port(s)") << endmsg;
+ PBD::warning << _("AlsaBackend::get_port_name: Invalid Port(s)") << endmsg;
return std::string ();
}
return static_cast<AlsaPort*>(port)->name ();
}
+int
+AlsaAudioBackend::get_port_property (PortHandle port, const std::string& key, std::string& value, std::string& type) const
+{
+ if (!valid_port (port)) {
+ PBD::warning << _("AlsaBackend::get_port_property: Invalid Port(s)") << endmsg;
+ return -1;
+ }
+ if (key == "http://jackaudio.org/metadata/pretty-name") {
+ type = "";
+ value = static_cast<AlsaPort*>(port)->pretty_name ();
+ if (!value.empty()) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+AlsaAudioBackend::set_port_property (PortHandle port, const std::string& key, const std::string& value, const std::string& type)
+{
+ if (!valid_port (port)) {
+ PBD::warning << _("AlsaBackend::set_port_property: Invalid Port(s)") << endmsg;
+ return -1;
+ }
+ if (key == "http://jackaudio.org/metadata/pretty-name" && type.empty ()) {
+ static_cast<AlsaPort*>(port)->set_pretty_name (value);
+ return 0;
+ }
+ return -1;
+}
+
PortEngine::PortHandle
AlsaAudioBackend::get_port_by_name (const std::string& name) const
{
const int a_ins = _n_inputs;
const int a_out = _n_outputs;
+ const uint32_t lcpp = (_periods_per_cycle - 2) * _samples_per_period;
+
/* audio ports */
lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_input_latency);
for (int i = 1; i <= a_ins; ++i) {
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
if (!p) return -1;
set_latency_range (p, false, lr);
- _system_inputs.push_back(static_cast<AlsaPort*>(p));
+ AlsaPort *ap = static_cast<AlsaPort*>(p);
+ //ap->set_pretty_name ("")
+ _system_inputs.push_back (ap);
}
- lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_output_latency);
+ lr.min = lr.max = lcpp + (_measure_latency ? 0 : _systemic_audio_output_latency);
for (int i = 1; i <= a_out; ++i) {
char tmp[64];
snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
if (!p) return -1;
set_latency_range (p, true, lr);
- _system_outputs.push_back(static_cast<AlsaPort*>(p));
+ AlsaPort *ap = static_cast<AlsaPort*>(p);
+ //ap->set_pretty_name ("")
+ _system_outputs.push_back (ap);
}
return 0;
}
int
-AlsaAudioBackend::register_system_midi_ports()
+AlsaAudioBackend::register_system_midi_ports(const std::string device)
{
std::map<std::string, std::string> devices;
- int midi_ins = 0;
- int midi_outs = 0;
+
+ // TODO use consistent numbering when re-adding devices: _midi_ins, _midi_outs
if (_midi_driver_option == get_standard_device_name(DeviceNone)) {
return 0;
}
for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
+ if (!device.empty() && device != i->first) {
+ continue;
+ }
struct AlsaMidiDeviceInfo * nfo = midi_device_info(i->first);
if (!nfo) continue;
if (!nfo->enabled) continue;
AlsaMidiOut *mout;
if (_midi_driver_option == _("ALSA raw devices")) {
- mout = new AlsaRawMidiOut (i->second.c_str());
+ mout = new AlsaRawMidiOut (i->first, i->second.c_str());
} else {
- mout = new AlsaSeqMidiOut (i->second.c_str());
+ mout = new AlsaSeqMidiOut (i->first, i->second.c_str());
}
if (mout->state ()) {
delete mout;
} else {
char tmp[64];
- snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++midi_ins);
+ snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++_midi_ins);
PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
if (!p) {
mout->stop();
}
LatencyRange lr;
lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_output_latency);
- set_latency_range (p, false, lr);
- static_cast<AlsaMidiPort*>(p)->set_n_periods(2);
- _system_midi_out.push_back(static_cast<AlsaPort*>(p));
+ set_latency_range (p, true, lr);
+ static_cast<AlsaMidiPort*>(p)->set_n_periods(_periods_per_cycle); // TODO check MIDI alignment
+ AlsaPort *ap = static_cast<AlsaPort*>(p);
+ ap->set_pretty_name (i->first);
+ _system_midi_out.push_back (ap);
_rmidi_out.push_back (mout);
}
}
AlsaMidiIn *midin;
if (_midi_driver_option == _("ALSA raw devices")) {
- midin = new AlsaRawMidiIn (i->second.c_str());
+ midin = new AlsaRawMidiIn (i->first, i->second.c_str());
} else {
- midin = new AlsaSeqMidiIn (i->second.c_str());
+ midin = new AlsaSeqMidiIn (i->first, i->second.c_str());
}
if (midin->state ()) {
delete midin;
} else {
char tmp[64];
- snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++midi_outs);
+ snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++_midi_outs);
PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
if (!p) {
midin->stop();
LatencyRange lr;
lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
set_latency_range (p, false, lr);
- _system_midi_in.push_back(static_cast<AlsaPort*>(p));
+ AlsaPort *ap = static_cast<AlsaPort*>(p);
+ ap->set_pretty_name (i->first);
+ _system_midi_in.push_back (ap);
_rmidi_in.push_back (midin);
}
}
nr -= _samples_per_period;
_processed_samples += _samples_per_period;
+ _dsp_load_calc.set_max_time(_samplerate, _samples_per_period);
_dsp_load_calc.set_start_timestamp_us (clock1);
_dsp_load_calc.set_stop_timestamp_us (g_get_monotonic_time());
_dsp_load = _dsp_load_calc.get_dsp_load ();