ALSA: allow to dynamically add/remove midi devices & update their latency.
This commit is contained in:
parent
ac075560bd
commit
bfd2cbaa3f
|
@ -70,6 +70,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
|||
, _dsp_load (0)
|
||||
, _processed_samples (0)
|
||||
, _port_change_flag (false)
|
||||
, _midi_ins (0)
|
||||
, _midi_outs (0)
|
||||
{
|
||||
_instance_name = s_instance_name;
|
||||
pthread_mutex_init (&_port_callback_mutex, 0);
|
||||
|
@ -544,19 +546,27 @@ AlsaAudioBackend::update_systemic_audio_latencies ()
|
|||
void
|
||||
AlsaAudioBackend::update_systemic_midi_latencies ()
|
||||
{
|
||||
#if 0
|
||||
// TODO, need a way to associate the port with the corresponding AlsaMidiDeviceInfo
|
||||
for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
|
||||
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);
|
||||
}
|
||||
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) {
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
update_latencies ();
|
||||
}
|
||||
|
||||
|
@ -712,6 +722,9 @@ AlsaAudioBackend::set_midi_option (const std::string& opt)
|
|||
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;
|
||||
}
|
||||
|
@ -727,8 +740,41 @@ AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable
|
|||
{
|
||||
struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
|
||||
if (!nfo) return -1;
|
||||
const bool prev_enabled = nfo->enabled;
|
||||
nfo->enabled = enable;
|
||||
// TODO - trigger update when already running
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -909,6 +955,7 @@ AlsaAudioBackend::_start (bool for_latency_measurement)
|
|||
|
||||
_measure_latency = for_latency_measurement;
|
||||
|
||||
_midi_ins = _midi_outs = 0;
|
||||
register_system_midi_ports();
|
||||
|
||||
if (register_system_audio_ports()) {
|
||||
|
@ -990,6 +1037,7 @@ AlsaAudioBackend::stop ()
|
|||
|
||||
unregister_ports();
|
||||
delete _pcmi; _pcmi = 0;
|
||||
_midi_ins = _midi_outs = 0;
|
||||
release_device();
|
||||
|
||||
return (_active == false) ? 0 : -1;
|
||||
|
@ -1312,11 +1360,11 @@ AlsaAudioBackend::register_system_audio_ports()
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -1327,15 +1375,18 @@ AlsaAudioBackend::register_system_midi_ports()
|
|||
}
|
||||
|
||||
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 ()) {
|
||||
|
@ -1353,7 +1404,7 @@ AlsaAudioBackend::register_system_midi_ports()
|
|||
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();
|
||||
|
@ -1370,9 +1421,9 @@ AlsaAudioBackend::register_system_midi_ports()
|
|||
|
||||
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 ()) {
|
||||
|
@ -1390,7 +1441,7 @@ AlsaAudioBackend::register_system_midi_ports()
|
|||
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();
|
||||
|
|
|
@ -395,7 +395,7 @@ class AlsaAudioBackend : public AudioBackend {
|
|||
/* port engine */
|
||||
PortHandle add_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags);
|
||||
int register_system_audio_ports ();
|
||||
int register_system_midi_ports ();
|
||||
int register_system_midi_ports (const std::string device = "");
|
||||
void unregister_ports (bool system_only = false);
|
||||
|
||||
std::vector<AlsaPort *> _ports;
|
||||
|
@ -407,6 +407,9 @@ class AlsaAudioBackend : public AudioBackend {
|
|||
std::vector<AlsaMidiOut *> _rmidi_out;
|
||||
std::vector<AlsaMidiIn *> _rmidi_in;
|
||||
|
||||
unsigned _midi_ins;
|
||||
unsigned _midi_outs;
|
||||
|
||||
struct PortConnectData {
|
||||
std::string a;
|
||||
std::string b;
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
|
||||
virtual void* main_process_thread () = 0;
|
||||
|
||||
const std::string & name () const { return _name; }
|
||||
|
||||
protected:
|
||||
pthread_t _main_thread;
|
||||
pthread_mutex_t _notify_mutex;
|
||||
|
@ -68,7 +70,8 @@ protected:
|
|||
|
||||
RingBuffer<uint8_t>* _rb;
|
||||
|
||||
protected:
|
||||
std::string _name;
|
||||
|
||||
virtual void init (const char *device_name, const bool input) = 0;
|
||||
|
||||
};
|
||||
|
|
|
@ -38,10 +38,11 @@ using namespace ARDOUR;
|
|||
#define _DEBUGPRINT(STR) ;
|
||||
#endif
|
||||
|
||||
AlsaRawMidiIO::AlsaRawMidiIO (const char *device, const bool input)
|
||||
AlsaRawMidiIO::AlsaRawMidiIO (const std::string &name, const char *device, const bool input)
|
||||
: AlsaMidiIO()
|
||||
, _device (0)
|
||||
{
|
||||
_name = name;
|
||||
init (device, input);
|
||||
}
|
||||
|
||||
|
@ -107,8 +108,8 @@ initerr:
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AlsaRawMidiOut::AlsaRawMidiOut (const char *device)
|
||||
: AlsaRawMidiIO (device, false)
|
||||
AlsaRawMidiOut::AlsaRawMidiOut (const std::string &name, const char *device)
|
||||
: AlsaRawMidiIO (name, device, false)
|
||||
, AlsaMidiOut ()
|
||||
{
|
||||
}
|
||||
|
@ -223,8 +224,8 @@ retry:
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AlsaRawMidiIn::AlsaRawMidiIn (const char *device)
|
||||
: AlsaRawMidiIO (device, true)
|
||||
AlsaRawMidiIn::AlsaRawMidiIn (const std::string &name, const char *device)
|
||||
: AlsaRawMidiIO (name, device, true)
|
||||
, AlsaMidiIn ()
|
||||
, _event(0,0)
|
||||
, _first_time(true)
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace ARDOUR {
|
|||
|
||||
class AlsaRawMidiIO : virtual public AlsaMidiIO {
|
||||
public:
|
||||
AlsaRawMidiIO (const char *device, const bool input);
|
||||
AlsaRawMidiIO (const std::string &name, const char *device, const bool input);
|
||||
virtual ~AlsaRawMidiIO ();
|
||||
|
||||
protected:
|
||||
|
@ -46,14 +46,14 @@ private:
|
|||
class AlsaRawMidiOut : public AlsaRawMidiIO, public AlsaMidiOut
|
||||
{
|
||||
public:
|
||||
AlsaRawMidiOut (const char *device);
|
||||
AlsaRawMidiOut (const std::string &name, const char *device);
|
||||
void* main_process_thread ();
|
||||
};
|
||||
|
||||
class AlsaRawMidiIn : public AlsaRawMidiIO, public AlsaMidiIn
|
||||
{
|
||||
public:
|
||||
AlsaRawMidiIn (const char *device);
|
||||
AlsaRawMidiIn (const std::string &name, const char *device);
|
||||
|
||||
void* main_process_thread ();
|
||||
|
||||
|
|
|
@ -37,10 +37,11 @@ using namespace ARDOUR;
|
|||
#define _DEBUGPRINT(STR) ;
|
||||
#endif
|
||||
|
||||
AlsaSeqMidiIO::AlsaSeqMidiIO (const char *device, const bool input)
|
||||
AlsaSeqMidiIO::AlsaSeqMidiIO (const std::string &name, const char *device, const bool input)
|
||||
: AlsaMidiIO()
|
||||
, _seq (0)
|
||||
{
|
||||
_name = name;
|
||||
init (device, input);
|
||||
}
|
||||
|
||||
|
@ -117,8 +118,8 @@ initerr:
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AlsaSeqMidiOut::AlsaSeqMidiOut (const char *device)
|
||||
: AlsaSeqMidiIO (device, false)
|
||||
AlsaSeqMidiOut::AlsaSeqMidiOut (const std::string &name, const char *device)
|
||||
: AlsaSeqMidiIO (name, device, false)
|
||||
, AlsaMidiOut ()
|
||||
{
|
||||
}
|
||||
|
@ -227,8 +228,8 @@ retry:
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AlsaSeqMidiIn::AlsaSeqMidiIn (const char *device)
|
||||
: AlsaSeqMidiIO (device, true)
|
||||
AlsaSeqMidiIn::AlsaSeqMidiIn (const std::string &name, const char *device)
|
||||
: AlsaSeqMidiIO (name, device, true)
|
||||
, AlsaMidiIn ()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace ARDOUR {
|
|||
|
||||
class AlsaSeqMidiIO : virtual public AlsaMidiIO {
|
||||
public:
|
||||
AlsaSeqMidiIO (const char *port_name, const bool input);
|
||||
AlsaSeqMidiIO (const std::string &name, const char *port_name, const bool input);
|
||||
virtual ~AlsaSeqMidiIO ();
|
||||
|
||||
protected:
|
||||
|
@ -47,14 +47,14 @@ private:
|
|||
class AlsaSeqMidiOut : public AlsaSeqMidiIO, public AlsaMidiOut
|
||||
{
|
||||
public:
|
||||
AlsaSeqMidiOut (const char *port_name);
|
||||
AlsaSeqMidiOut (const std::string &name, const char *port_name);
|
||||
void* main_process_thread ();
|
||||
};
|
||||
|
||||
class AlsaSeqMidiIn : public AlsaSeqMidiIO, public AlsaMidiIn
|
||||
{
|
||||
public:
|
||||
AlsaSeqMidiIn (const char *port_name);
|
||||
AlsaSeqMidiIn (const std::string &name, const char *port_name);
|
||||
|
||||
void* main_process_thread ();
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue