13
0

implement midi capture alignment:

For audio: not writing frames to the capture ringbuffer offsets
the recording.
For midi: we need to keep track of the record range
and subtract the accumulated difference from the event time.
This commit is contained in:
Robin Gareus 2014-06-08 01:07:03 +02:00
parent 5a41487a08
commit 6416a429a8
2 changed files with 29 additions and 6 deletions

View File

@ -173,6 +173,7 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
gint _frames_read_from_ringbuffer;
volatile gint _frames_pending_write;
volatile gint _num_captured_loops;
framepos_t _accumulated_capture_offset;
/** A buffer that we use to put newly-arrived MIDI data in for
the GUI to read (so that it can update itself).

View File

@ -75,6 +75,7 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
, _frames_read_from_ringbuffer(0)
, _frames_pending_write(0)
, _num_captured_loops(0)
, _accumulated_capture_offset(0)
, _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
{
in_set_state = true;
@ -99,6 +100,7 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
, _frames_read_from_ringbuffer(0)
, _frames_pending_write(0)
, _num_captured_loops(0)
, _accumulated_capture_offset(0)
, _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
{
in_set_state = true;
@ -362,6 +364,15 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
calculate_record_range(ot, transport_frame, nframes, rec_nframes, rec_offset);
/* For audio: not writing frames to the capture ringbuffer offsets
* the recording. For midi: we need to keep track of the record range
* and subtract the accumulated difference from the event time.
*/
if (rec_nframes) {
_accumulated_capture_offset += rec_offset;
} else {
_accumulated_capture_offset += nframes;
}
if (rec_nframes && !was_recording) {
if (loop_loc) {
@ -394,6 +405,9 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
if (ev.time() + rec_offset > rec_nframes) {
break;
}
#ifndef NDEBUG
if (DEBUG::MidiIO & PBD::debug_bits) {
const uint8_t* __data = ev.buffer();
@ -416,23 +430,26 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
any desirable behaviour. We don't want to send event with
transport time here since that way the source can not
reconstruct their actual time; future clever MIDI looping should
probabl be implemented in the source instead of here.
probably be implemented in the source instead of here.
*/
const framecnt_t loop_offset = _num_captured_loops * loop_length;
const framepos_t event_time = transport_frame + loop_offset - _accumulated_capture_offset + ev.time();
if (event_time < 0 || event_time < first_recordable_frame) {
continue;
}
switch (mode) {
case AllChannels:
_capture_buf->write(transport_frame + loop_offset + ev.time(),
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
break;
case FilterChannels:
if (ev.is_channel_event()) {
if ((1<<ev.channel()) & mask) {
_capture_buf->write(transport_frame + loop_offset + ev.time(),
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
}
} else {
_capture_buf->write(transport_frame + loop_offset + ev.time(),
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
}
break;
@ -440,7 +457,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
if (ev.is_channel_event()) {
ev.set_channel (PBD::ffs(mask) - 1);
}
_capture_buf->write(transport_frame + loop_offset + ev.time(),
_capture_buf->write(event_time,
ev.type(), ev.size(), ev.buffer());
break;
}
@ -472,6 +489,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
if (was_recording) {
finish_capture ();
}
_accumulated_capture_offset = 0;
}
@ -972,6 +990,10 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
RegionFactory::region_name (region_name, _write_source->name(), false);
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n",
_name, (*ci)->start, (*ci)->frames, region_name));
// cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
try {