MIDI looping fixes from torbenh.
authorDavid Robillard <d@drobilla.net>
Sun, 12 Oct 2008 17:40:37 +0000 (17:40 +0000)
committerDavid Robillard <d@drobilla.net>
Sun, 12 Oct 2008 17:40:37 +0000 (17:40 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@3932 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/configuration_vars.h
libs/ardour/ardour/midi_diskstream.h
libs/ardour/ardour/midi_ring_buffer.h
libs/ardour/midi_diskstream.cc
libs/ardour/session_butler.cc

index 77a12be2d04333cade9544888823bd76449e903e..f433cf94a7aab870f45853fa4fb30acbdf47cfd2 100644 (file)
@@ -52,6 +52,7 @@ CONFIG_VARIABLE (RemoteModel, remote_model, "remote-model", MixerOrdered)
 /* disk operations */
 
 CONFIG_VARIABLE (uint32_t, minimum_disk_io_bytes,  "minimum-disk-io-bytes", 1024 * 256)
+CONFIG_VARIABLE (float, midi_readahead,  "midi-readahead", 1.0)
 CONFIG_VARIABLE (float, audio_track_buffer_seconds, "track-buffer-seconds", 5.0)
 CONFIG_VARIABLE (float, midi_track_buffer_seconds, "midi-track-buffer-seconds", 1.0)
 CONFIG_VARIABLE (uint32_t, disk_choice_space_threshold,  "disk-choice-space-threshold", 57600000)
index a3d4d6d0a459252a768db264bea53cd504d98644..56e704f88ec44f703554dc66cc758d3c61d66332 100644 (file)
@@ -132,6 +132,8 @@ 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; }
+
   protected:
        int seek (nframes_t which_sample, bool complete_refill = false);
 
@@ -140,6 +142,7 @@ class MidiDiskstream : public Diskstream
 
        int  process (nframes_t transport_frame, nframes_t nframes, nframes_t offset, bool can_record, bool rec_monitors_input);
        bool commit  (nframes_t nframes);
+       static nframes_t midi_readahead;
 
   private:
 
@@ -181,6 +184,8 @@ class MidiDiskstream : public Diskstream
        nframes_t                         _last_flush_frame;
        NoteMode                          _note_mode;  
        MidiStateTracker                  _midistate_tracker;
+       volatile gint                     _frames_written_to_ringbuffer;
+       volatile gint                     _frames_read_from_ringbuffer;
 };
 
 }; /* namespace ARDOUR */
index 6e827d285219a7cc2401f96755a26670ec086e80..72bf7a0fe5b632421604680b7b3f16411a8af31d 100644 (file)
@@ -131,7 +131,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
 
        //std::cerr << "MRB read " << start << " .. " << end << " + " << offset << std::endl;
 
-       while (read_space() > sizeof(EventTime) + sizeof(EventType) + sizeof(uint32_t)) {
+       while (read_space() >= sizeof(EventTime) + sizeof(EventType) + sizeof(uint32_t)) {
 
                full_peek(sizeof(EventTime), (uint8_t*)&ev_time);
 
@@ -153,8 +153,10 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
                // the next events timestamp will be non-monotonic.
                if (ev_type == LoopEventType) {
                        ev_time -= start;
+                       ev_time += offset;
                        Evoral::MIDIEvent loopevent(LoopEventType, ev_time); 
                        dst.push_back(loopevent);
+
                        
                        // We can safely return, without reading the data, because
                        // a LoopEvent does not have data.
index 2372d91c5d4a100fc94f46173b74ede524dbed94..5b81401c41de8b70d311fe91990f7e135e06541c 100644 (file)
@@ -57,6 +57,8 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
+nframes_t MidiDiskstream::midi_readahead = 4096;
+
 MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
        : Diskstream(sess, name, flag)
        , _playback_buf(0)
@@ -64,6 +66,8 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
        , _source_port(0)
        , _last_flush_frame(0)
        , _note_mode(Sustained)
+       , _frames_written_to_ringbuffer(0)
+       , _frames_read_from_ringbuffer(0)
 {
        /* prevent any write sources from being created */
 
@@ -84,6 +88,8 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
        , _source_port(0)
        , _last_flush_frame(0)
        , _note_mode(Sustained)
+       , _frames_written_to_ringbuffer(0)
+       , _frames_read_from_ringbuffer(0)
 {
        in_set_state = true;
        init (Recordable);
@@ -623,9 +629,11 @@ MidiDiskstream::commit (nframes_t nframes)
                        || _capture_buf->read_space() >= disk_io_chunk_frames;
        }*/
        
-       /* we'll just keep the playback buffer full for now.
-        * this should be decreased to reduce edit latency */
-       need_butler = _playback_buf->write_space() >= _playback_buf->capacity() / 2;
+       // 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)
+               need_butler = true;
        
        if (commit_should_unlock) {
                state_lock.unlock();
@@ -649,7 +657,7 @@ MidiDiskstream::set_pending_overwrite (bool yn)
 int
 MidiDiskstream::overwrite_existing_buffers ()
 {
-       read(overwrite_frame, disk_io_chunk_frames, false);
+       //read(overwrite_frame, disk_io_chunk_frames, false);
        overwrite_queued = false;
        pending_overwrite = false;
 
@@ -664,6 +672,8 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill)
        
        _playback_buf->reset();
        _capture_buf->reset();
+       g_atomic_int_set(&_frames_read_from_ringbuffer, 0);
+       g_atomic_int_set(&_frames_written_to_ringbuffer, 0);
 
        playback_sample = frame;
        file_frame = frame;
@@ -680,7 +690,9 @@ MidiDiskstream::seek (nframes_t frame, bool complete_refill)
 int
 MidiDiskstream::can_internal_playback_seek (nframes_t distance)
 {
-       if (_playback_buf->read_space() < distance) {
+       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;
@@ -760,6 +772,8 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
                                         start) << endmsg;
                        return -1;
                }
+               //cout << "this write " << this_read << "start= " << start << endl;
+               g_atomic_int_add(&_frames_written_to_ringbuffer, this_read);
 
                _read_data_count = _playlist->read_data_count();
                
@@ -777,6 +791,9 @@ MidiDiskstream::read (nframes_t& start, nframes_t dur, bool reversed)
                                // Synthesize LoopEvent here, because the next events
                                // written will have non-monotonic timestamps.
                                _playback_buf->write(loop_end - 1, LoopEventType, 0, 0);
+                               //cout << "Pushing LoopEvent ts=" << loop_end-1 
+                               //     << " start+this_read " << start+this_read << endl;
+
                                start = loop_start;
                        } else {
                                start += this_read;
@@ -820,7 +837,20 @@ MidiDiskstream::do_refill ()
        assert(_playback_buf->write_space() > 0); // ... have something to write to, and
        assert(file_frame <= max_frames); // ... something to write
 
-       nframes_t to_read = min(disk_io_chunk_frames, (max_frames - file_frame));
+       // now calculate how much time is in the ringbuffer.
+       // 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;
+               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;
+
+       to_read = min(to_read, (max_frames - file_frame));
        
        if (read (file_frame, to_read, reversed)) {
                ret = -1;
@@ -1466,6 +1496,10 @@ MidiDiskstream::get_playback(MidiBuffer& dst, nframes_t start, nframes_t end, nf
        // Translates stamps to be relative to start, but add offset.
        _playback_buf->read(dst, start, end, offset);
 
+       gint32 data_read = end-start;
+       //cout << "data read = " << data_read << " e=" << end << " s=" << start << "off= " << offset
+       //      << " readspace " << _playback_buf->read_space() << " writespace " << _playback_buf->write_space() << endl;
+       g_atomic_int_add(&_frames_read_from_ringbuffer, data_read);
        
        // Now feed the data through the MidiStateTracker.
        // In case it detects a LoopEvent it will add necessary note
index eac71fb5d1eda01d9abfd46700bdd78c292c0816..02f8569a3d4d7fa0c71e8951f5c1f410bd8da2a6 100644 (file)
@@ -35,6 +35,7 @@
 #include <ardour/audioengine.h>
 #include <ardour/session.h>
 #include <ardour/audio_diskstream.h>
+#include <ardour/midi_diskstream.h>
 #include <ardour/crossfade.h>
 #include <ardour/timestamps.h>
 
@@ -76,6 +77,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()));
        
        Crossfade::set_buffer_size (audio_dstream_buffer_size);