PortAudio backend RT-safe MIDI buffer allocation
authorRobin Gareus <robin@gareus.org>
Sat, 5 Aug 2017 13:35:31 +0000 (15:35 +0200)
committerRobin Gareus <robin@gareus.org>
Sat, 5 Aug 2017 13:36:36 +0000 (15:36 +0200)
libs/backends/portaudio/portaudio_backend.cc
libs/backends/portaudio/portaudio_backend.h
libs/backends/portaudio/winmmemidi_io.h
libs/backends/portaudio/winmmemidi_output_device.cc
libs/backends/portaudio/winmmemidi_output_device.h

index 3ce0f094acaf45a249c55be5f77392c33fa79f18..ad7d976a2d526151f2aa6d2f68e218f72849eb39 100644 (file)
@@ -93,6 +93,8 @@ PortAudioBackend::PortAudioBackend (AudioEngine& e, AudioBackendInfo& info)
        pthread_mutex_init (&_freewheel_mutex, 0);
        pthread_cond_init (&_freewheel_signal, 0);
 
+       _port_connection_queue.reserve (128);
+
        _pcmio = new PortAudioIO ();
        _midiio = new WinMMEMidiIO ();
 }
@@ -1618,11 +1620,11 @@ PortAudioBackend::midi_event_get (
        if (event_index >= source.size ()) {
                return -1;
        }
-       PortMidiEvent * const event = source[event_index].get ();
+       PortMidiEvent const& event = source[event_index].get ();
 
-       timestamp = event->timestamp ();
-       size = event->size ();
-       *buf = event->data ();
+       timestamp = event.timestamp ();
+       size = event.size ();
+       *buf = event.data ();
        return 0;
 }
 
@@ -1634,13 +1636,15 @@ PortAudioBackend::midi_event_put (
 {
        if (!buffer || !port_buffer) return -1;
        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
                DEBUG_MIDI (string_compose ("PortMidiBuffer: unordered event: %1 > %2\n",
-                                           (pframes_t)dst.back ()->timestamp (),
+                                           (pframes_t)dst.back ().timestamp (),
                                            timestamp));
        }
-       dst.push_back (boost::shared_ptr<PortMidiEvent>(new PortMidiEvent (timestamp, buffer, size)));
+#endif
+       dst.push_back (PortMidiEvent (timestamp, buffer, size));
        return 0;
 }
 
@@ -2038,7 +2042,7 @@ PortAudioBackend::process_incoming_midi ()
                mbuf->clear();
                uint64_t timestamp;
                pframes_t sample_offset;
-               uint8_t data[256];
+               uint8_t data[MaxWinMidiEventSize];
                size_t size = sizeof(data);
                while (_midiio->dequeue_input_event(i,
                                                    _cycle_timer.get_start(),
@@ -2079,14 +2083,14 @@ PortAudioBackend::process_outgoing_midi ()
                for (PortMidiBuffer::const_iterator mit = src->begin(); mit != src->end();
                     ++mit) {
                        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: "
                                                  "%1 sample_offset: %2 timestamp: %3, size: %4\n",
                                                  _midiio->get_outputs()[i]->name(),
-                                                 (*mit)->timestamp(),
+                                                 mit->timestamp(),
                                                  timestamp,
-                                                 (*mit)->size()));
-                       _midiio->enqueue_output_event(i, timestamp, (*mit)->data(), (*mit)->size());
+                                                 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[1].clear ();
+
+       _buffer[0].reserve (256);
+       _buffer[1].reserve (256);
 }
 
 PortMidiPort::~PortMidiPort () { }
 
 struct MidiEventSorter {
-       bool operator() (const boost::shared_ptr<PortMidiEvent>& a, const boost::shared_ptr<PortMidiEvent>& b) {
-               return *a < *b;
+       bool operator() (PortMidiEvent const& a, PortMidiEvent const& b) {
+               return a < b;
        }
 };
 
@@ -2373,7 +2380,7 @@ void* PortMidiPort::get_buffer (pframes_t /* nframes */)
                                ++i) {
                        const PortMidiBuffer * src = static_cast<const PortMidiPort*>(*i)->const_buffer ();
                        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());
@@ -2384,10 +2391,8 @@ void* PortMidiPort::get_buffer (pframes_t /* nframes */)
 PortMidiEvent::PortMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
        : _size (size)
        , _timestamp (timestamp)
-       , _data (0)
 {
-       if (size > 0) {
-               _data = (uint8_t*) malloc (size);
+       if (size > 0 && size < MaxWinMidiEventSize) {
                memcpy (_data, data, size);
        }
 }
@@ -2395,14 +2400,9 @@ PortMidiEvent::PortMidiEvent (const pframes_t timestamp, const uint8_t* data, si
 PortMidiEvent::PortMidiEvent (const PortMidiEvent& other)
        : _size (other.size ())
        , _timestamp (other.timestamp ())
-       , _data (0)
 {
-       if (other.size () && other.const_data ()) {
-               _data = (uint8_t*) malloc (other.size ());
-               memcpy (_data, other.const_data (), other.size ());
+       if (other._size > 0) {
+               assert (other._size < MaxWinMidiEventSize);
+               memcpy (_data, other._data, other._size);
        }
 };
-
-PortMidiEvent::~PortMidiEvent () {
-       free (_data);
-};
index 34bdabe7871414e8ec7f15fbf42592b3d0549a5e..d5ce42aad07c0b244ce0d98c79952239959901cc 100644 (file)
@@ -45,19 +45,17 @@ class PortMidiEvent {
        public:
                PortMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
                PortMidiEvent (const PortMidiEvent& other);
-               ~PortMidiEvent ();
                size_t size () const { return _size; };
                pframes_t timestamp () const { return _timestamp; };
-               const unsigned char* const_data () const { return _data; };
-               unsigned char* data () { return _data; };
+               const uint8_t* const_data () const { return _data; };
                bool operator< (const PortMidiEvent &other) const { return timestamp () < other.timestamp (); };
        private:
                size_t _size;
                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
        protected:
index 672a68cc733ca78f2284d273fc2059370202e302..4d146981fb19d90a7da686cfa76a2ffe0bf51346 100644 (file)
@@ -50,7 +50,7 @@ struct WinMMEMIDIPacket {
 
        // MIDITimeStamp timeStamp;
        uint16_t length;
-       uint8_t data[256];
+       uint8_t data[MaxWinMidiEventSize];
 };
 
 typedef std::vector<boost::shared_ptr<WinMMEMIDIPacket> > WinMMEMIDIQueue;
index 5730e4b1be86f91ebf27ad0352cc84aa45ce903d..2f6ad018958120e2cdfb6aa20c2b55c29e2b22d5 100644 (file)
@@ -32,7 +32,6 @@
 
 // remove dup with input_device
 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;
 
 namespace ARDOUR {
@@ -361,7 +360,7 @@ WinMMEMidiOutputDevice::midi_output_thread ()
                DEBUG_MIDI ("WinMMEMidiOut: output thread woken by semaphore\n");
 
                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 ();
 
@@ -375,7 +374,7 @@ WinMMEMidiOutputDevice::midi_output_thread ()
                        }
                        assert (read_space >= h.size);
 
-                       if (h.size > MAX_MIDI_MSG_SIZE) {
+                       if (h.size > MaxWinMidiEventSize) {
                                m_midi_buffer->increment_read_idx (h.size);
                                DEBUG_MIDI ("WinMMEMidiOut: MIDI event too large!\n");
                                continue;
index 8c4d4d0c903d9e6b2c168f92b40903b3d7261a6e..bc3a6251ae0132dc3195680ce232399a779fa309 100644 (file)
@@ -31,6 +31,8 @@
 
 #include <pbd/ringbuffer.h>
 
+#define MaxWinMidiEventSize 256
+
 namespace ARDOUR {
 
 class WinMMEMidiOutputDevice {