Improve reliability of MIDI event rec-box
Previously there was a race condition. DiskWriter::run() cleared the gui_feed_buffer before writing new events. If the GUI thread had not yet picked up the events by then they were not displayed. Furthermore due to the try-lock, some events may have been written to the buffer in the first place. This fixes missing events (notably stuck notes) in the red record box while recording MIDI.
This commit is contained in:
parent
9df6d7c5fa
commit
a1ba561cc5
@ -26,6 +26,7 @@
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "ardour/disk_io.h"
|
||||
#include "ardour/event_ring_buffer.h"
|
||||
#include "ardour/midi_buffer.h"
|
||||
|
||||
namespace ARDOUR
|
||||
@ -201,8 +202,8 @@ private:
|
||||
/** A buffer that we use to put newly-arrived MIDI data in for
|
||||
* the GUI to read (so that it can update itself).
|
||||
*/
|
||||
MidiBuffer _gui_feed_buffer;
|
||||
mutable Glib::Threads::Mutex _gui_feed_buffer_mutex;
|
||||
mutable EventRingBuffer<samplepos_t> _gui_feed_fifo;
|
||||
mutable Glib::Threads::Mutex _gui_feed_reset_mutex;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -60,7 +60,7 @@ DiskWriter::DiskWriter (Session& s, Track& t, string const & str, DiskIOProcesso
|
||||
, _accumulated_capture_offset (0)
|
||||
, _transport_looped (false)
|
||||
, _transport_loop_sample (0)
|
||||
, _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
|
||||
, _gui_feed_fifo (AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
|
||||
{
|
||||
DiskIOProcessor::init ();
|
||||
_xruns.reserve (128);
|
||||
@ -684,25 +684,18 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
|
||||
_samples_pending_write.fetch_add ((int) nframes);
|
||||
|
||||
if (buf.size() != 0) {
|
||||
Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex, Glib::Threads::TRY_LOCK);
|
||||
|
||||
if (lm.locked ()) {
|
||||
/* Copy this data into our GUI feed buffer and tell the GUI
|
||||
that it can read it if it likes.
|
||||
*/
|
||||
_gui_feed_buffer.clear ();
|
||||
|
||||
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
|
||||
/* This may fail if buf is larger than _gui_feed_buffer, but it's not really
|
||||
* the end of the world if it does.
|
||||
*/
|
||||
samplepos_t mpos = (*i).time() + start_sample - _accumulated_capture_offset;
|
||||
if (mpos >= _first_recordable_sample) {
|
||||
_gui_feed_buffer.push_back (mpos, Evoral::MIDI_EVENT, (*i).size(), (*i).buffer());
|
||||
}
|
||||
/* Copy this data into our GUI feed buffer and tell the GUI
|
||||
* that it can read it if it likes.
|
||||
*/
|
||||
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
|
||||
/* This may fail if buf is larger than _gui_feed_fifo, but it's not really
|
||||
* the end of the world if it does.
|
||||
*/
|
||||
samplepos_t mpos = (*i).time() + start_sample - _accumulated_capture_offset;
|
||||
if (mpos >= _first_recordable_sample) {
|
||||
_gui_feed_fifo.write (mpos, Evoral::MIDI_EVENT, (*i).size(), (*i).buffer());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (cnt) {
|
||||
@ -807,10 +800,18 @@ DiskWriter::finish_capture (std::shared_ptr<ChannelList const> c)
|
||||
std::shared_ptr<MidiBuffer>
|
||||
DiskWriter::get_gui_feed_buffer () const
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_gui_feed_reset_mutex);
|
||||
std::shared_ptr<MidiBuffer> b (new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)));
|
||||
|
||||
Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex);
|
||||
b->copy (_gui_feed_buffer);
|
||||
vector<MIDI::byte> buffer (_gui_feed_fifo.capacity());
|
||||
samplepos_t time;
|
||||
Evoral::EventType type;
|
||||
uint32_t size;
|
||||
|
||||
while (_gui_feed_fifo.read (&time, &type, &size, &buffer[0])) {
|
||||
b->push_back (time, type, size, &buffer[0]);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -1191,6 +1192,11 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
|
||||
|
||||
finish_capture (c);
|
||||
|
||||
{
|
||||
Glib::Threads::Mutex::Lock lm (_gui_feed_reset_mutex);
|
||||
_gui_feed_fifo.reset ();
|
||||
}
|
||||
|
||||
/* butler is already stopped, but there may be work to do
|
||||
to flush remaining data to disk.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user