summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorTim Mayberry <mojofunk@gmail.com>2015-12-04 22:23:01 +1000
committerTim Mayberry <mojofunk@gmail.com>2016-02-11 12:15:07 +1000
commitb2cf028fcba055110a9b1bf36af0fb6bd443c1af (patch)
treeaa1bd198841daef6b5753180bf78a33cd105c172 /libs
parentd54a32037406775cad9431c3f0cc21fa9670fba2 (diff)
Implement MIDI device enumeration and latency offset/calibration in portaudio backend
Diffstat (limited to 'libs')
-rw-r--r--libs/backends/portaudio/midi_device_info.h20
-rw-r--r--libs/backends/portaudio/portaudio_backend.cc102
-rw-r--r--libs/backends/portaudio/portaudio_backend.h24
-rw-r--r--libs/backends/portaudio/winmmemidi_io.cc121
-rw-r--r--libs/backends/portaudio/winmmemidi_io.h16
5 files changed, 267 insertions, 16 deletions
diff --git a/libs/backends/portaudio/midi_device_info.h b/libs/backends/portaudio/midi_device_info.h
new file mode 100644
index 0000000000..7b470df891
--- /dev/null
+++ b/libs/backends/portaudio/midi_device_info.h
@@ -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
diff --git a/libs/backends/portaudio/portaudio_backend.cc b/libs/backends/portaudio/portaudio_backend.cc
index 4f74992adf..0f816c991f 100644
--- a/libs/backends/portaudio/portaudio_backend.cc
+++ b/libs/backends/portaudio/portaudio_backend.cc
@@ -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());
diff --git a/libs/backends/portaudio/portaudio_backend.h b/libs/backends/portaudio/portaudio_backend.h
index f0ef5fa993..b028dc212b 100644
--- a/libs/backends/portaudio/portaudio_backend.h
+++ b/libs/backends/portaudio/portaudio_backend.h
@@ -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;
diff --git a/libs/backends/portaudio/winmmemidi_io.cc b/libs/backends/portaudio/winmmemidi_io.cc
index 427ff486d7..d845e60551 100644
--- a/libs/backends/portaudio/winmmemidi_io.cc
+++ b/libs/backends/portaudio/winmmemidi_io.cc
@@ -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 ()) {
@@ -201,6 +200,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 ()
{
int srcCount = midiInGetNumDevs ();
@@ -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) {
diff --git a/libs/backends/portaudio/winmmemidi_io.h b/libs/backends/portaudio/winmmemidi_io.h
index 28450e95cb..672a68cc73 100644
--- a/libs/backends/portaudio/winmmemidi_io.h
+++ b/libs/backends/portaudio/winmmemidi_io.h
@@ -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;