PortAudio backend RT-safe MIDI buffer allocation

This commit is contained in:
Robin Gareus 2017-08-05 15:35:31 +02:00
parent f4c76f89d3
commit bc46a7e2e9
5 changed files with 34 additions and 35 deletions

View file

@ -93,6 +93,8 @@ PortAudioBackend::PortAudioBackend (AudioEngine& e, AudioBackendInfo& info)
pthread_mutex_init (&_freewheel_mutex, 0); pthread_mutex_init (&_freewheel_mutex, 0);
pthread_cond_init (&_freewheel_signal, 0); pthread_cond_init (&_freewheel_signal, 0);
_port_connection_queue.reserve (128);
_pcmio = new PortAudioIO (); _pcmio = new PortAudioIO ();
_midiio = new WinMMEMidiIO (); _midiio = new WinMMEMidiIO ();
} }
@ -1618,11 +1620,11 @@ PortAudioBackend::midi_event_get (
if (event_index >= source.size ()) { if (event_index >= source.size ()) {
return -1; return -1;
} }
PortMidiEvent * const event = source[event_index].get (); PortMidiEvent const& event = source[event_index].get ();
timestamp = event->timestamp (); timestamp = event.timestamp ();
size = event->size (); size = event.size ();
*buf = event->data (); *buf = event.data ();
return 0; return 0;
} }
@ -1634,13 +1636,15 @@ PortAudioBackend::midi_event_put (
{ {
if (!buffer || !port_buffer) return -1; if (!buffer || !port_buffer) return -1;
PortMidiBuffer& dst = * static_cast<PortMidiBuffer*>(port_buffer); PortMidiBuffer& dst = * static_cast<PortMidiBuffer*>(port_buffer);
if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) { #ifndef NDEBUG
if (dst.size () && (pframes_t)dst.back ().timestamp () > timestamp) {
// nevermind, ::get_buffer() sorts events // nevermind, ::get_buffer() sorts events
DEBUG_MIDI (string_compose ("PortMidiBuffer: unordered event: %1 > %2\n", DEBUG_MIDI (string_compose ("PortMidiBuffer: unordered event: %1 > %2\n",
(pframes_t)dst.back ()->timestamp (), (pframes_t)dst.back ().timestamp (),
timestamp)); timestamp));
} }
dst.push_back (boost::shared_ptr<PortMidiEvent>(new PortMidiEvent (timestamp, buffer, size))); #endif
dst.push_back (PortMidiEvent (timestamp, buffer, size));
return 0; return 0;
} }
@ -2038,7 +2042,7 @@ PortAudioBackend::process_incoming_midi ()
mbuf->clear(); mbuf->clear();
uint64_t timestamp; uint64_t timestamp;
pframes_t sample_offset; pframes_t sample_offset;
uint8_t data[256]; uint8_t data[MaxWinMidiEventSize];
size_t size = sizeof(data); size_t size = sizeof(data);
while (_midiio->dequeue_input_event(i, while (_midiio->dequeue_input_event(i,
_cycle_timer.get_start(), _cycle_timer.get_start(),
@ -2079,14 +2083,14 @@ PortAudioBackend::process_outgoing_midi ()
for (PortMidiBuffer::const_iterator mit = src->begin(); mit != src->end(); for (PortMidiBuffer::const_iterator mit = src->begin(); mit != src->end();
++mit) { ++mit) {
uint64_t timestamp = uint64_t timestamp =
_cycle_timer.timestamp_from_sample_offset((*mit)->timestamp()); _cycle_timer.timestamp_from_sample_offset(mit->timestamp());
DEBUG_MIDI(string_compose("Queuing outgoing MIDI data for device: " DEBUG_MIDI(string_compose("Queuing outgoing MIDI data for device: "
"%1 sample_offset: %2 timestamp: %3, size: %4\n", "%1 sample_offset: %2 timestamp: %3, size: %4\n",
_midiio->get_outputs()[i]->name(), _midiio->get_outputs()[i]->name(),
(*mit)->timestamp(), mit->timestamp(),
timestamp, timestamp,
(*mit)->size())); mit->size()));
_midiio->enqueue_output_event(i, timestamp, (*mit)->data(), (*mit)->size()); _midiio->enqueue_output_event(i, timestamp, mit->data(), mit->size());
} }
} }
} }
@ -2354,13 +2358,16 @@ PortMidiPort::PortMidiPort (PortAudioBackend &b, const std::string& name, PortFl
{ {
_buffer[0].clear (); _buffer[0].clear ();
_buffer[1].clear (); _buffer[1].clear ();
_buffer[0].reserve (256);
_buffer[1].reserve (256);
} }
PortMidiPort::~PortMidiPort () { } PortMidiPort::~PortMidiPort () { }
struct MidiEventSorter { struct MidiEventSorter {
bool operator() (const boost::shared_ptr<PortMidiEvent>& a, const boost::shared_ptr<PortMidiEvent>& b) { bool operator() (PortMidiEvent const& a, PortMidiEvent const& b) {
return *a < *b; return a < b;
} }
}; };
@ -2373,7 +2380,7 @@ void* PortMidiPort::get_buffer (pframes_t /* nframes */)
++i) { ++i) {
const PortMidiBuffer * src = static_cast<const PortMidiPort*>(*i)->const_buffer (); const PortMidiBuffer * src = static_cast<const PortMidiPort*>(*i)->const_buffer ();
for (PortMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) { for (PortMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
(_buffer[_bufperiod]).push_back (boost::shared_ptr<PortMidiEvent>(new PortMidiEvent (**it))); (_buffer[_bufperiod]).push_back (*it);
} }
} }
std::stable_sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter()); std::stable_sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
@ -2384,10 +2391,8 @@ void* PortMidiPort::get_buffer (pframes_t /* nframes */)
PortMidiEvent::PortMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size) PortMidiEvent::PortMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
: _size (size) : _size (size)
, _timestamp (timestamp) , _timestamp (timestamp)
, _data (0)
{ {
if (size > 0) { if (size > 0 && size < MaxWinMidiEventSize) {
_data = (uint8_t*) malloc (size);
memcpy (_data, data, size); memcpy (_data, data, size);
} }
} }
@ -2395,14 +2400,9 @@ PortMidiEvent::PortMidiEvent (const pframes_t timestamp, const uint8_t* data, si
PortMidiEvent::PortMidiEvent (const PortMidiEvent& other) PortMidiEvent::PortMidiEvent (const PortMidiEvent& other)
: _size (other.size ()) : _size (other.size ())
, _timestamp (other.timestamp ()) , _timestamp (other.timestamp ())
, _data (0)
{ {
if (other.size () && other.const_data ()) { if (other._size > 0) {
_data = (uint8_t*) malloc (other.size ()); assert (other._size < MaxWinMidiEventSize);
memcpy (_data, other.const_data (), other.size ()); memcpy (_data, other._data, other._size);
} }
}; };
PortMidiEvent::~PortMidiEvent () {
free (_data);
};

View file

@ -45,19 +45,17 @@ class PortMidiEvent {
public: public:
PortMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size); PortMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
PortMidiEvent (const PortMidiEvent& other); PortMidiEvent (const PortMidiEvent& other);
~PortMidiEvent ();
size_t size () const { return _size; }; size_t size () const { return _size; };
pframes_t timestamp () const { return _timestamp; }; pframes_t timestamp () const { return _timestamp; };
const unsigned char* const_data () const { return _data; }; const uint8_t* const_data () const { return _data; };
unsigned char* data () { return _data; };
bool operator< (const PortMidiEvent &other) const { return timestamp () < other.timestamp (); }; bool operator< (const PortMidiEvent &other) const { return timestamp () < other.timestamp (); };
private: private:
size_t _size; size_t _size;
pframes_t _timestamp; pframes_t _timestamp;
uint8_t *_data; uint8_t _data[MaxWinMidiEventSize];
}; };
typedef std::vector<boost::shared_ptr<PortMidiEvent> > PortMidiBuffer; typedef std::vector<PortMidiEvent> PortMidiBuffer;
class PamPort { // PortAudio / PortMidi Backend Port class PamPort { // PortAudio / PortMidi Backend Port
protected: protected:

View file

@ -50,7 +50,7 @@ struct WinMMEMIDIPacket {
// MIDITimeStamp timeStamp; // MIDITimeStamp timeStamp;
uint16_t length; uint16_t length;
uint8_t data[256]; uint8_t data[MaxWinMidiEventSize];
}; };
typedef std::vector<boost::shared_ptr<WinMMEMIDIPacket> > WinMMEMIDIQueue; typedef std::vector<boost::shared_ptr<WinMMEMIDIPacket> > WinMMEMIDIQueue;

View file

@ -32,7 +32,6 @@
// remove dup with input_device // remove dup with input_device
static const uint32_t MIDI_BUFFER_SIZE = 32768; static const uint32_t MIDI_BUFFER_SIZE = 32768;
static const uint32_t MAX_MIDI_MSG_SIZE = 256; // fix this for sysex
static const uint32_t MAX_QUEUE_SIZE = 4096; static const uint32_t MAX_QUEUE_SIZE = 4096;
namespace ARDOUR { namespace ARDOUR {
@ -361,7 +360,7 @@ WinMMEMidiOutputDevice::midi_output_thread ()
DEBUG_MIDI ("WinMMEMidiOut: output thread woken by semaphore\n"); DEBUG_MIDI ("WinMMEMidiOut: output thread woken by semaphore\n");
MidiEventHeader h (0, 0); MidiEventHeader h (0, 0);
uint8_t data[MAX_MIDI_MSG_SIZE]; uint8_t data[MaxWinMidiEventSize];
const uint32_t read_space = m_midi_buffer->read_space (); const uint32_t read_space = m_midi_buffer->read_space ();
@ -375,7 +374,7 @@ WinMMEMidiOutputDevice::midi_output_thread ()
} }
assert (read_space >= h.size); assert (read_space >= h.size);
if (h.size > MAX_MIDI_MSG_SIZE) { if (h.size > MaxWinMidiEventSize) {
m_midi_buffer->increment_read_idx (h.size); m_midi_buffer->increment_read_idx (h.size);
DEBUG_MIDI ("WinMMEMidiOut: MIDI event too large!\n"); DEBUG_MIDI ("WinMMEMidiOut: MIDI event too large!\n");
continue; continue;

View file

@ -31,6 +31,8 @@
#include <pbd/ringbuffer.h> #include <pbd/ringbuffer.h>
#define MaxWinMidiEventSize 256
namespace ARDOUR { namespace ARDOUR {
class WinMMEMidiOutputDevice { class WinMMEMidiOutputDevice {