Implement MIDI device enumeration and latency offset/calibration in portaudio backend

This commit is contained in:
Tim Mayberry 2015-12-04 22:23:01 +10:00
parent d54a320374
commit b2cf028fcb
5 changed files with 267 additions and 16 deletions

View 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

View File

@ -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());

View File

@ -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;

View File

@ -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) {

View File

@ -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;