Fix MIDI playback.
authorDavid Robillard <d@drobilla.net>
Fri, 1 May 2009 17:32:48 +0000 (17:32 +0000)
committerDavid Robillard <d@drobilla.net>
Fri, 1 May 2009 17:32:48 +0000 (17:32 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5024 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/midi_diskstream.h
libs/ardour/audio_diskstream.cc
libs/ardour/midi_buffer.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_playlist.cc
libs/ardour/midi_region.cc
libs/ardour/midi_ring_buffer.cc
libs/ardour/midi_source.cc
libs/ardour/session_butler.cc

index 26198e1c62ab834b9ead62348e86ff6fc00fe562..839e35ea5b59442d03e5ccee68e92e5538f73b4f 100644 (file)
@@ -128,7 +128,7 @@ class MidiDiskstream : public Diskstream
        void non_realtime_input_change ();
        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:
        int seek (nframes_t which_sample, bool complete_refill = false);
index 960112a997abf7b466f3aa75d5a352a00b478fe6..d424d81c11b3cef02a36980da36a31b03f122c6b 100644 (file)
@@ -652,8 +652,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
                                
                                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
-                                  rec_offset
+                               /* note: grab the entire port buffer, but only copy what we were supposed to
+                                  for recording, and use rec_offset
                                */
 
                                AudioPort* const ap = _io->audio_input(n);
index e6a6fbf447e94ae964dc40820b8530636575e3ba..2a1426ab61f6b7b7242b60d6f56e288ba471338a 100644 (file)
@@ -111,10 +111,8 @@ bool
 MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
 {
        const size_t stamp_size = sizeof(TimeType);
-       /*cerr << "MidiBuffer: pushing event " << " size: " << _size 
-           << " event size: " << ev.size() 
-           << " capacity: " << _capacity 
-           << " stamp size: " << stamp_size << " \n";*/
+       /*cerr << "MidiBuffer: pushing event @ " << ev.time()
+               << " size = " << ev.size() << endl;*/
        
        if (_size + stamp_size + ev.size() >= _capacity) {
                cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
index b7ae01353a37bdc2234092e307694592e79a73ac..5ae09aaeeb037ff1ec4bc1104ba7419fcc211330 100644 (file)
@@ -542,10 +542,8 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
                /* data will be written to disk */
 
                if (rec_nframes == nframes && rec_offset == 0) {
-
                        playback_distance = nframes;
                } else {
-               
                        collect_playback = true;
                }
 
@@ -615,20 +613,15 @@ MidiDiskstream::commit (nframes_t nframes)
                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_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;
+       }
+
+       /*cerr << "MDS written: " << frames_written << " - read: " << frames_read <<
+               " = " << frames_written - frames_read
+               << " + " << nframes << " < " << midi_readahead << " = " << need_butler << ")" << endl;*/
        
        if (commit_should_unlock) {
                state_lock.unlock();
@@ -685,13 +678,9 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill)
 int
 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);
-       if ((frames_written-frames_read) < distance) {
-               return false;
-       } else {
-               return true;
-       }
+       return ((frames_written - frames_read) < distance);
 }
 
 int
@@ -763,11 +752,13 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
                this_read = min(dur,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, 
-                                        start) << endmsg;
+                       error << string_compose(
+                                       _("MidiDiskstream %1: cannot read %2 from playlist at frame %3"),
+                                       _id, this_read, start) << endmsg;
                        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);
 
                _read_data_count = _playlist->read_data_count();
@@ -775,7 +766,7 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
                if (reversed) {
 
                        // 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.
 
                } else {
@@ -836,14 +827,15 @@ MidiDiskstream::do_refill ()
        // 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_written = g_atomic_int_get(&_frames_written_to_ringbuffer);
-       if ((frames_written-frames_read) >= midi_readahead) {
-               //cout << "Nothing to do. all fine" << endl;
+       if ((frames_written - frames_read) >= midi_readahead) {
+               //cout << "MDS Nothing to do. all fine" << endl;
                return 0;
        }
 
        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));
        
@@ -1494,8 +1486,8 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end)
                _playback_buf->read(dst, start, end);
        #else   
                const size_t events_read = _playback_buf->read(dst, start, end);
-               cout << "frames read = " << frames_read << " events read = " << events_read
-               << " end = " << end << " start = " << start
+               cout << "MDS events read = " << events_read
+               << " start = " << start << " end = " << end
                << " readspace " << _playback_buf->read_space()
                << " writespace " << _playback_buf->write_space() << endl;
        #endif
index bb3603b8a82551244bd3109dff8a28c97a843194..20ee0c277075bb69ed231cbfbc791dd27d0f4e20 100644 (file)
@@ -140,7 +140,6 @@ MidiPlaylist::read (MidiRingBuffer<nframes_t>& dst, nframes_t start, nframes_t d
        vector<boost::shared_ptr<Region> > regs;
 
        for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-
                if ((*i)->coverage (start, end) != OverlapNone) {
                        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);
 
        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);
                if (mr) {
                        mr->read_at (dst, start, dur, chan_n, _note_mode);
index 066b410a098992c12382a6bb1b332c4fe6a4c7ae..29357322ead5b2dc69d9dcccacbf523d23acf4b5 100644 (file)
@@ -144,9 +144,6 @@ MidiRegion::master_read_at (MidiRingBuffer<nframes_t>& out, sframes_t position,
 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
 {
-       /*cerr << "MidiRegion " << _name << "._read_at(" << position << ") - "
-               << position << " duration: " << dur << endl;*/
-
        nframes_t internal_offset = 0;
        nframes_t src_offset      = 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 */
        }
        
-
        if ((to_read = min (dur, _length - internal_offset)) == 0) {
                return 0; /* read nothing */
        }
@@ -199,7 +195,7 @@ MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer<nframes_t>& dst, nf
        if (src->midi_read (
                        dst, // destination buffer
                        _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
                        output_buffer_position, // the offset in the output buffer
                        negative_output_buffer_position // amount to substract from note times
index cd21905bad00f625a52345ecc4ec655c1cda7899..469222d5d7b2f1912055100253effc7a21d4ef3d 100644 (file)
@@ -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);
 
                if (ev_time > end) {
-                       //cerr << "MRB: PAST END (" << ev_time << " : " << end << ")" << endl;
+                       //cerr << "MRB event @ " << ev_time << " past end @ " << end << endl;
                        break;
                } 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;
                }
 
@@ -63,8 +63,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
                        continue;
                }
 
-               // This event marks a loop happening. this means that
-               // the next events timestamp will be non-monotonic.
+               // This event marks a loop end (i.e. the next event's timestamp will be non-monotonic)
                if (ev_type == LoopEventType) {
                        ev_time -= start;
                        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
                        // a LoopEvent does not have data.
+                       cerr << "MRB loop boundary @ " << ev_time << endl;
                        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
                if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
                        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;
                                this->skip(ev_size); // Advance read pointer to next event
                                continue;
                        }
                }
 
-               //cerr << "MRB " << this << " - Reading event, time = "
-               //      << ev_time << " - " << start << " => " << ev_time - start
-               //      << ", size = " << ev_size << endl;
+               /*cerr << "MRB " << this << " - Reading event, time = "
+                       << ev_time << " - " << start << " => " << ev_time - start
+                       << ", size = " << ev_size << endl;*/
 
                assert(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);
                        }
                        ++count;
-                       //cerr << "MRB - read event at time " << ev_time << endl;
                } else {
                        cerr << "WARNING: error reading event contents from MIDI ring" << endl;
                }
        }
        
-       //cerr << "MTB read space: " << read_space() << endl;
-
        return count;
 }
 
index eec89c60f3223795371ac715cc5d4579dec2c78d..9f0a021274a88d731235dc587eb919f187d846a3 100644 (file)
@@ -138,7 +138,7 @@ MidiSource::midi_read (MidiRingBuffer<nframes_t>& dst, sframes_t source_start,
 
                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;
                        for (i = _model->begin(); i != _model->end(); ++i) {
                                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;
 
                for (; i != _model->end(); ++i) {
-                       const nframes_t time_frames = BEATS_TO_FRAMES(i->time());
-                       if (time_frames < start + cnt) {
+                       const sframes_t time_frames = BEATS_TO_FRAMES(i->time());
+                       if (time_frames < source_start + start + cnt) {
                                dst.write(time_frames, i->event_type(), i->size(), i->buffer());
                        } else {
                                break;
index 3415b7243d328808f42266e50b1edd6df0779567..1c31bc2e26df53db5157d21336ce8cba15c36c42 100644 (file)
@@ -78,7 +78,7 @@ Session::start_butler_thread ()
         * (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());
-       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);