mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 16:46:35 +01:00
Implement MIDI device enumeration and latency offset/calibration in portaudio backend
This commit is contained in:
parent
d54a320374
commit
b2cf028fcb
5 changed files with 267 additions and 16 deletions
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
|
bool
|
||||||
PortAudioBackend::update_devices ()
|
PortAudioBackend::update_devices ()
|
||||||
{
|
{
|
||||||
|
// update midi device info?
|
||||||
return _pcmio->update_devices();
|
return _pcmio->update_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,6 +330,24 @@ PortAudioBackend::set_systemic_output_latency (uint32_t sl)
|
||||||
return 0;
|
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 */
|
/* Retrieving parameters */
|
||||||
std::string
|
std::string
|
||||||
PortAudioBackend::device_name () const
|
PortAudioBackend::device_name () const
|
||||||
|
|
@ -390,6 +409,22 @@ PortAudioBackend::systemic_output_latency () const
|
||||||
return _systemic_audio_output_latency;
|
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
|
std::string
|
||||||
PortAudioBackend::control_app_name () const
|
PortAudioBackend::control_app_name () const
|
||||||
{
|
{
|
||||||
|
|
@ -431,6 +466,61 @@ PortAudioBackend::midi_option () const
|
||||||
return _midi_driver_option;
|
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 */
|
/* State Control */
|
||||||
|
|
||||||
static void * blocking_thread_func (void *arg)
|
static void * blocking_thread_func (void *arg)
|
||||||
|
|
@ -1309,7 +1399,13 @@ PortAudioBackend::register_system_midi_ports()
|
||||||
DataType::MIDI,
|
DataType::MIDI,
|
||||||
static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
|
static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
|
||||||
if (!p) return -1;
|
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);
|
set_latency_range (p, false, lr);
|
||||||
|
|
||||||
PortMidiPort* midi_port = static_cast<PortMidiPort*>(p);
|
PortMidiPort* midi_port = static_cast<PortMidiPort*>(p);
|
||||||
midi_port->set_pretty_name ((*i)->name());
|
midi_port->set_pretty_name ((*i)->name());
|
||||||
_system_midi_in.push_back (midi_port);
|
_system_midi_in.push_back (midi_port);
|
||||||
|
|
@ -1327,7 +1423,13 @@ PortAudioBackend::register_system_midi_ports()
|
||||||
DataType::MIDI,
|
DataType::MIDI,
|
||||||
static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
|
static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
|
||||||
if (!p) return -1;
|
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);
|
set_latency_range (p, false, lr);
|
||||||
|
|
||||||
PortMidiPort* midi_port = static_cast<PortMidiPort*>(p);
|
PortMidiPort* midi_port = static_cast<PortMidiPort*>(p);
|
||||||
midi_port->set_n_periods(2);
|
midi_port->set_n_periods(2);
|
||||||
midi_port->set_pretty_name ((*i)->name());
|
midi_port->set_pretty_name ((*i)->name());
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,8 @@ class PortAudioBackend : public AudioBackend {
|
||||||
int set_output_channels (uint32_t);
|
int set_output_channels (uint32_t);
|
||||||
int set_systemic_input_latency (uint32_t);
|
int set_systemic_input_latency (uint32_t);
|
||||||
int set_systemic_output_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_input_latency (std::string const, uint32_t);
|
||||||
int set_systemic_midi_output_latency (std::string const, uint32_t) { return 0; }
|
int set_systemic_midi_output_latency (std::string const, uint32_t);
|
||||||
|
|
||||||
int reset_device () { return 0; };
|
int reset_device () { return 0; };
|
||||||
|
|
||||||
|
|
@ -213,10 +213,10 @@ class PortAudioBackend : public AudioBackend {
|
||||||
uint32_t output_channels () const;
|
uint32_t output_channels () const;
|
||||||
uint32_t systemic_input_latency () const;
|
uint32_t systemic_input_latency () const;
|
||||||
uint32_t systemic_output_latency () const;
|
uint32_t systemic_output_latency () const;
|
||||||
uint32_t systemic_midi_input_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 { return 0; }
|
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 */
|
/* External control app */
|
||||||
std::string control_app_name () const;
|
std::string control_app_name () const;
|
||||||
|
|
@ -227,15 +227,9 @@ class PortAudioBackend : public AudioBackend {
|
||||||
int set_midi_option (const std::string&);
|
int set_midi_option (const std::string&);
|
||||||
std::string midi_option () const;
|
std::string midi_option () const;
|
||||||
|
|
||||||
std::vector<DeviceStatus> enumerate_midi_devices () const {
|
std::vector<DeviceStatus> enumerate_midi_devices () const;
|
||||||
return std::vector<AudioBackend::DeviceStatus> ();
|
int set_midi_device_enabled (std::string const, bool);
|
||||||
}
|
bool midi_device_enabled (std::string const) const;
|
||||||
int set_midi_device_enabled (std::string const, bool) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
bool midi_device_enabled (std::string const) const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* State Control */
|
/* State Control */
|
||||||
|
|
@ -402,6 +396,8 @@ class PortAudioBackend : public AudioBackend {
|
||||||
uint32_t _systemic_audio_input_latency;
|
uint32_t _systemic_audio_input_latency;
|
||||||
uint32_t _systemic_audio_output_latency;
|
uint32_t _systemic_audio_output_latency;
|
||||||
|
|
||||||
|
MidiDeviceInfo* midi_device_info(const std::string&) const;
|
||||||
|
|
||||||
/* portaudio specific */
|
/* portaudio specific */
|
||||||
int name_to_id(std::string) const;
|
int name_to_id(std::string) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,7 @@ WinMMEMidiIO::port_id (uint32_t port, bool input)
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string WinMMEMidiIO::port_name(uint32_t port, bool input)
|
||||||
WinMMEMidiIO::port_name (uint32_t port, bool input)
|
|
||||||
{
|
{
|
||||||
if (input) {
|
if (input) {
|
||||||
if (port < m_inputs.size ()) {
|
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
|
void
|
||||||
WinMMEMidiIO::create_input_devices ()
|
WinMMEMidiIO::create_input_devices ()
|
||||||
{
|
{
|
||||||
|
|
@ -208,6 +287,25 @@ WinMMEMidiIO::create_input_devices ()
|
||||||
DEBUG_MIDI (string_compose ("MidiIn count: %1\n", srcCount));
|
DEBUG_MIDI (string_compose ("MidiIn count: %1\n", srcCount));
|
||||||
|
|
||||||
for (int i = 0; i < srcCount; ++i) {
|
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 {
|
try {
|
||||||
WinMMEMidiInputDevice* midi_input = new WinMMEMidiInputDevice (i);
|
WinMMEMidiInputDevice* midi_input = new WinMMEMidiInputDevice (i);
|
||||||
if (midi_input) {
|
if (midi_input) {
|
||||||
|
|
@ -228,6 +326,25 @@ WinMMEMidiIO::create_output_devices ()
|
||||||
DEBUG_MIDI (string_compose ("MidiOut count: %1\n", dstCount));
|
DEBUG_MIDI (string_compose ("MidiOut count: %1\n", dstCount));
|
||||||
|
|
||||||
for (int i = 0; i < dstCount; ++i) {
|
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 {
|
try {
|
||||||
WinMMEMidiOutputDevice* midi_output = new WinMMEMidiOutputDevice(i);
|
WinMMEMidiOutputDevice* midi_output = new WinMMEMidiOutputDevice(i);
|
||||||
if (midi_output) {
|
if (midi_output) {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
#include "winmmemidi_input_device.h"
|
#include "winmmemidi_input_device.h"
|
||||||
#include "winmmemidi_output_device.h"
|
#include "winmmemidi_output_device.h"
|
||||||
|
|
||||||
|
#include "midi_device_info.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
struct WinMMEMIDIPacket {
|
struct WinMMEMIDIPacket {
|
||||||
|
|
@ -79,6 +81,12 @@ public:
|
||||||
std::vector<WinMMEMidiInputDevice*> get_inputs () { return m_inputs; }
|
std::vector<WinMMEMidiInputDevice*> get_inputs () { return m_inputs; }
|
||||||
std::vector<WinMMEMidiOutputDevice*> get_outputs () { return m_outputs; }
|
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_id (uint32_t, bool input);
|
||||||
std::string port_name (uint32_t, bool input);
|
std::string port_name (uint32_t, bool input);
|
||||||
|
|
||||||
|
|
@ -91,6 +99,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private: // Methods
|
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 discover ();
|
||||||
void cleanup ();
|
void cleanup ();
|
||||||
|
|
||||||
|
|
@ -105,6 +119,8 @@ private: // Methods
|
||||||
|
|
||||||
private: // Data
|
private: // Data
|
||||||
|
|
||||||
|
std::vector<MidiDeviceInfo*> m_device_info;
|
||||||
|
|
||||||
std::vector<WinMMEMidiInputDevice*> m_inputs;
|
std::vector<WinMMEMidiInputDevice*> m_inputs;
|
||||||
std::vector<WinMMEMidiOutputDevice*> m_outputs;
|
std::vector<WinMMEMidiOutputDevice*> m_outputs;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue