mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 15:54:57 +01:00
ALSA backend RT-safe MIDI buffer allocation
This commit is contained in:
parent
2b7c585dba
commit
59a63a08f9
5 changed files with 42 additions and 45 deletions
|
|
@ -77,6 +77,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
||||||
pthread_mutex_init (&_port_callback_mutex, 0);
|
pthread_mutex_init (&_port_callback_mutex, 0);
|
||||||
_input_audio_device_info.valid = false;
|
_input_audio_device_info.valid = false;
|
||||||
_output_audio_device_info.valid = false;
|
_output_audio_device_info.valid = false;
|
||||||
|
|
||||||
|
_port_connection_queue.reserve (128);
|
||||||
}
|
}
|
||||||
|
|
||||||
AlsaAudioBackend::~AlsaAudioBackend ()
|
AlsaAudioBackend::~AlsaAudioBackend ()
|
||||||
|
|
@ -1693,11 +1695,11 @@ AlsaAudioBackend::midi_event_get (
|
||||||
if (event_index >= source.size ()) {
|
if (event_index >= source.size ()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
AlsaMidiEvent * const event = source[event_index].get ();
|
AlsaMidiEvent const& event = source[event_index];
|
||||||
|
|
||||||
timestamp = event->timestamp ();
|
timestamp = event.timestamp ();
|
||||||
size = event->size ();
|
size = event.size ();
|
||||||
*buf = event->data ();
|
*buf = event.data ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1708,15 +1710,18 @@ AlsaAudioBackend::midi_event_put (
|
||||||
const uint8_t* buffer, size_t size)
|
const uint8_t* buffer, size_t size)
|
||||||
{
|
{
|
||||||
assert (buffer && port_buffer);
|
assert (buffer && port_buffer);
|
||||||
|
if (size >= MaxAlsaMidiEventSize) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
|
AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
|
||||||
if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
if (dst.size () && (pframes_t)dst.back ().timestamp () > timestamp) {
|
||||||
// nevermind, ::get_buffer() sorts events
|
// nevermind, ::get_buffer() sorts events
|
||||||
fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
|
fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
|
||||||
(pframes_t)dst.back ()->timestamp (), timestamp);
|
(pframes_t)dst.back ().timestamp (), timestamp);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
dst.push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (timestamp, buffer, size)));
|
#endif
|
||||||
|
dst.push_back (AlsaMidiEvent (timestamp, buffer, size));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1949,7 +1954,7 @@ AlsaAudioBackend::main_process_thread ()
|
||||||
AlsaMidiIn *rm = _rmidi_in.at(i);
|
AlsaMidiIn *rm = _rmidi_in.at(i);
|
||||||
void *bptr = (*it)->get_buffer(0);
|
void *bptr = (*it)->get_buffer(0);
|
||||||
pframes_t time;
|
pframes_t time;
|
||||||
uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
|
uint8_t data[MaxAlsaMidiEventSize];
|
||||||
size_t size = sizeof(data);
|
size_t size = sizeof(data);
|
||||||
midi_clear(bptr);
|
midi_clear(bptr);
|
||||||
while (rm->recv_event (time, data, size)) {
|
while (rm->recv_event (time, data, size)) {
|
||||||
|
|
@ -1983,7 +1988,7 @@ AlsaAudioBackend::main_process_thread ()
|
||||||
AlsaMidiOut *rm = _rmidi_out.at(i);
|
AlsaMidiOut *rm = _rmidi_out.at(i);
|
||||||
rm->sync_time (clock1);
|
rm->sync_time (clock1);
|
||||||
for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
|
for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
|
||||||
rm->send_event ((*mit)->timestamp(), (*mit)->data(), (*mit)->size());
|
rm->send_event (mit->timestamp (), mit->data (), mit->size ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2321,13 +2326,18 @@ AlsaMidiPort::AlsaMidiPort (AlsaAudioBackend &b, const std::string& name, PortFl
|
||||||
{
|
{
|
||||||
_buffer[0].clear ();
|
_buffer[0].clear ();
|
||||||
_buffer[1].clear ();
|
_buffer[1].clear ();
|
||||||
|
_buffer[2].clear ();
|
||||||
|
|
||||||
|
_buffer[0].reserve(256);
|
||||||
|
_buffer[1].reserve(256);
|
||||||
|
_buffer[2].reserve(256);
|
||||||
}
|
}
|
||||||
|
|
||||||
AlsaMidiPort::~AlsaMidiPort () { }
|
AlsaMidiPort::~AlsaMidiPort () { }
|
||||||
|
|
||||||
struct MidiEventSorter {
|
struct MidiEventSorter {
|
||||||
bool operator() (const boost::shared_ptr<AlsaMidiEvent>& a, const boost::shared_ptr<AlsaMidiEvent>& b) {
|
bool operator() (AlsaMidiEvent const& a, AlsaMidiEvent const& b) {
|
||||||
return *a < *b;
|
return a < b;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2341,7 +2351,7 @@ void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
|
||||||
++i) {
|
++i) {
|
||||||
const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
|
const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
|
||||||
for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
|
for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
|
||||||
(_buffer[_bufperiod]).push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (**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());
|
||||||
|
|
@ -2352,10 +2362,8 @@ void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
|
||||||
AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
|
AlsaMidiEvent::AlsaMidiEvent (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 < MaxAlsaMidiEventSize) {
|
||||||
_data = (uint8_t*) malloc (size);
|
|
||||||
memcpy (_data, data, size);
|
memcpy (_data, data, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2363,14 +2371,9 @@ AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, si
|
||||||
AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other)
|
AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& 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 < MaxAlsaMidiEventSize);
|
||||||
memcpy (_data, other.const_data (), other.size ());
|
memcpy (_data, other._data, other._size);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AlsaMidiEvent::~AlsaMidiEvent () {
|
|
||||||
free (_data);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -50,19 +50,17 @@ class AlsaMidiEvent {
|
||||||
public:
|
public:
|
||||||
AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
|
AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
|
||||||
AlsaMidiEvent (const AlsaMidiEvent& other);
|
AlsaMidiEvent (const AlsaMidiEvent& other);
|
||||||
~AlsaMidiEvent ();
|
|
||||||
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* data () const { return _data; };
|
||||||
unsigned char* data () { return _data; };
|
|
||||||
bool operator< (const AlsaMidiEvent &other) const { return timestamp () < other.timestamp (); };
|
bool operator< (const AlsaMidiEvent &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[MaxAlsaMidiEventSize];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<boost::shared_ptr<AlsaMidiEvent> > AlsaMidiBuffer;
|
typedef std::vector<AlsaMidiEvent> AlsaMidiBuffer;
|
||||||
|
|
||||||
class AlsaPort {
|
class AlsaPort {
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,10 @@
|
||||||
#include "pbd/ringbuffer.h"
|
#include "pbd/ringbuffer.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
|
||||||
|
/* max bytes per individual midi-event
|
||||||
|
* events larger than this are ignored */
|
||||||
|
#define MaxAlsaMidiEventSize (64)
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class AlsaMidiIO {
|
class AlsaMidiIO {
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,6 @@
|
||||||
|
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
|
||||||
/* max bytes per individual midi-event
|
|
||||||
* events larger than this are ignored */
|
|
||||||
#define MaxAlsaRawEventSize (64)
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define _DEBUGPRINT(STR) fprintf(stderr, STR);
|
#define _DEBUGPRINT(STR) fprintf(stderr, STR);
|
||||||
#else
|
#else
|
||||||
|
|
@ -123,7 +119,7 @@ AlsaRawMidiOut::main_process_thread ()
|
||||||
while (_running) {
|
while (_running) {
|
||||||
bool have_data = false;
|
bool have_data = false;
|
||||||
struct MidiEventHeader h(0,0);
|
struct MidiEventHeader h(0,0);
|
||||||
uint8_t data[MaxAlsaRawEventSize];
|
uint8_t data[MaxAlsaMidiEventSize];
|
||||||
|
|
||||||
const uint32_t read_space = _rb->read_space();
|
const uint32_t read_space = _rb->read_space();
|
||||||
|
|
||||||
|
|
@ -133,7 +129,7 @@ AlsaRawMidiOut::main_process_thread ()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert (read_space >= h.size);
|
assert (read_space >= h.size);
|
||||||
if (h.size > MaxAlsaRawEventSize) {
|
if (h.size > MaxAlsaMidiEventSize) {
|
||||||
_rb->increment_read_idx (h.size);
|
_rb->increment_read_idx (h.size);
|
||||||
_DEBUGPRINT("AlsaRawMidiOut: MIDI event too large!\n");
|
_DEBUGPRINT("AlsaRawMidiOut: MIDI event too large!\n");
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -280,7 +276,7 @@ AlsaRawMidiIn::main_process_thread ()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[MaxAlsaRawEventSize];
|
uint8_t data[MaxAlsaMidiEventSize];
|
||||||
uint64_t time = g_get_monotonic_time();
|
uint64_t time = g_get_monotonic_time();
|
||||||
ssize_t err = snd_rawmidi_read (_device, data, sizeof(data));
|
ssize_t err = snd_rawmidi_read (_device, data, sizeof(data));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,6 @@
|
||||||
|
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
|
||||||
/* max bytes per individual midi-event
|
|
||||||
* events larger than this are ignored */
|
|
||||||
#define MaxAlsaSeqEventSize (64)
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define _DEBUGPRINT(STR) fprintf(stderr, STR);
|
#define _DEBUGPRINT(STR) fprintf(stderr, STR);
|
||||||
#else
|
#else
|
||||||
|
|
@ -130,12 +126,12 @@ AlsaSeqMidiOut::main_process_thread ()
|
||||||
_running = true;
|
_running = true;
|
||||||
bool need_drain = false;
|
bool need_drain = false;
|
||||||
snd_midi_event_t *alsa_codec = NULL;
|
snd_midi_event_t *alsa_codec = NULL;
|
||||||
snd_midi_event_new (MaxAlsaSeqEventSize, &alsa_codec);
|
snd_midi_event_new (MaxAlsaMidiEventSize, &alsa_codec);
|
||||||
pthread_mutex_lock (&_notify_mutex);
|
pthread_mutex_lock (&_notify_mutex);
|
||||||
while (_running) {
|
while (_running) {
|
||||||
bool have_data = false;
|
bool have_data = false;
|
||||||
struct MidiEventHeader h(0,0);
|
struct MidiEventHeader h(0,0);
|
||||||
uint8_t data[MaxAlsaSeqEventSize];
|
uint8_t data[MaxAlsaMidiEventSize];
|
||||||
|
|
||||||
const uint32_t read_space = _rb->read_space();
|
const uint32_t read_space = _rb->read_space();
|
||||||
|
|
||||||
|
|
@ -145,7 +141,7 @@ AlsaSeqMidiOut::main_process_thread ()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert (read_space >= h.size);
|
assert (read_space >= h.size);
|
||||||
if (h.size > MaxAlsaSeqEventSize) {
|
if (h.size > MaxAlsaMidiEventSize) {
|
||||||
_rb->increment_read_idx (h.size);
|
_rb->increment_read_idx (h.size);
|
||||||
_DEBUGPRINT("AlsaSeqMidiOut: MIDI event too large!\n");
|
_DEBUGPRINT("AlsaSeqMidiOut: MIDI event too large!\n");
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -240,7 +236,7 @@ AlsaSeqMidiIn::main_process_thread ()
|
||||||
_running = true;
|
_running = true;
|
||||||
bool do_poll = true;
|
bool do_poll = true;
|
||||||
snd_midi_event_t *alsa_codec = NULL;
|
snd_midi_event_t *alsa_codec = NULL;
|
||||||
snd_midi_event_new (MaxAlsaSeqEventSize, &alsa_codec);
|
snd_midi_event_new (MaxAlsaMidiEventSize, &alsa_codec);
|
||||||
|
|
||||||
while (_running) {
|
while (_running) {
|
||||||
|
|
||||||
|
|
@ -275,7 +271,7 @@ AlsaSeqMidiIn::main_process_thread ()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[MaxAlsaSeqEventSize];
|
uint8_t data[MaxAlsaMidiEventSize];
|
||||||
snd_midi_event_reset_decode (alsa_codec);
|
snd_midi_event_reset_decode (alsa_codec);
|
||||||
ssize_t size = snd_midi_event_decode (alsa_codec, data, sizeof(data), event);
|
ssize_t size = snd_midi_event_decode (alsa_codec, data, sizeof(data), event);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue