mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 08:36:32 +01:00
Dynamic ALSA MIDI I/O device discovery and re/connect
This commit is contained in:
parent
2d87af1988
commit
79e247e00a
2 changed files with 152 additions and 2 deletions
|
|
@ -71,6 +71,7 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
||||||
, _n_outputs (0)
|
, _n_outputs (0)
|
||||||
, _systemic_audio_input_latency (0)
|
, _systemic_audio_input_latency (0)
|
||||||
, _systemic_audio_output_latency (0)
|
, _systemic_audio_output_latency (0)
|
||||||
|
, _midi_device_thread_active (false)
|
||||||
, _dsp_load (0)
|
, _dsp_load (0)
|
||||||
, _processed_samples (0)
|
, _processed_samples (0)
|
||||||
, _port_change_flag (false)
|
, _port_change_flag (false)
|
||||||
|
|
@ -947,6 +948,8 @@ AlsaAudioBackend::_start (bool for_latency_measurement)
|
||||||
return ProcessThreadStartError;
|
return ProcessThreadStartError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_midi_device_thread_active = listen_for_midi_device_changes ();
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
if (NULL != getenv ("ALSAEXT")) {
|
if (NULL != getenv ("ALSAEXT")) {
|
||||||
boost::char_separator<char> sep (";");
|
boost::char_separator<char> sep (";");
|
||||||
|
|
@ -992,6 +995,8 @@ AlsaAudioBackend::stop ()
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop_listen_for_midi_device_changes ();
|
||||||
|
|
||||||
while (!_rmidi_out.empty ()) {
|
while (!_rmidi_out.empty ()) {
|
||||||
AlsaMidiIO *m = _rmidi_out.back ();
|
AlsaMidiIO *m = _rmidi_out.back ();
|
||||||
m->stop();
|
m->stop();
|
||||||
|
|
@ -1386,6 +1391,142 @@ AlsaAudioBackend::register_system_audio_ports()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AlsaAudioBackend::auto_update_midi_devices ()
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> devices;
|
||||||
|
if (_midi_driver_option == _("ALSA raw devices")) {
|
||||||
|
get_alsa_rawmidi_device_names (devices);
|
||||||
|
} else if (_midi_driver_option == _("ALSA sequencer")) {
|
||||||
|
get_alsa_sequencer_names (devices);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find new devices */
|
||||||
|
for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
|
||||||
|
if (_midi_devices.find (i->first) != _midi_devices.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf ("NEW MIDI DEVICE %s", i->first.c_str());
|
||||||
|
_midi_devices[i->first] = new AlsaMidiDeviceInfo (false);
|
||||||
|
set_midi_device_enabled (i->first, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::map<std::string, struct AlsaMidiDeviceInfo*>::iterator i = _midi_devices.begin (); i != _midi_devices.end(); ) {
|
||||||
|
if (devices.find (i->first) != devices.end()) {
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf ("REMOVE MIDI DEVICE %s", i->first.c_str());
|
||||||
|
set_midi_device_enabled (i->first, false);
|
||||||
|
i = _midi_devices.erase (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
AlsaAudioBackend::_midi_device_thread (void* arg)
|
||||||
|
{
|
||||||
|
AlsaAudioBackend* self = static_cast<AlsaAudioBackend*>(arg);
|
||||||
|
self->midi_device_thread ();
|
||||||
|
pthread_exit (0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AlsaAudioBackend::midi_device_thread ()
|
||||||
|
{
|
||||||
|
snd_seq_t* seq;
|
||||||
|
if (snd_seq_open (&seq, "hw", SND_SEQ_OPEN_INPUT, 0) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (snd_seq_set_client_name (seq, "Ardour")) {
|
||||||
|
snd_seq_close (seq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (snd_seq_nonblock (seq, 1) < 0) {
|
||||||
|
snd_seq_close (seq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int npfds = snd_seq_poll_descriptors_count (seq, POLLIN);
|
||||||
|
if (npfds < 1) {
|
||||||
|
snd_seq_close (seq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = snd_seq_create_simple_port (seq, "port", SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT, SND_SEQ_PORT_TYPE_APPLICATION);
|
||||||
|
snd_seq_connect_from (seq, port, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
|
||||||
|
|
||||||
|
struct pollfd* pfds = (struct pollfd*) malloc (npfds * sizeof(struct pollfd));
|
||||||
|
snd_seq_poll_descriptors (seq, pfds, npfds, POLLIN);
|
||||||
|
snd_seq_drop_input (seq);
|
||||||
|
|
||||||
|
bool do_poll = true;
|
||||||
|
while (_run) {
|
||||||
|
if (do_poll) {
|
||||||
|
int perr = poll (pfds, npfds, 200 /* ms */);
|
||||||
|
if (perr == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (perr < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_seq_event_t *event;
|
||||||
|
ssize_t err = snd_seq_event_input (seq, &event);
|
||||||
|
#if EAGAIN == EWOULDBLOCK
|
||||||
|
if ((err == -EAGAIN) || (err == -ENOSPC))
|
||||||
|
#else
|
||||||
|
if ((err == -EAGAIN) || (err == -EWOULDBLOCK) || (err == -ENOSPC))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
do_poll = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (err < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (event->source.client == SND_SEQ_CLIENT_SYSTEM);
|
||||||
|
|
||||||
|
const snd_seq_addr_t addr = event->data.addr;
|
||||||
|
switch (event->type) {
|
||||||
|
case SND_SEQ_EVENT_PORT_START:
|
||||||
|
case SND_SEQ_EVENT_PORT_EXIT:
|
||||||
|
case SND_SEQ_EVENT_PORT_CHANGE:
|
||||||
|
auto_update_midi_devices ();
|
||||||
|
engine.request_device_list_update();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
do_poll = (0 == err);
|
||||||
|
}
|
||||||
|
free (pfds);
|
||||||
|
snd_seq_delete_simple_port (seq, port);
|
||||||
|
snd_seq_close (seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AlsaAudioBackend::listen_for_midi_device_changes ()
|
||||||
|
{
|
||||||
|
if (pthread_create (&_midi_device_thread_id, NULL, _midi_device_thread, this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AlsaAudioBackend::stop_listen_for_midi_device_changes ()
|
||||||
|
{
|
||||||
|
if (!_midi_device_thread_active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pthread_join (_midi_device_thread_id, NULL);
|
||||||
|
_midi_device_thread_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* set playback-latency for _system_inputs
|
/* set playback-latency for _system_inputs
|
||||||
* and capture-latency for _system_outputs
|
* and capture-latency for _system_outputs
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -374,8 +374,8 @@ class AlsaAudioBackend : public AudioBackend {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
uint32_t systemic_input_latency;
|
uint32_t systemic_input_latency;
|
||||||
uint32_t systemic_output_latency;
|
uint32_t systemic_output_latency;
|
||||||
AlsaMidiDeviceInfo()
|
AlsaMidiDeviceInfo (bool en = true)
|
||||||
: enabled (true)
|
: enabled (en)
|
||||||
, systemic_input_latency (0)
|
, systemic_input_latency (0)
|
||||||
, systemic_output_latency (0)
|
, systemic_output_latency (0)
|
||||||
{}
|
{}
|
||||||
|
|
@ -384,6 +384,15 @@ class AlsaAudioBackend : public AudioBackend {
|
||||||
mutable std::map<std::string, struct AlsaMidiDeviceInfo *> _midi_devices;
|
mutable std::map<std::string, struct AlsaMidiDeviceInfo *> _midi_devices;
|
||||||
struct AlsaMidiDeviceInfo * midi_device_info(std::string const) const;
|
struct AlsaMidiDeviceInfo * midi_device_info(std::string const) const;
|
||||||
|
|
||||||
|
/* midi device changes */
|
||||||
|
void auto_update_midi_devices();
|
||||||
|
bool listen_for_midi_device_changes ();
|
||||||
|
void stop_listen_for_midi_device_changes ();
|
||||||
|
void midi_device_thread ();
|
||||||
|
static void* _midi_device_thread (void *arg);
|
||||||
|
pthread_t _midi_device_thread_id;
|
||||||
|
bool _midi_device_thread_active;
|
||||||
|
|
||||||
/* processing */
|
/* processing */
|
||||||
float _dsp_load;
|
float _dsp_load;
|
||||||
ARDOUR::DSPLoadCalculator _dsp_load_calc;
|
ARDOUR::DSPLoadCalculator _dsp_load_calc;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue