mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-15 02:56:35 +01:00
Fix MIDI playback.
git-svn-id: svn://localhost/ardour2/branches/3.0@5024 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
3014d23801
commit
848df74e58
9 changed files with 38 additions and 57 deletions
|
|
@ -128,7 +128,7 @@ class MidiDiskstream : public Diskstream
|
||||||
void non_realtime_input_change ();
|
void non_realtime_input_change ();
|
||||||
void non_realtime_locate (nframes_t location);
|
void non_realtime_locate (nframes_t location);
|
||||||
|
|
||||||
static void set_readahed_frames( nframes_t frames_ahead ) { midi_readahead = frames_ahead; }
|
static void set_readahead_frames(nframes_t frames_ahead) { midi_readahead = frames_ahead; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int seek (nframes_t which_sample, bool complete_refill = false);
|
int seek (nframes_t which_sample, bool complete_refill = false);
|
||||||
|
|
|
||||||
|
|
@ -652,8 +652,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
|
||||||
|
|
||||||
chaninfo->current_capture_buffer = chaninfo->capture_vector.buf[0];
|
chaninfo->current_capture_buffer = chaninfo->capture_vector.buf[0];
|
||||||
|
|
||||||
/* note: grab the entire port buffer, but only copy what we were supposed to for recording, and use
|
/* note: grab the entire port buffer, but only copy what we were supposed to
|
||||||
rec_offset
|
for recording, and use rec_offset
|
||||||
*/
|
*/
|
||||||
|
|
||||||
AudioPort* const ap = _io->audio_input(n);
|
AudioPort* const ap = _io->audio_input(n);
|
||||||
|
|
|
||||||
|
|
@ -111,10 +111,8 @@ bool
|
||||||
MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
|
MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
|
||||||
{
|
{
|
||||||
const size_t stamp_size = sizeof(TimeType);
|
const size_t stamp_size = sizeof(TimeType);
|
||||||
/*cerr << "MidiBuffer: pushing event " << " size: " << _size
|
/*cerr << "MidiBuffer: pushing event @ " << ev.time()
|
||||||
<< " event size: " << ev.size()
|
<< " size = " << ev.size() << endl;*/
|
||||||
<< " capacity: " << _capacity
|
|
||||||
<< " stamp size: " << stamp_size << " \n";*/
|
|
||||||
|
|
||||||
if (_size + stamp_size + ev.size() >= _capacity) {
|
if (_size + stamp_size + ev.size() >= _capacity) {
|
||||||
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
|
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
|
||||||
|
|
|
||||||
|
|
@ -542,10 +542,8 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
|
||||||
/* data will be written to disk */
|
/* data will be written to disk */
|
||||||
|
|
||||||
if (rec_nframes == nframes && rec_offset == 0) {
|
if (rec_nframes == nframes && rec_offset == 0) {
|
||||||
|
|
||||||
playback_distance = nframes;
|
playback_distance = nframes;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
collect_playback = true;
|
collect_playback = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -615,20 +613,15 @@ MidiDiskstream::commit (nframes_t nframes)
|
||||||
adjust_capture_position = 0;
|
adjust_capture_position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* what audio does:
|
|
||||||
* can't do this with midi: write space is in bytes, chunk_frames is in frames
|
|
||||||
if (_slaved) {
|
|
||||||
need_butler = _playback_buf->write_space() >= _playback_buf->capacity() / 2;
|
|
||||||
} else {
|
|
||||||
need_butler = _playback_buf->write_space() >= disk_io_chunk_frames
|
|
||||||
|| _capture_buf->read_space() >= disk_io_chunk_frames;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Use The Counters To calculate how much time the Ringbuffer holds.
|
|
||||||
uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
|
uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
|
||||||
uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
|
uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
|
||||||
if ((frames_written - frames_read) <= midi_readahead)
|
if ((frames_written - frames_read) + nframes < midi_readahead) {
|
||||||
need_butler = true;
|
need_butler = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*cerr << "MDS written: " << frames_written << " - read: " << frames_read <<
|
||||||
|
" = " << frames_written - frames_read
|
||||||
|
<< " + " << nframes << " < " << midi_readahead << " = " << need_butler << ")" << endl;*/
|
||||||
|
|
||||||
if (commit_should_unlock) {
|
if (commit_should_unlock) {
|
||||||
state_lock.unlock();
|
state_lock.unlock();
|
||||||
|
|
@ -685,13 +678,9 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill)
|
||||||
int
|
int
|
||||||
MidiDiskstream::can_internal_playback_seek (nframes_t distance)
|
MidiDiskstream::can_internal_playback_seek (nframes_t distance)
|
||||||
{
|
{
|
||||||
uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
|
uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
|
||||||
uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
|
uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
|
||||||
if ((frames_written-frames_read) < distance) {
|
return ((frames_written - frames_read) < distance);
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -763,11 +752,13 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
|
||||||
this_read = min(dur,this_read);
|
this_read = min(dur,this_read);
|
||||||
|
|
||||||
if (midi_playlist()->read (*_playback_buf, start, this_read) != this_read) {
|
if (midi_playlist()->read (*_playback_buf, start, this_read) != this_read) {
|
||||||
error << string_compose(_("MidiDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read,
|
error << string_compose(
|
||||||
start) << endmsg;
|
_("MidiDiskstream %1: cannot read %2 from playlist at frame %3"),
|
||||||
|
_id, this_read, start) << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
//cout << "this write " << this_read << "start= " << start << endl;
|
|
||||||
|
//cout << "MDS this read " << this_read << " start = " << start << endl;
|
||||||
g_atomic_int_add(&_frames_written_to_ringbuffer, this_read);
|
g_atomic_int_add(&_frames_written_to_ringbuffer, this_read);
|
||||||
|
|
||||||
_read_data_count = _playlist->read_data_count();
|
_read_data_count = _playlist->read_data_count();
|
||||||
|
|
@ -775,7 +766,7 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
|
||||||
if (reversed) {
|
if (reversed) {
|
||||||
|
|
||||||
// Swap note ons with note offs here. etc?
|
// Swap note ons with note offs here. etc?
|
||||||
// Fully reversing MIDI required look-ahead (well, behind) to find previous
|
// Fully reversing MIDI requires look-ahead (well, behind) to find previous
|
||||||
// CC values etc. hard.
|
// CC values etc. hard.
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -836,14 +827,15 @@ MidiDiskstream::do_refill ()
|
||||||
// and lets write as much as we need to get this to be midi_readahead;
|
// and lets write as much as we need to get this to be midi_readahead;
|
||||||
uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
|
uint32_t frames_read = g_atomic_int_get(&_frames_read_from_ringbuffer);
|
||||||
uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
|
uint32_t frames_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
|
||||||
if ((frames_written-frames_read) >= midi_readahead) {
|
if ((frames_written - frames_read) >= midi_readahead) {
|
||||||
//cout << "Nothing to do. all fine" << endl;
|
//cout << "MDS Nothing to do. all fine" << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nframes_t to_read = midi_readahead - (frames_written - frames_read);
|
nframes_t to_read = midi_readahead - (frames_written - frames_read);
|
||||||
|
|
||||||
//cout << "read for midi_readahead " << to_read << " rb_contains: " << frames_written-frames_read << endl;
|
//cout << "MDS read for midi_readahead " << to_read << " rb_contains: "
|
||||||
|
// << frames_written - frames_read << endl;
|
||||||
|
|
||||||
to_read = min(to_read, (max_frames - file_frame));
|
to_read = min(to_read, (max_frames - file_frame));
|
||||||
|
|
||||||
|
|
@ -1494,8 +1486,8 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end)
|
||||||
_playback_buf->read(dst, start, end);
|
_playback_buf->read(dst, start, end);
|
||||||
#else
|
#else
|
||||||
const size_t events_read = _playback_buf->read(dst, start, end);
|
const size_t events_read = _playback_buf->read(dst, start, end);
|
||||||
cout << "frames read = " << frames_read << " events read = " << events_read
|
cout << "MDS events read = " << events_read
|
||||||
<< " end = " << end << " start = " << start
|
<< " start = " << start << " end = " << end
|
||||||
<< " readspace " << _playback_buf->read_space()
|
<< " readspace " << _playback_buf->read_space()
|
||||||
<< " writespace " << _playback_buf->write_space() << endl;
|
<< " writespace " << _playback_buf->write_space() << endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,6 @@ MidiPlaylist::read (MidiRingBuffer<nframes_t>& dst, nframes_t start, nframes_t d
|
||||||
vector<boost::shared_ptr<Region> > regs;
|
vector<boost::shared_ptr<Region> > regs;
|
||||||
|
|
||||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||||
|
|
||||||
if ((*i)->coverage (start, end) != OverlapNone) {
|
if ((*i)->coverage (start, end) != OverlapNone) {
|
||||||
regs.push_back(*i);
|
regs.push_back(*i);
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +149,6 @@ MidiPlaylist::read (MidiRingBuffer<nframes_t>& dst, nframes_t start, nframes_t d
|
||||||
sort(regs.begin(), regs.end(), layer_cmp);
|
sort(regs.begin(), regs.end(), layer_cmp);
|
||||||
|
|
||||||
for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) {
|
for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) {
|
||||||
// FIXME: ensure time is monotonic here?
|
|
||||||
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*i);
|
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*i);
|
||||||
if (mr) {
|
if (mr) {
|
||||||
mr->read_at (dst, start, dur, chan_n, _note_mode);
|
mr->read_at (dst, start, dur, chan_n, _note_mode);
|
||||||
|
|
|
||||||
|
|
@ -144,9 +144,6 @@ MidiRegion::master_read_at (MidiRingBuffer<nframes_t>& out, sframes_t position,
|
||||||
nframes_t
|
nframes_t
|
||||||
MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer<nframes_t>& dst, nframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const
|
MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer<nframes_t>& dst, nframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const
|
||||||
{
|
{
|
||||||
/*cerr << "MidiRegion " << _name << "._read_at(" << position << ") - "
|
|
||||||
<< position << " duration: " << dur << endl;*/
|
|
||||||
|
|
||||||
nframes_t internal_offset = 0;
|
nframes_t internal_offset = 0;
|
||||||
nframes_t src_offset = 0;
|
nframes_t src_offset = 0;
|
||||||
nframes_t to_read = 0;
|
nframes_t to_read = 0;
|
||||||
|
|
@ -168,7 +165,6 @@ MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer<nframes_t>& dst, nf
|
||||||
return 0; /* read nothing */
|
return 0; /* read nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((to_read = min (dur, _length - internal_offset)) == 0) {
|
if ((to_read = min (dur, _length - internal_offset)) == 0) {
|
||||||
return 0; /* read nothing */
|
return 0; /* read nothing */
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +195,7 @@ MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer<nframes_t>& dst, nf
|
||||||
if (src->midi_read (
|
if (src->midi_read (
|
||||||
dst, // destination buffer
|
dst, // destination buffer
|
||||||
_position - _start, // start position of the source in this read context
|
_position - _start, // start position of the source in this read context
|
||||||
_start + internal_offset, // where to start reading in the region
|
_start + internal_offset, // where to start reading in the source
|
||||||
to_read, // read duration in frames
|
to_read, // read duration in frames
|
||||||
output_buffer_position, // the offset in the output buffer
|
output_buffer_position, // the offset in the output buffer
|
||||||
negative_output_buffer_position // amount to substract from note times
|
negative_output_buffer_position // amount to substract from note times
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,10 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
|
||||||
this->full_peek(sizeof(T), (uint8_t*)&ev_time);
|
this->full_peek(sizeof(T), (uint8_t*)&ev_time);
|
||||||
|
|
||||||
if (ev_time > end) {
|
if (ev_time > end) {
|
||||||
//cerr << "MRB: PAST END (" << ev_time << " : " << end << ")" << endl;
|
//cerr << "MRB event @ " << ev_time << " past end @ " << end << endl;
|
||||||
break;
|
break;
|
||||||
} else if (ev_time < start) {
|
} else if (ev_time < start) {
|
||||||
//cerr << "MRB (start " << start << ") - Skipping event at (too early) time " << ev_time << endl;
|
//cerr << "MRB event @ " << ev_time << " before start @ " << start << endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,8 +63,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This event marks a loop happening. this means that
|
// This event marks a loop end (i.e. the next event's timestamp will be non-monotonic)
|
||||||
// the next events timestamp will be non-monotonic.
|
|
||||||
if (ev_type == LoopEventType) {
|
if (ev_type == LoopEventType) {
|
||||||
ev_time -= start;
|
ev_time -= start;
|
||||||
ev_time += offset;
|
ev_time += offset;
|
||||||
|
|
@ -73,6 +72,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
|
||||||
|
|
||||||
// We can safely return, without reading the data, because
|
// We can safely return, without reading the data, because
|
||||||
// a LoopEvent does not have data.
|
// a LoopEvent does not have data.
|
||||||
|
cerr << "MRB loop boundary @ " << ev_time << endl;
|
||||||
return count + 1;
|
return count + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,16 +83,16 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
|
||||||
// Ignore event if it doesn't match channel filter
|
// Ignore event if it doesn't match channel filter
|
||||||
if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
|
if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
|
||||||
const uint8_t channel = status & 0x0F;
|
const uint8_t channel = status & 0x0F;
|
||||||
if ( !(get_channel_mask() & (1L << channel)) ) {
|
if (!(get_channel_mask() & (1L << channel))) {
|
||||||
//cerr << "MRB skipping event due to channel mask" << endl;
|
//cerr << "MRB skipping event due to channel mask" << endl;
|
||||||
this->skip(ev_size); // Advance read pointer to next event
|
this->skip(ev_size); // Advance read pointer to next event
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//cerr << "MRB " << this << " - Reading event, time = "
|
/*cerr << "MRB " << this << " - Reading event, time = "
|
||||||
// << ev_time << " - " << start << " => " << ev_time - start
|
<< ev_time << " - " << start << " => " << ev_time - start
|
||||||
// << ", size = " << ev_size << endl;
|
<< ", size = " << ev_size << endl;*/
|
||||||
|
|
||||||
assert(ev_time >= start);
|
assert(ev_time >= start);
|
||||||
ev_time -= start;
|
ev_time -= start;
|
||||||
|
|
@ -119,14 +119,11 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
|
||||||
write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
|
write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
|
||||||
}
|
}
|
||||||
++count;
|
++count;
|
||||||
//cerr << "MRB - read event at time " << ev_time << endl;
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "WARNING: error reading event contents from MIDI ring" << endl;
|
cerr << "WARNING: error reading event contents from MIDI ring" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//cerr << "MTB read space: " << read_space() << endl;
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ MidiSource::midi_read (MidiRingBuffer<nframes_t>& dst, sframes_t source_start,
|
||||||
|
|
||||||
Evoral::Sequence<double>::const_iterator& i = _model_iter;
|
Evoral::Sequence<double>::const_iterator& i = _model_iter;
|
||||||
|
|
||||||
if (_last_read_end == 0 || start != _last_read_end || !i.valid()) {
|
if (_last_read_end == 0 || start != _last_read_end) { // || !i.valid()) {
|
||||||
cerr << "MidiSource seeking to " << start << " from " << _last_read_end << endl;
|
cerr << "MidiSource seeking to " << start << " from " << _last_read_end << endl;
|
||||||
for (i = _model->begin(); i != _model->end(); ++i) {
|
for (i = _model->begin(); i != _model->end(); ++i) {
|
||||||
if (BEATS_TO_FRAMES(i->time()) >= start) {
|
if (BEATS_TO_FRAMES(i->time()) >= start) {
|
||||||
|
|
@ -150,8 +150,8 @@ MidiSource::midi_read (MidiRingBuffer<nframes_t>& dst, sframes_t source_start,
|
||||||
_last_read_end = start + cnt;
|
_last_read_end = start + cnt;
|
||||||
|
|
||||||
for (; i != _model->end(); ++i) {
|
for (; i != _model->end(); ++i) {
|
||||||
const nframes_t time_frames = BEATS_TO_FRAMES(i->time());
|
const sframes_t time_frames = BEATS_TO_FRAMES(i->time());
|
||||||
if (time_frames < start + cnt) {
|
if (time_frames < source_start + start + cnt) {
|
||||||
dst.write(time_frames, i->event_type(), i->size(), i->buffer());
|
dst.write(time_frames, i->event_type(), i->size(), i->buffer());
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ Session::start_butler_thread ()
|
||||||
* (i.e. how many MIDI bytes we might see in a cycle)
|
* (i.e. how many MIDI bytes we might see in a cycle)
|
||||||
*/
|
*/
|
||||||
midi_dstream_buffer_size = (uint32_t) floor (Config->get_midi_track_buffer_seconds() * (float)frame_rate());
|
midi_dstream_buffer_size = (uint32_t) floor (Config->get_midi_track_buffer_seconds() * (float)frame_rate());
|
||||||
MidiDiskstream::set_readahed_frames ((nframes_t) (Config->get_midi_readahead() * (float) frame_rate()));
|
MidiDiskstream::set_readahead_frames ((nframes_t) (Config->get_midi_readahead() * (float) frame_rate()));
|
||||||
|
|
||||||
Crossfade::set_buffer_size (audio_dstream_buffer_size);
|
Crossfade::set_buffer_size (audio_dstream_buffer_size);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue