Implement MIDI device enumeration and latency offset/calibration in portaudio backend
This commit is contained in:
parent
d54a320374
commit
b2cf028fcb
20
libs/backends/portaudio/midi_device_info.h
Normal file
20
libs/backends/portaudio/midi_device_info.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef MIDI_DEVICE_INFO_H
|
||||
#define MIDI_DEVICE_INFO_H
|
||||
|
||||
/* midi settings */
|
||||
struct MidiDeviceInfo {
|
||||
MidiDeviceInfo(const std::string& dev_name)
|
||||
: device_name(dev_name)
|
||||
, enable(true)
|
||||
, systemic_input_latency(0)
|
||||
, systemic_output_latency(0)
|
||||
{
|
||||
}
|
||||
|
||||
std::string device_name;
|
||||
bool enable;
|
||||
uint32_t systemic_input_latency;
|
||||
uint32_t systemic_output_latency;
|
||||
};
|
||||
|
||||
#endif // MIDI_DEVICE_INFO_H
|
@ -156,6 +156,7 @@ PortAudioBackend::set_driver (const std::string& name)
|
||||
bool
|
||||
PortAudioBackend::update_devices ()
|
||||
{
|
||||
// update midi device info?
|
||||
return _pcmio->update_devices();
|
||||
}
|
||||
|
||||
@ -329,6 +330,24 @@ PortAudioBackend::set_systemic_output_latency (uint32_t sl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PortAudioBackend::set_systemic_midi_input_latency (std::string const device, uint32_t sl)
|
||||
{
|
||||
MidiDeviceInfo* nfo = midi_device_info (device);
|
||||
if (!nfo) return -1;
|
||||
nfo->systemic_input_latency = sl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PortAudioBackend::set_systemic_midi_output_latency (std::string const device, uint32_t sl)
|
||||
{
|
||||
MidiDeviceInfo* nfo = midi_device_info (device);
|
||||
if (!nfo) return -1;
|
||||
nfo->systemic_output_latency = sl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieving parameters */
|
||||
std::string
|
||||
PortAudioBackend::device_name () const
|
||||
@ -390,6 +409,22 @@ PortAudioBackend::systemic_output_latency () const
|
||||
return _systemic_audio_output_latency;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PortAudioBackend::systemic_midi_input_latency (std::string const device) const
|
||||
{
|
||||
MidiDeviceInfo* nfo = midi_device_info (device);
|
||||
if (!nfo) return 0;
|
||||
return nfo->systemic_input_latency;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PortAudioBackend::systemic_midi_output_latency (std::string const device) const
|
||||
{
|
||||
MidiDeviceInfo* nfo = midi_device_info (device);
|
||||
if (!nfo) return 0;
|
||||
return nfo->systemic_output_latency;
|
||||
}
|
||||
|
||||
std::string
|
||||
PortAudioBackend::control_app_name () const
|
||||
{
|
||||
@ -431,6 +466,61 @@ PortAudioBackend::midi_option () const
|
||||
return _midi_driver_option;
|
||||
}
|
||||
|
||||
std::vector<AudioBackend::DeviceStatus>
|
||||
PortAudioBackend::enumerate_midi_devices () const
|
||||
{
|
||||
std::vector<AudioBackend::DeviceStatus> midi_device_status;
|
||||
std::vector<MidiDeviceInfo*> device_info;
|
||||
|
||||
if (_midi_driver_option == winmme_driver_name) {
|
||||
_midiio->update_device_info ();
|
||||
device_info = _midiio->get_device_info ();
|
||||
}
|
||||
|
||||
for (std::vector<MidiDeviceInfo*>::const_iterator i = device_info.begin();
|
||||
i != device_info.end();
|
||||
++i) {
|
||||
midi_device_status.push_back(DeviceStatus((*i)->device_name, true));
|
||||
}
|
||||
return midi_device_status;
|
||||
}
|
||||
|
||||
MidiDeviceInfo*
|
||||
PortAudioBackend::midi_device_info (const std::string& device_name) const
|
||||
{
|
||||
std::vector<MidiDeviceInfo*> dev_info;
|
||||
|
||||
if (_midi_driver_option == winmme_driver_name) {
|
||||
dev_info = _midiio->get_device_info();
|
||||
|
||||
for (std::vector<MidiDeviceInfo*>::const_iterator i = dev_info.begin();
|
||||
i != dev_info.end();
|
||||
++i) {
|
||||
if ((*i)->device_name == device_name) {
|
||||
return *i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PortAudioBackend::set_midi_device_enabled (std::string const device, bool enable)
|
||||
{
|
||||
MidiDeviceInfo* nfo = midi_device_info(device);
|
||||
if (!nfo) return -1;
|
||||
nfo->enable = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
PortAudioBackend::midi_device_enabled (std::string const device) const
|
||||
{
|
||||
MidiDeviceInfo* nfo = midi_device_info(device);
|
||||
if (!nfo) return false;
|
||||
return nfo->enable;
|
||||
}
|
||||
|
||||
/* State Control */
|
||||
|
||||
static void * blocking_thread_func (void *arg)
|
||||
@ -1309,7 +1399,13 @@ PortAudioBackend::register_system_midi_ports()
|
||||
DataType::MIDI,
|
||||
static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
|
||||
if (!p) return -1;
|
||||
|
||||
MidiDeviceInfo* info = _midiio->get_device_info((*i)->name());
|
||||
if (info) { // assert?
|
||||
lr.min = lr.max = _samples_per_period + info->systemic_input_latency;
|
||||
}
|
||||
set_latency_range (p, false, lr);
|
||||
|
||||
PortMidiPort* midi_port = static_cast<PortMidiPort*>(p);
|
||||
midi_port->set_pretty_name ((*i)->name());
|
||||
_system_midi_in.push_back (midi_port);
|
||||
@ -1327,7 +1423,13 @@ PortAudioBackend::register_system_midi_ports()
|
||||
DataType::MIDI,
|
||||
static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
|
||||
if (!p) return -1;
|
||||
|
||||
MidiDeviceInfo* info = _midiio->get_device_info((*i)->name());
|
||||
if (info) { // assert?
|
||||
lr.min = lr.max = _samples_per_period + info->systemic_output_latency;
|
||||
}
|
||||
set_latency_range (p, false, lr);
|
||||
|
||||
PortMidiPort* midi_port = static_cast<PortMidiPort*>(p);
|
||||
midi_port->set_n_periods(2);
|
||||
midi_port->set_pretty_name ((*i)->name());
|
||||
|
@ -197,8 +197,8 @@ class PortAudioBackend : public AudioBackend {
|
||||
int set_output_channels (uint32_t);
|
||||
int set_systemic_input_latency (uint32_t);
|
||||
int set_systemic_output_latency (uint32_t);
|
||||
int set_systemic_midi_input_latency (std::string const, uint32_t) { return 0; }
|
||||
int set_systemic_midi_output_latency (std::string const, uint32_t) { return 0; }
|
||||
int set_systemic_midi_input_latency (std::string const, uint32_t);
|
||||
int set_systemic_midi_output_latency (std::string const, uint32_t);
|
||||
|
||||
int reset_device () { return 0; };
|
||||
|
||||
@ -213,10 +213,10 @@ class PortAudioBackend : public AudioBackend {
|
||||
uint32_t output_channels () const;
|
||||
uint32_t systemic_input_latency () const;
|
||||
uint32_t systemic_output_latency () const;
|
||||
uint32_t systemic_midi_input_latency (std::string const) const { return 0; }
|
||||
uint32_t systemic_midi_output_latency (std::string const) const { return 0; }
|
||||
uint32_t systemic_midi_input_latency (std::string const) const;
|
||||
uint32_t systemic_midi_output_latency (std::string const) const;
|
||||
|
||||
bool can_set_systemic_midi_latencies () const { return false; }
|
||||
bool can_set_systemic_midi_latencies () const { return true; }
|
||||
|
||||
/* External control app */
|
||||
std::string control_app_name () const;
|
||||
@ -227,15 +227,9 @@ class PortAudioBackend : public AudioBackend {
|
||||
int set_midi_option (const std::string&);
|
||||
std::string midi_option () const;
|
||||
|
||||
std::vector<DeviceStatus> enumerate_midi_devices () const {
|
||||
return std::vector<AudioBackend::DeviceStatus> ();
|
||||
}
|
||||
int set_midi_device_enabled (std::string const, bool) {
|
||||
return 0;
|
||||
}
|
||||
bool midi_device_enabled (std::string const) const {
|
||||
return true;
|
||||
}
|
||||
std::vector<DeviceStatus> enumerate_midi_devices () const;
|
||||
int set_midi_device_enabled (std::string const, bool);
|
||||
bool midi_device_enabled (std::string const) const;
|
||||
|
||||
protected:
|
||||
/* State Control */
|
||||
@ -402,6 +396,8 @@ class PortAudioBackend : public AudioBackend {
|
||||
uint32_t _systemic_audio_input_latency;
|
||||
uint32_t _systemic_audio_output_latency;
|
||||
|
||||
MidiDeviceInfo* midi_device_info(const std::string&) const;
|
||||
|
||||
/* portaudio specific */
|
||||
int name_to_id(std::string) const;
|
||||
|
||||
|
@ -109,8 +109,7 @@ WinMMEMidiIO::port_id (uint32_t port, bool input)
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
WinMMEMidiIO::port_name (uint32_t port, bool input)
|
||||
std::string WinMMEMidiIO::port_name(uint32_t port, bool input)
|
||||
{
|
||||
if (input) {
|
||||
if (port < m_inputs.size ()) {
|
||||
@ -200,6 +199,86 @@ WinMMEMidiIO::stop_devices ()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WinMMEMidiIO::clear_device_info ()
|
||||
{
|
||||
for (std::vector<MidiDeviceInfo*>::iterator i = m_device_info.begin();
|
||||
i != m_device_info.end();
|
||||
++i) {
|
||||
delete *i;
|
||||
}
|
||||
m_device_info.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
WinMMEMidiIO::get_input_name_from_index (int index, std::string& name)
|
||||
{
|
||||
MIDIINCAPS capabilities;
|
||||
MMRESULT result = midiInGetDevCaps(index, &capabilities, sizeof(capabilities));
|
||||
if (result == MMSYSERR_NOERROR) {
|
||||
name = capabilities.szPname;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
WinMMEMidiIO::get_output_name_from_index (int index, std::string& name)
|
||||
{
|
||||
MIDIOUTCAPS capabilities;
|
||||
MMRESULT result = midiOutGetDevCaps(index, &capabilities, sizeof(capabilities));
|
||||
if (result == MMSYSERR_NOERROR) {
|
||||
name = capabilities.szPname;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WinMMEMidiIO::update_device_info ()
|
||||
{
|
||||
std::set<std::string> device_names;
|
||||
|
||||
int in_count = midiInGetNumDevs ();
|
||||
|
||||
for (int i = 0; i < in_count; ++i) {
|
||||
std::string input_name;
|
||||
if (get_input_name_from_index(i, input_name)) {
|
||||
device_names.insert(input_name);
|
||||
}
|
||||
}
|
||||
|
||||
int out_count = midiOutGetNumDevs ();
|
||||
|
||||
for (int i = 0; i < out_count; ++i) {
|
||||
std::string output_name;
|
||||
if (get_output_name_from_index(i, output_name)) {
|
||||
device_names.insert(output_name);
|
||||
}
|
||||
}
|
||||
|
||||
clear_device_info ();
|
||||
|
||||
for (std::set<std::string>::const_iterator i = device_names.begin();
|
||||
i != device_names.end();
|
||||
++i) {
|
||||
m_device_info.push_back(new MidiDeviceInfo(*i));
|
||||
}
|
||||
}
|
||||
|
||||
MidiDeviceInfo*
|
||||
WinMMEMidiIO::get_device_info (const std::string& name)
|
||||
{
|
||||
for (std::vector<MidiDeviceInfo*>::const_iterator i = m_device_info.begin();
|
||||
i != m_device_info.end();
|
||||
++i) {
|
||||
if ((*i)->device_name == name) {
|
||||
return *i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
WinMMEMidiIO::create_input_devices ()
|
||||
{
|
||||
@ -208,6 +287,25 @@ WinMMEMidiIO::create_input_devices ()
|
||||
DEBUG_MIDI (string_compose ("MidiIn count: %1\n", srcCount));
|
||||
|
||||
for (int i = 0; i < srcCount; ++i) {
|
||||
std::string input_name;
|
||||
if (!get_input_name_from_index (i, input_name)) {
|
||||
DEBUG_MIDI ("Unable to get MIDI input name from index\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
MidiDeviceInfo* info = get_device_info (input_name);
|
||||
|
||||
if (!info) {
|
||||
DEBUG_MIDI ("Unable to MIDI device info from name\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!info->enable) {
|
||||
DEBUG_MIDI(string_compose(
|
||||
"MIDI input device %1 not enabled, not opening device\n", input_name));
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
WinMMEMidiInputDevice* midi_input = new WinMMEMidiInputDevice (i);
|
||||
if (midi_input) {
|
||||
@ -228,6 +326,25 @@ WinMMEMidiIO::create_output_devices ()
|
||||
DEBUG_MIDI (string_compose ("MidiOut count: %1\n", dstCount));
|
||||
|
||||
for (int i = 0; i < dstCount; ++i) {
|
||||
std::string output_name;
|
||||
if (!get_output_name_from_index (i, output_name)) {
|
||||
DEBUG_MIDI ("Unable to get MIDI output name from index\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
MidiDeviceInfo* info = get_device_info (output_name);
|
||||
|
||||
if (!info) {
|
||||
DEBUG_MIDI ("Unable to MIDI device info from name\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!info->enable) {
|
||||
DEBUG_MIDI(string_compose(
|
||||
"MIDI output device %1 not enabled, not opening device\n", output_name));
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
WinMMEMidiOutputDevice* midi_output = new WinMMEMidiOutputDevice(i);
|
||||
if (midi_output) {
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "winmmemidi_input_device.h"
|
||||
#include "winmmemidi_output_device.h"
|
||||
|
||||
#include "midi_device_info.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
struct WinMMEMIDIPacket {
|
||||
@ -79,6 +81,12 @@ public:
|
||||
std::vector<WinMMEMidiInputDevice*> get_inputs () { return m_inputs; }
|
||||
std::vector<WinMMEMidiOutputDevice*> get_outputs () { return m_outputs; }
|
||||
|
||||
void update_device_info ();
|
||||
|
||||
std::vector<MidiDeviceInfo*> get_device_info () { return m_device_info; }
|
||||
|
||||
MidiDeviceInfo* get_device_info (const std::string& name);
|
||||
|
||||
std::string port_id (uint32_t, bool input);
|
||||
std::string port_name (uint32_t, bool input);
|
||||
|
||||
@ -91,6 +99,12 @@ public:
|
||||
}
|
||||
|
||||
private: // Methods
|
||||
|
||||
void clear_device_info ();
|
||||
|
||||
static bool get_input_name_from_index (int index, std::string& name);
|
||||
static bool get_output_name_from_index (int index, std::string& name);
|
||||
|
||||
void discover ();
|
||||
void cleanup ();
|
||||
|
||||
@ -105,6 +119,8 @@ private: // Methods
|
||||
|
||||
private: // Data
|
||||
|
||||
std::vector<MidiDeviceInfo*> m_device_info;
|
||||
|
||||
std::vector<WinMMEMidiInputDevice*> m_inputs;
|
||||
std::vector<WinMMEMidiOutputDevice*> m_outputs;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user