From fa4e858eb351668bc6687819903d019703daef7a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 16 Sep 2009 01:08:51 +0000 Subject: [PATCH] do not allow smf_source's reads to stomp on cached read_end position in parent class, which creates chaos by being out of sync with MidiSource::_model_iterator. this doesn't totally fix MIDI playback, but it helps git-svn-id: svn://localhost/ardour2/branches/3.0@5665 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/midi_ring_buffer.h | 1 + libs/ardour/ardour/smf_source.h | 1 + libs/ardour/midi_buffer.cc | 1 - libs/ardour/midi_diskstream.cc | 7 +- libs/ardour/midi_playlist.cc | 2 +- libs/ardour/midi_region.cc | 13 +++- libs/ardour/midi_ring_buffer.cc | 94 +++++++++++++++++++++++---- libs/ardour/midi_source.cc | 9 ++- libs/ardour/smf_source.cc | 8 ++- libs/evoral/evoral/Event.hpp | 6 +- libs/evoral/src/SMF.cpp | 8 +-- libs/evoral/src/Sequence.cpp | 10 +-- 12 files changed, 121 insertions(+), 39 deletions(-) diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index 228479067f..f879aa7534 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -51,6 +51,7 @@ public: inline bool read_contents(uint32_t size, uint8_t* buf); size_t read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset=0); + void dump(std::ostream& dst); /** Set the channel filtering mode. * @param mask If mode is FilterChannels, each bit represents a midi channel: diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 73bef5480a..025f770fc3 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -85,6 +85,7 @@ private: double _last_ev_time_beats; sframes_t _last_ev_time_frames; + mutable sframes_t _smf_last_read_end; }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc index 12b46e7f04..ae3071a53c 100644 --- a/libs/ardour/midi_buffer.cc +++ b/libs/ardour/midi_buffer.cc @@ -93,7 +93,6 @@ MidiBuffer::read_from (const Buffer& src, nframes_t nframes, nframes_t dst_offse const Evoral::MIDIEvent ev(*i, false); if (ev.time() >= src_offset && ev.time() < (nframes+src_offset)) { push_back (ev); - cerr << "got note " << ev << endl; } } diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 9c8c9e8620..6e57714ae2 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -858,8 +858,6 @@ MidiDiskstream::can_internal_playback_seek (nframes_t distance) int MidiDiskstream::internal_playback_seek (nframes_t distance) { - cerr << "MDS: internal_playback_seek " << distance << endl; - first_recordable_frame += distance; playback_sample += distance; @@ -929,8 +927,7 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed) _id, this_read, start) << endmsg; return -1; } - - //cout << "MDS this read " << this_read << " start = " << start << endl; + g_atomic_int_add(&_frames_written_to_ringbuffer, this_read); _read_data_count = _playlist->read_data_count(); @@ -1650,7 +1647,9 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end) // Translates stamps to be relative to start + _playback_buf->read(dst, start, end); + #if 0 const size_t events_read = _playback_buf->read(dst, start, end); cout << _name << ": MDS events read = " << events_read diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index 8f8b882d1e..82f8827f21 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -91,7 +91,7 @@ MidiPlaylist::MidiPlaylist (boost::shared_ptr other, string out_o++; out_n++; } - // cerr << "HUH!? second region in the crossfade not found!" << endl; + // cerr << "HUH!? second region in the crossfade not found!" << endl; } } diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 910789c7fb..aca8d039ad 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -147,7 +147,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, MidiRingBuffer& dst nframes_t internal_offset = 0; nframes_t src_offset = 0; nframes_t to_read = 0; - + /* precondition: caller has verified that we cover the desired section */ assert(chan_n == 0); @@ -191,7 +191,16 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, MidiRingBuffer& dst // _start from the note times in the midi source negative_output_buffer_position = _start; } - + +#if 0 + cerr << "\t\tsource read from " << _position << " - " << _start << " (" << _position - _start << ") " + << " start in source " << _start << " + " << internal_offset << " (" << _start + internal_offset << ") " + << " dur = " << to_read + << " offset = " << output_buffer_position + << " negoffset = " << negative_output_buffer_position + << endl; +#endif + if (src->midi_read ( dst, // destination buffer _position - _start, // start position of the source in this read context diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc index 88064c8798..5fcd3e8298 100644 --- a/libs/ardour/midi_ring_buffer.cc +++ b/libs/ardour/midi_ring_buffer.cc @@ -43,17 +43,15 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes size_t count = 0; - //cerr << "MRB read " << start << " .. " << end << " + " << offset << endl; - while (this->read_space() >= sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t)) { this->full_peek(sizeof(T), (uint8_t*)&ev_time); - + if (ev_time > end) { - //cerr << "MRB event @ " << ev_time << " past end @ " << end << endl; + // cerr << "MRB event @ " << ev_time << " past end @ " << end << endl; break; } else if (ev_time < start) { - //cerr << "MRB event @ " << ev_time << " before start @ " << start << endl; + // cerr << "MRB event @ " << ev_time << " before start @ " << start << endl; break; } @@ -67,7 +65,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes if (ev_type == LoopEventType) { /*ev_time -= start; ev_time += offset;*/ - cerr << "MRB loop boundary @ " << ev_time << endl; + // cerr << "MRB loop boundary @ " << ev_time << endl; // Return without reading data or writing to buffer (loop events have no data) // FIXME: This is not correct, loses events after the loop this cycle @@ -87,11 +85,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes continue; } } - - /*cerr << "MRB " << this << " - Reading event, time = " - << ev_time << " - " << start << " => " << ev_time - start - << ", size = " << ev_size << endl;*/ - + assert(ev_time >= start); ev_time -= start; ev_time += offset; @@ -126,6 +120,84 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes return count; } +template +void +MidiRingBuffer::dump(ostream& str) +{ + size_t rspace; + + if ((rspace = this->read_space()) == 0) { + str << "MRB::dump: empty\n"; + return; + } + + T ev_time; + Evoral::EventType ev_type; + uint32_t ev_size; + size_t read_ptr = g_atomic_int_get (&this->_read_ptr); + + str << "Dump @ " << read_ptr << endl; + + while (1) { + uint8_t* wp; + uint8_t* data; + size_t write_ptr; + +#define space(r,w) ((w > r) ? (w - r) : ((w - r + this->_size) % this->_size)) + + write_ptr = g_atomic_int_get (&this->_write_ptr); + if (space (read_ptr, write_ptr) < sizeof (T)) { + break; + } + + wp = &this->_buf[read_ptr]; + memcpy (&ev_time, wp, sizeof (T)); + read_ptr = (read_ptr + sizeof (T)) % this->_size; + str << "time " << ev_time; + + write_ptr = g_atomic_int_get (&this->_write_ptr); + if (space (read_ptr, write_ptr) < sizeof (ev_type)) { + break; + } + + wp = &this->_buf[read_ptr]; + memcpy (&ev_type, wp, sizeof (ev_type)); + read_ptr = (read_ptr + sizeof (ev_type)) % this->_size; + str << " type " << ev_type; + + write_ptr = g_atomic_int_get (&this->_write_ptr); + if (space (read_ptr, write_ptr) < sizeof (ev_size)) { + str << "!OUT!\n"; + break; + } + + wp = &this->_buf[read_ptr]; + memcpy (&ev_size, wp, sizeof (ev_size)); + read_ptr = (read_ptr + sizeof (ev_size)) % this->_size; + str << " size " << ev_size; + + write_ptr = g_atomic_int_get (&this->_write_ptr); + if (space (read_ptr, write_ptr) < ev_size) { + str << "!OUT!\n"; + break; + } + + data = new uint8_t[ev_size]; + + wp = &this->_buf[read_ptr]; + memcpy (data, wp, ev_size); + read_ptr = (read_ptr + ev_size) % this->_size; + + for (uint32_t i = 0; i != ev_size; ++i) { + str << ' ' << hex << (int) data[i] << dec; + } + + str << endl; + + delete [] data; + } +} + template class MidiRingBuffer; diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index f16ebf186f..4da2dbb845 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -137,16 +137,15 @@ MidiSource::midi_read (MidiRingBuffer& dst, sframes_t source_start, #define BEATS_TO_FRAMES(t) (converter.to(t) + stamp_offset - negative_stamp_offset) Evoral::Sequence::const_iterator& i = _model_iter; - - if (_last_read_end == 0 || start != _last_read_end) { // || !i.valid()) { - //cerr << "MidiSource seeking to " << start << " from " << _last_read_end << endl; + + if (_last_read_end == 0 || start != _last_read_end || !i.valid()) { for (i = _model->begin(); i != _model->end(); ++i) { if (BEATS_TO_FRAMES(i->time()) >= start) { break; } } } - + _last_read_end = start + cnt; for (; i != _model->end(); ++i) { @@ -234,7 +233,7 @@ MidiSource::session_saved() stringstream ss(basename.substr(last_dash+1)); unsigned write_count = 0; ss >> write_count; - cerr << "WRITE COUNT: " << write_count << endl; + // cerr << "WRITE COUNT: " << write_count << endl; ++write_count; // start at 1 ss.clear(); ss << basename.substr(0, last_dash) << "-" << write_count; diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 7db027124b..7fbc8b0287 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -55,6 +55,7 @@ SMFSource::SMFSource (Session& s, const ustring& path, bool embedded, Source::Fl , Evoral::SMF() , _last_ev_time_beats(0.0) , _last_ev_time_frames(0) + , _smf_last_read_end (0) { if (init(_name, false)) { throw failed_constructor (); @@ -72,6 +73,7 @@ SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist) , FileSource(s, node, must_exist) , _last_ev_time_beats(0.0) , _last_ev_time_frames(0) + , _smf_last_read_end (0) { if (set_state(node)) { throw failed_constructor (); @@ -116,20 +118,20 @@ SMFSource::read_unlocked (MidiRingBuffer& destination, sframes_t sour const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn()); - if (_last_read_end == 0 || start != _last_read_end) { + if (_smf_last_read_end == 0 || start != _smf_last_read_end) { //cerr << "SMFSource::read_unlocked seeking to " << start << endl; Evoral::SMF::seek_to_start(); while (time < start_ticks) { ret = read_event(&ev_delta_t, &ev_size, &ev_buffer); if (ret == -1) { // EOF - _last_read_end = start + duration; + _smf_last_read_end = start + duration; return duration; } time += ev_delta_t; // accumulate delta time } } - _last_read_end = start + duration; + _smf_last_read_end = start + duration; while (true) { ret = read_event(&ev_delta_t, &ev_size, &ev_buffer); diff --git a/libs/evoral/evoral/Event.hpp b/libs/evoral/evoral/Event.hpp index 3e8e05fa3b..cc24ac87f7 100644 --- a/libs/evoral/evoral/Event.hpp +++ b/libs/evoral/evoral/Event.hpp @@ -199,12 +199,12 @@ protected: template std::ostream& operator<<(std::ostream& o, const Evoral::Event