mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-23 15:16:25 +01:00
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:
parent
5a41487a08
commit
6416a429a8
2 changed files with 29 additions and 6 deletions
|
|
@ -173,6 +173,7 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
|
||||||
gint _frames_read_from_ringbuffer;
|
gint _frames_read_from_ringbuffer;
|
||||||
volatile gint _frames_pending_write;
|
volatile gint _frames_pending_write;
|
||||||
volatile gint _num_captured_loops;
|
volatile gint _num_captured_loops;
|
||||||
|
framepos_t _accumulated_capture_offset;
|
||||||
|
|
||||||
/** A buffer that we use to put newly-arrived MIDI data in for
|
/** A buffer that we use to put newly-arrived MIDI data in for
|
||||||
the GUI to read (so that it can update itself).
|
the GUI to read (so that it can update itself).
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
|
||||||
, _frames_read_from_ringbuffer(0)
|
, _frames_read_from_ringbuffer(0)
|
||||||
, _frames_pending_write(0)
|
, _frames_pending_write(0)
|
||||||
, _num_captured_loops(0)
|
, _num_captured_loops(0)
|
||||||
|
, _accumulated_capture_offset(0)
|
||||||
, _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
|
, _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
|
||||||
{
|
{
|
||||||
in_set_state = true;
|
in_set_state = true;
|
||||||
|
|
@ -99,6 +100,7 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
|
||||||
, _frames_read_from_ringbuffer(0)
|
, _frames_read_from_ringbuffer(0)
|
||||||
, _frames_pending_write(0)
|
, _frames_pending_write(0)
|
||||||
, _num_captured_loops(0)
|
, _num_captured_loops(0)
|
||||||
|
, _accumulated_capture_offset(0)
|
||||||
, _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
|
, _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
|
||||||
{
|
{
|
||||||
in_set_state = true;
|
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);
|
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);
|
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 (rec_nframes && !was_recording) {
|
||||||
if (loop_loc) {
|
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) {
|
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
|
||||||
Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
|
Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
|
||||||
|
if (ev.time() + rec_offset > rec_nframes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (DEBUG::MidiIO & PBD::debug_bits) {
|
if (DEBUG::MidiIO & PBD::debug_bits) {
|
||||||
const uint8_t* __data = ev.buffer();
|
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
|
any desirable behaviour. We don't want to send event with
|
||||||
transport time here since that way the source can not
|
transport time here since that way the source can not
|
||||||
reconstruct their actual time; future clever MIDI looping should
|
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 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) {
|
switch (mode) {
|
||||||
case AllChannels:
|
case AllChannels:
|
||||||
_capture_buf->write(transport_frame + loop_offset + ev.time(),
|
_capture_buf->write(event_time,
|
||||||
ev.type(), ev.size(), ev.buffer());
|
ev.type(), ev.size(), ev.buffer());
|
||||||
break;
|
break;
|
||||||
case FilterChannels:
|
case FilterChannels:
|
||||||
if (ev.is_channel_event()) {
|
if (ev.is_channel_event()) {
|
||||||
if ((1<<ev.channel()) & mask) {
|
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());
|
ev.type(), ev.size(), ev.buffer());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_capture_buf->write(transport_frame + loop_offset + ev.time(),
|
_capture_buf->write(event_time,
|
||||||
ev.type(), ev.size(), ev.buffer());
|
ev.type(), ev.size(), ev.buffer());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -440,7 +457,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
|
||||||
if (ev.is_channel_event()) {
|
if (ev.is_channel_event()) {
|
||||||
ev.set_channel (PBD::ffs(mask) - 1);
|
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());
|
ev.type(), ev.size(), ev.buffer());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -472,6 +489,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
|
||||||
if (was_recording) {
|
if (was_recording) {
|
||||||
finish_capture ();
|
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);
|
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";
|
// cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue