revert to single buffer for disk playback, and 5.x-style overwrite
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 10 Dec 2019 16:28:41 +0000 (09:28 -0700)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 10 Dec 2019 16:29:22 +0000 (09:29 -0700)
Also address issues with MIDI and also atomicity of _pending_overwrite

14 files changed:
libs/ardour/ardour/disk_io.h
libs/ardour/ardour/disk_reader.h
libs/ardour/ardour/session.h
libs/ardour/ardour/session_event.h
libs/ardour/ardour/track.h
libs/ardour/ardour/types.h
libs/ardour/disk_io.cc
libs/ardour/disk_reader.cc
libs/ardour/session.cc
libs/ardour/session_butler.cc
libs/ardour/session_process.cc
libs/ardour/session_transport.cc
libs/ardour/track.cc
libs/pbd/pbd/playback_buffer.h

index 65486febf41c015f87763c9777855c9bec25a23b..1ae7cbfa94475fd1445ebdf61f707197f824f810 100644 (file)
@@ -151,13 +151,11 @@ protected:
                ChannelInfo (samplecnt_t buffer_size);
                virtual ~ChannelInfo ();
 
-               /** A pair of random-access ringbuffers for data to be played back.
+               /** A semi-random-access ringbuffers for data to be played back.
                 * written to in the butler thread, read from in the process
                 * thread.
-                *
-                *
                 */
-               PBD::PlaybackBuffer<Sample>* rbuf[2];
+               PBD::PlaybackBuffer<Sample>* rbuf;
 
                /** A ringbuffer for data to be recorded back, written to in the
                 * process thread, read from in the butler thread.
index e43192f0ffce29c5250b0eeecc46df27e22763c7..dbe639d5c6ba7f47e4a1b4a1ac779752d09b83c5 100644 (file)
@@ -54,7 +54,7 @@ public:
        void realtime_handle_transport_stopped ();
        void realtime_locate (bool);
        bool overwrite_existing_buffers ();
-       void set_pending_overwrite ();
+       void set_pending_overwrite (OverwriteReason);
        void set_loop (Location *);
 
        int set_state (const XMLNode&, int version);
@@ -118,8 +118,6 @@ public:
        static void alloc_loop_declick (samplecnt_t sample_rate);
 
        Glib::Threads::Mutex rbuf_lock;
-       void queue_switch_rbuf ();
-       void switch_rbufs ();
 
 protected:
        friend class Track;
@@ -186,10 +184,8 @@ protected:
        };
 
 private:
-       bool         _switch_rbuf;
-       int           process_rbuf;
-       int           other_rbuf;
        samplepos_t   overwrite_sample;
+       sampleoffset_t overwrite_offset;
        samplepos_t   new_file_sample;
        mutable gint  _pending_overwrite;
        bool          overwrite_queued;
@@ -211,14 +207,13 @@ private:
        static Declicker loop_declick_out;
        static samplecnt_t loop_fade_length;
 
-       int audio_read (PBD::PlaybackBuffer<Sample>*,
-                       Sample* sum_buffer,
-                       Sample* mixdown_buffer,
-                       float*  gain_buffer,
-                       samplepos_t& start, samplecnt_t cnt,
-                       ReaderChannelInfo* rci,
-                       int channel,
-                       bool reversed);
+       samplecnt_t audio_read (Sample* sum_buffer,
+                               Sample* mixdown_buffer,
+                               float*  gain_buffer,
+                               samplepos_t& start, samplecnt_t cnt,
+                               ReaderChannelInfo* rci,
+                               int channel,
+                               bool reversed);
 
        static Sample* _sum_buffer;
        static Sample* _mixdown_buffer;
@@ -234,7 +229,8 @@ private:
        void get_midi_playback (MidiBuffer& dst, samplepos_t start_sample, samplepos_t end_sample, MonitorState, BufferSet&, double speed, samplecnt_t distance);
        void maybe_xfade_loop (Sample*, samplepos_t read_start, samplepos_t read_end, ReaderChannelInfo*);
 
-
+       bool overwrite_existing_audio ();
+       bool overwrite_existing_midi ();
 };
 
 } // namespace
index 6c34a1b93ff73332459dedb893899919d961d22e..5491f49df4ef8953e35c4696235f708bc734c43f 100644 (file)
@@ -456,7 +456,7 @@ public:
        void allow_auto_play (bool yn);
        void request_transport_speed (double speed, bool as_default = true, TransportRequestSource origin = TRS_UI);
        void request_transport_speed_nonzero (double, bool as_default = true, TransportRequestSource origin = TRS_UI);
-       void request_overwrite_buffer (boost::shared_ptr<Track>);
+       void request_overwrite_buffer (boost::shared_ptr<Track>, OverwriteReason);
        void adjust_playback_buffering();
        void adjust_capture_buffering();
 
@@ -1685,7 +1685,7 @@ private:
 
        void set_play_loop (bool yn, bool change_transport_state);
        void unset_play_loop (bool change_transport_state = false);
-       void overwrite_some_buffers (boost::shared_ptr<Route>);
+       void overwrite_some_buffers (boost::shared_ptr<Route>, OverwriteReason);
        void flush_all_inserts ();
        int  micro_locate (samplecnt_t distance);
 
index da6a0505f273d60dbf566ea1fa3bf94dd8d6cc32..ddf7210617c2267d1ba59615463743e377439590 100644 (file)
@@ -83,6 +83,7 @@ public:
        union {
                bool             yes_or_no;
                samplepos_t      target2_sample;
+               OverwriteReason  overwrite;
        };
 
        boost::shared_ptr<Track> track;
index 0b6462fbc3205e79c53cabc5e6e0633ca658c351..fbac03edf075a5ad6af510586a4b6ba1f2526677 100644 (file)
@@ -137,7 +137,7 @@ public:
        float capture_buffer_load () const;
        int do_refill ();
        int do_flush (RunContext, bool force = false);
-       void set_pending_overwrite ();
+       void set_pending_overwrite (OverwriteReason);
        int seek (samplepos_t, bool complete_refill = false);
        bool can_internal_playback_seek (samplecnt_t);
        void internal_playback_seek (samplecnt_t);
index 7cd3759a8839e609a4e6d77d4e8287ad9c693f01..26da1cf9e1a2b07ab11c7a459529dd6d74f8d8ea 100644 (file)
@@ -792,6 +792,12 @@ enum LoopFadeChoice {
        XFadeLoop,
 };
 
+enum OverwriteReason {
+       PlaylistModified,
+       LoopDisabled,
+       LoopChanged,
+};
+
 typedef std::vector<CaptureInfo*> CaptureInfos;
 
 } // namespace ARDOUR
index 7d153661b9e114dc798a2ea44badbad9d647d323..a55e2c559bcf455313812d14fff8d5fdaa05db4e 100644 (file)
@@ -324,22 +324,19 @@ DiskIOProcessor::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist
 }
 
 DiskIOProcessor::ChannelInfo::ChannelInfo (samplecnt_t bufsize)
-       : wbuf (0)
+       : rbuf (0)
+       , wbuf (0)
        , capture_transition_buf (0)
        , curr_capture_cnt (0)
 {
-       rbuf[0] = 0;
-       rbuf[1] = 0;
 }
 
 DiskIOProcessor::ChannelInfo::~ChannelInfo ()
 {
-       delete rbuf[0];
-       delete rbuf[1];
+       delete rbuf;
        delete wbuf;
        delete capture_transition_buf;
-       rbuf[0] = 0;
-       rbuf[1] = 0;
+       rbuf = 0;
        wbuf = 0;
        capture_transition_buf = 0;
 }
index 304cf7d461adff2dc24aa877eb6f049c864f9272..0672741fa374e6eb5ed7f21a5a9f78ea0722de92 100644 (file)
@@ -60,9 +60,6 @@ samplecnt_t DiskReader::loop_fade_length (0);
 
 DiskReader::DiskReader (Session& s, string const & str, DiskIOProcessor::Flag f)
        : DiskIOProcessor (s, str, f)
-       , _switch_rbuf (false)
-       , process_rbuf (0)
-       , other_rbuf (1)
        , overwrite_sample (0)
        , overwrite_queued (false)
        , run_must_resolve (false)
@@ -84,15 +81,11 @@ DiskReader::ReaderChannelInfo::resize (samplecnt_t bufsize)
 {
        /* caller must hold rbuf lock */
 
-       delete rbuf[0]; rbuf[0] = 0;
-       delete rbuf[1]; rbuf[1] = 0;
+       delete rbuf; rbuf = 0;
 
-       rbuf[0] = new PlaybackBuffer<Sample> (bufsize);
+       rbuf = new PlaybackBuffer<Sample> (bufsize);
        /* touch memory to lock it */
-       memset (rbuf[0]->buffer(), 0, sizeof (Sample) * rbuf[0]->bufsize());
-       rbuf[1] = new PlaybackBuffer<Sample> (bufsize);
-       /* touch memory to lock it */
-       memset (rbuf[1]->buffer(), 0, sizeof (Sample) * rbuf[1]->bufsize());
+       memset (rbuf->buffer(), 0, sizeof (Sample) * rbuf->bufsize());
 }
 
 void
@@ -116,8 +109,8 @@ DiskReader::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many)
                c->push_back (new ReaderChannelInfo (_session.butler()->audio_diskstream_playback_buffer_size(), loop_fade_length));
                DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: new reader channel, write space = %2 read = %3\n",
                                                            name(),
-                                                           c->back()->rbuf[process_rbuf]->write_space(),
-                                                           c->back()->rbuf[process_rbuf]->read_space()));
+                                                           c->back()->rbuf->write_space(),
+                                                           c->back()->rbuf->read_space()));
        }
 
        return 0;
@@ -226,7 +219,7 @@ DiskReader::buffer_load () const
                return 1.0;
        }
 
-       PBD::PlaybackBuffer<Sample>* b = c->front()->rbuf[process_rbuf];
+       PBD::PlaybackBuffer<Sample>* b = c->front()->rbuf;
        return (float) ((double) b->read_space() / (double) b->bufsize());
 }
 
@@ -239,17 +232,13 @@ DiskReader::adjust_buffering ()
        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
                (*chan)->resize (_session.butler()->audio_diskstream_playback_buffer_size());
        }
-
-       process_rbuf = 0;
-       other_rbuf = 1;
-       _switch_rbuf = false;
 }
 
 void
 DiskReader::playlist_modified ()
 {
        if (!overwrite_queued) {
-               _session.request_overwrite_buffer (_track);
+               _session.request_overwrite_buffer (_track, PlaylistModified);
                overwrite_queued = true;
        }
 }
@@ -273,7 +262,7 @@ DiskReader::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist)
        */
 
         if (!overwrite_queued && (prior_playlist || _session.loading())) {
-               _session.request_overwrite_buffer (_track);
+               _session.request_overwrite_buffer (_track, PlaylistModified);
                overwrite_queued = true;
        }
 
@@ -352,8 +341,8 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
 
                if (!still_locating || _no_disk_output) {
                        for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                               assert ((*chan)->rbuf[process_rbuf]);
-                               (*chan)->rbuf[process_rbuf]->increment_read_ptr (disk_samples_to_consume);
+                               assert ((*chan)->rbuf);
+                               (*chan)->rbuf->increment_read_ptr (disk_samples_to_consume);
                        }
                }
 
@@ -380,20 +369,6 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                const float initial_declick_gain = _declick_amp.gain ();
                const sampleoffset_t declick_offs = _declick_offs;
 
-               Glib::Threads::Mutex::Lock lm (rbuf_lock, Glib::Threads::TRY_LOCK);
-               samplecnt_t skip_for_switch = 0;
-
-               if (lm.locked()) {
-                       if (_switch_rbuf) {
-                               cerr << name() << " switching buffers\n";
-                               switch_rbufs ();
-                               if (playback_sample > overwrite_sample) {
-                                       skip_for_switch = playback_sample - overwrite_sample;
-                                       cerr << name() << " will skip " << skip_for_switch << " to align new buffer @ " << overwrite_sample << " to " << playback_sample << endl;
-                               }
-                       }
-               }
-
                for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
                        ChannelInfo* chaninfo (*chan);
@@ -402,6 +377,7 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                        AudioBuffer& disk_buf ((ms & MonitoringInput) ? scratch_bufs.get_audio(n) : output);
 
                        if (start_sample != playback_sample && target_gain != 0) {
+                               cerr << name() << " Not at start (" << start_sample << ") ps = " << playback_sample << " iseek (" << start_sample - playback_sample << endl;
                                if (can_internal_playback_seek (start_sample - playback_sample)) {
                                        internal_playback_seek (start_sample - playback_sample);
                                } else {
@@ -415,13 +391,9 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                        }
 
 
-                       if (skip_for_switch) {
-                               chaninfo->rbuf[process_rbuf]->increment_read_ptr (skip_for_switch);
-                       }
-
                        if (!declick_out) {
 
-                               const samplecnt_t total = chaninfo->rbuf[process_rbuf]->read (disk_buf.data(), disk_samples_to_consume);
+                               const samplecnt_t total = chaninfo->rbuf->read (disk_buf.data(), disk_samples_to_consume);
 
                                if (disk_samples_to_consume > total) {
                                        cerr << _name << " Need " << total << " have only " << disk_samples_to_consume << endl;
@@ -445,7 +417,7 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                                   to ::run()
                                */
 
-                               const samplecnt_t total = chaninfo->rbuf[process_rbuf]->read (disk_buf.data(), nframes, false, declick_offs);
+                               const samplecnt_t total = chaninfo->rbuf->read (disk_buf.data(), nframes, false, declick_offs);
 
                                if (n == 0) {
                                        _declick_offs += total;
@@ -470,6 +442,8 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
   midi:
        /* MIDI data handling */
 
+       const bool midi_data_available = !(pending_overwrite() & PlaylistModified);
+
        if (bufs.count().n_midi()) {
 
                MidiBuffer& dst (bufs.get_midi (0));
@@ -486,7 +460,7 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
 
        /* decide if we need the butler */
 
-       if (!still_locating) {
+       if (!still_locating && midi_data_available) {
 
                bool butler_required = false;
 
@@ -505,13 +479,13 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                if (_playlists[DataType::AUDIO]) {
                        if (!c->empty()) {
                                if (_slaved) {
-                                       if (c->front()->rbuf[process_rbuf]->write_space() >= c->front()->rbuf[process_rbuf]->bufsize() / 2) {
-                                               DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: slaved, write space = %2 of %3\n", name(), c->front()->rbuf[process_rbuf]->write_space(), c->front()->rbuf[process_rbuf]->bufsize()));
+                                       if (c->front()->rbuf->write_space() >= c->front()->rbuf->bufsize() / 2) {
+                                               DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: slaved, write space = %2 of %3\n", name(), c->front()->rbuf->write_space(), c->front()->rbuf->bufsize()));
                                                butler_required = true;
                                        }
                                } else {
-                                       if ((samplecnt_t) c->front()->rbuf[process_rbuf]->write_space() >= _chunk_samples) {
-                                               DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: write space = %2 of %3\n", name(), c->front()->rbuf[process_rbuf]->write_space(),
+                                       if ((samplecnt_t) c->front()->rbuf->write_space() >= _chunk_samples) {
+                                               DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: write space = %2 of %3\n", name(), c->front()->rbuf->write_space(),
                                                                                            _chunk_samples));
                                                butler_required = true;
                                        }
@@ -536,73 +510,96 @@ DiskReader::declick_in_progress () const
 }
 
 bool
-DiskReader::pending_overwrite () const {
+DiskReader::pending_overwrite () const
+{
        return g_atomic_int_get (&_pending_overwrite) != 0;
 }
 
 void
-DiskReader::set_pending_overwrite ()
+DiskReader::set_pending_overwrite (OverwriteReason why)
 {
        /* called from audio thread, so we can use the read ptr and playback sample as we wish */
 
        overwrite_sample = playback_sample;
-       g_atomic_int_set (&_pending_overwrite, 1);
+       boost::shared_ptr<ChannelList> c = channels.reader ();
+       if (!c->empty ()) {
+               overwrite_offset = c->front()->rbuf->read_ptr();
+       }
+
+       while (true) {
+               OverwriteReason current = OverwriteReason (g_atomic_int_get (&_pending_overwrite));
+               OverwriteReason next = OverwriteReason (current | why);
+               if (g_atomic_int_compare_and_exchange (&_pending_overwrite, current, next)) {
+                       break;
+               }
+       }
+
        run_must_resolve = true;
 }
 
 bool
-DiskReader::overwrite_existing_buffers ()
+DiskReader::overwrite_existing_audio ()
 {
-       /* called from butler thread */
-
-       Glib::Threads::Mutex::Lock lm (rbuf_lock);
+       boost::shared_ptr<ChannelList> c = channels.reader();
 
-       DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 overwriting existing buffers at %2\n", name(), overwrite_sample));
-       cerr << string_compose ("%1 overwriting existing buffers at %2\n", name(), overwrite_sample) << endl;
+       if (c->empty ()) {
+               return true;
+       }
 
-       boost::shared_ptr<ChannelList> c = channels.reader();
+       const bool reversed = _session.transport_speed() < 0.0f;
 
-       if (!c->empty ()) {
+       /* assume all are the same size */
 
-               /* AUDIO */
+       samplecnt_t size = c->front()->rbuf->bufsize () - c->front()->rbuf->reserved_size() - 1;
+       assert (size > 0);
 
-               const bool reversed = _session.transport_speed() < 0.0f;
+       boost::scoped_array<Sample> mixdown_buffer (new Sample[size]);
+       boost::scoped_array<float> gain_buffer (new float[size]);
+       uint32_t n = 0;
+       bool ret = true;
 
-               /* assume all are the same size */
+       for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) {
 
-               samplecnt_t size = c->front()->rbuf[process_rbuf]->bufsize ();
-               assert (size > 0);
+               samplepos_t start = overwrite_sample;
 
-               boost::scoped_array<Sample> sum_buffer (new Sample[size]);
-               boost::scoped_array<Sample> mixdown_buffer (new Sample[size]);
-               boost::scoped_array<float> gain_buffer (new float[size]);
+               /* to fill the buffer without resetting the playback sample, we need to
+                  do it one or two chunks (normally two).
 
-               samplecnt_t to_read = c->front()->rbuf[other_rbuf]->write_space();
-               uint32_t n = 0;
+                  |----------------------------------------------------------------------|
+                                    ^               ^
+                                        RESERVED    overwrite_offset  (old read_ptr)
+                  |<- second chunk->|<-------------><---- first chunk ------------------>|
 
-               for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) {
+               */
 
-                       samplepos_t start = overwrite_sample;
+               samplecnt_t to_read = size - overwrite_offset;
+               Sample* buf = (*chan)->rbuf->buffer();
+               ReaderChannelInfo* rci = dynamic_cast<ReaderChannelInfo*> (*chan);
+               samplecnt_t nread;
 
-                       ReaderChannelInfo* rci = dynamic_cast<ReaderChannelInfo*> (*chan);
+               if ((nread = audio_read (buf + overwrite_offset, mixdown_buffer.get(), gain_buffer.get(), start, to_read, rci, n, reversed)) != to_read)  {
+                       error << string_compose(_("DiskReader %1: when overwriting(1), cannot read %2 from playlist at sample %3"), id(), to_read, overwrite_sample) << endmsg;
+                       ret = false;
+                       continue;
+               }
 
-                       PlaybackBuffer<Sample>* rbuf = (*chan)->rbuf[other_rbuf];
+               if (size > to_read) {
 
-                       cerr << name() << ' ' << n << " overwrite read into " << other_rbuf << " @ " << overwrite_sample << " tr " << to_read << " ws " << (*chan)->rbuf[other_rbuf]->write_space() << endl;
+                       to_read = size - to_read;
 
-                       if (audio_read (rbuf, sum_buffer.get(), mixdown_buffer.get(), gain_buffer.get(), start, to_read, rci, n, reversed)) {
-                               error << string_compose(_("DiskReader %1: when refilling, cannot read %2 from playlist at sample %3"), id(), size, overwrite_sample) << endmsg;
-                               goto midi;
+                       if ((nread = audio_read (buf, mixdown_buffer.get(), gain_buffer.get(), start, to_read, rci, n, reversed)) != to_read) {
+                               error << string_compose(_("DiskReader %1: when overwriting(2), cannot read %2 from playlist at sample %3"), id(), to_read, overwrite_sample) << endmsg;
+                               ret = false;
                        }
                }
-
-               new_file_sample = overwrite_sample + to_read;
-
-               queue_switch_rbuf ();
        }
 
-  midi:
+       return ret;
+}
 
+bool
+DiskReader::overwrite_existing_midi ()
+{
        RTMidiBuffer* mbuf = rt_midibuffer ();
 
        if (mbuf) {
@@ -619,10 +616,34 @@ DiskReader::overwrite_existing_buffers ()
                cerr << "Reading " << name()  << " took " << minsert.elapsed() << " microseconds, final size = " << midi_playlist()->rendered()->size() << endl;
        }
 
-       g_atomic_int_set (&_pending_overwrite, 0);
        return true;
 }
 
+bool
+DiskReader::overwrite_existing_buffers ()
+{
+       /* called from butler thread */
+
+       DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 overwriting existing buffers at %2\n", owner()->name(), overwrite_sample));
+       bool ret = true;
+
+       if (g_atomic_int_get (&_pending_overwrite) & (PlaylistModified|LoopDisabled|LoopChanged)) {
+               if (!overwrite_existing_audio ()) {
+                       ret = false;
+               }
+       }
+
+       if (g_atomic_int_get (&_pending_overwrite) & (LoopChanged|LoopDisabled)) {
+               if (!overwrite_existing_midi ()) {
+                       ret = false;
+               }
+       }
+
+       g_atomic_int_set (&_pending_overwrite, 0);
+
+       return ret;
+}
+
 int
 DiskReader::seek (samplepos_t sample, bool complete_refill)
 {
@@ -648,7 +669,7 @@ DiskReader::seek (samplepos_t sample, bool complete_refill)
        }
 
        for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
-               (*chan)->rbuf[process_rbuf]->reset ();
+               (*chan)->rbuf->reset ();
        }
 
        playback_sample = sample;
@@ -679,7 +700,7 @@ DiskReader::can_internal_playback_seek (sampleoffset_t distance)
        boost::shared_ptr<ChannelList> c = channels.reader();
 
        for (chan = c->begin(); chan != c->end(); ++chan) {
-               if (!(*chan)->rbuf[process_rbuf]->can_seek (distance)) {
+               if (!(*chan)->rbuf->can_seek (distance)) {
                        return false;
                }
        }
@@ -702,9 +723,9 @@ DiskReader::internal_playback_seek (sampleoffset_t distance)
        boost::shared_ptr<ChannelList> c = channels.reader();
        for (chan = c->begin(); chan != c->end(); ++chan) {
                if (distance < 0) {
-                       off = 0 - (sampleoffset_t) (*chan)->rbuf[process_rbuf]->decrement_read_ptr (::llabs (distance));
+                       off = 0 - (sampleoffset_t) (*chan)->rbuf->decrement_read_ptr (::llabs (distance));
                } else {
-                       off = (*chan)->rbuf[process_rbuf]->increment_read_ptr (distance);
+                       off = (*chan)->rbuf->increment_read_ptr (distance);
                }
        }
 
@@ -728,25 +749,22 @@ void swap_by_ptr (Sample *first, Sample *last)
  *  @param cnt Count of samples to read.
  *  @param reversed true if we are running backwards, otherwise false.
  */
-int
-DiskReader::audio_read (PBD::PlaybackBuffer<Sample>*rb,
-                        Sample* sum_buffer,
+samplecnt_t
+DiskReader::audio_read (Sample* sum_buffer,
                         Sample* mixdown_buffer,
                         float* gain_buffer,
-                        samplepos_t& start, samplecnt_t cnt,
+                        samplepos_t& start,
+                        samplecnt_t cnt,
                         ReaderChannelInfo* rci,
-                        int channel, bool reversed)
+                        int channel,
+                        bool reversed)
 {
        samplecnt_t this_read = 0;
        bool reloop = false;
        samplepos_t loop_end = 0;
        samplepos_t loop_start = 0;
        Location *loc = 0;
-
-       if (!_playlists[DataType::AUDIO]) {
-               rb->write_zero (cnt);
-               return 0;
-       }
+       const samplecnt_t rcnt = cnt;
 
        /* XXX we don't currently play loops in reverse. not sure why */
 
@@ -811,7 +829,7 @@ DiskReader::audio_read (PBD::PlaybackBuffer<Sample>*rb,
 
                if (audio_playlist()->read (sum_buffer, mixdown_buffer, gain_buffer, start, this_read, channel) != this_read) {
                        error << string_compose(_("DiskReader %1: cannot read %2 from playlist at sample %3"), id(), this_read, start) << endmsg;
-                       return -1;
+                       return 0;
                }
 
                if (loc) {
@@ -849,16 +867,11 @@ DiskReader::audio_read (PBD::PlaybackBuffer<Sample>*rb,
                        }
                }
 
-               samplecnt_t written;
-
-               if ((written = rb->write (sum_buffer, this_read)) != this_read) {
-                       cerr << owner()->name() << " Ringbuffer Write overrun on (tried " << this_read << " wrote " << written << ')' << endl;
-               }
-
                cnt -= this_read;
+               sum_buffer += this_read;
        }
 
-       return 0;
+       return rcnt;
 }
 
 int
@@ -926,7 +939,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
        assert(mixdown_buffer);
        assert(gain_buffer);
 
-       samplecnt_t total_space = c->front()->rbuf[process_rbuf]->write_space();
+       samplecnt_t total_space = c->front()->rbuf->write_space();
 
        if (total_space == 0) {
                DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: no space to refill\n", name()));
@@ -964,7 +977,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
           work with.
        */
 
-       if (_slaved && total_space < (samplecnt_t) (c->front()->rbuf[process_rbuf]->bufsize() / 2)) {
+       if (_slaved && total_space < (samplecnt_t) (c->front()->rbuf->bufsize() / 2)) {
                DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: not enough to refill while slaved\n", this));
                return 0;
        }
@@ -977,7 +990,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
                        /* at start: nothing to do but fill with silence */
                        for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
                                ChannelInfo* chan (*i);
-                               chan->rbuf[process_rbuf]->write_zero (chan->rbuf[process_rbuf]->write_space ());
+                               chan->rbuf->write_zero (chan->rbuf->write_space ());
                        }
                        return 0;
                }
@@ -996,7 +1009,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
                        /* at end: nothing to do but fill with silence */
                        for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
                                ChannelInfo* chan (*i);
-                               chan->rbuf[process_rbuf]->write_zero (chan->rbuf[process_rbuf]->write_space ());
+                               chan->rbuf->write_zero (chan->rbuf->write_space ());
                        }
                        return 0;
                }
@@ -1030,11 +1043,12 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
        samplepos_t file_sample_tmp = ffa;
 
        for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
+
                ChannelInfo* chan (*i);
                file_sample_tmp = ffa;
                samplecnt_t ts = total_space;
 
-               samplecnt_t to_read = min (ts, (samplecnt_t) chan->rbuf[process_rbuf]->write_space ());
+               samplecnt_t to_read = min (ts, (samplecnt_t) chan->rbuf->write_space ());
                to_read = min (to_read, samples_to_read);
                assert (to_read >= 0);
 
@@ -1042,11 +1056,26 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
 
                if (to_read) {
                        ReaderChannelInfo* rci = dynamic_cast<ReaderChannelInfo*> (chan);
-                       cerr << name() << ' ' << chan_n << " refill read into " << process_rbuf << " @ " << file_sample_tmp << " tr " << to_read << "  ts was " << ts << "scnt " << samples_to_read << " ws " << chan->rbuf[process_rbuf]->write_space() << endl;
-                       if (audio_read (chan->rbuf[process_rbuf], sum_buffer, mixdown_buffer, gain_buffer, file_sample_tmp, to_read, rci, chan_n, reversed)) {
-                               error << string_compose(_("DiskReader %1: when refilling, cannot read %2 from playlist at sample %3"), id(), to_read, ffa) << endmsg;
-                               ret = -1;
-                               goto out;
+                       samplecnt_t nread;
+
+                       cerr << name() << ' ' << chan_n << " refill read  @ " << file_sample_tmp << " tr " << to_read << "  ts was " << ts << "scnt " << samples_to_read << " ws " << chan->rbuf->write_space() << endl;
+
+                       if (!_playlists[DataType::AUDIO]) {
+
+                               chan->rbuf->write_zero (to_read);
+
+                       } else {
+
+                               if ((nread = audio_read (sum_buffer, mixdown_buffer, gain_buffer, file_sample_tmp, to_read, rci, chan_n, reversed)) != to_read) {
+                                       error << string_compose(_("DiskReader %1: when refilling, cannot read %2 from playlist at sample %3"), name(), to_read, ffa) << endmsg;
+                                       ret = -1;
+                                       goto out;
+                               }
+
+                               if (chan->rbuf->write (sum_buffer, nread) != nread) {
+                                       error << string_compose(_("DiskReader %1: when refilling, cannot write %2 into buffer"), name(), nread) << endmsg;
+                                       ret = -1;
+                               }
                        }
                }
 
@@ -1054,7 +1083,7 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai
                        /* not sure if action is needed,
                         * we'll later hit the "to close to the end" case
                         */
-                       //chan->rbuf[process_rbuf]->write_zero (zero_fill);
+                       //chan->rbuf->write_zero (zero_fill);
                }
        }
 
@@ -1661,31 +1690,3 @@ DiskReader::reload_loop ()
 
        }
 }
-void
-DiskReader::queue_switch_rbuf ()
-{
-       /* must hold _rbuf_lock */
-       _switch_rbuf = true;
-}
-
-void
-DiskReader::switch_rbufs ()
-{
-       /* must hold _rbuf_lock */
-       assert (_switch_rbuf);
-
-       std::swap (process_rbuf, other_rbuf);
-
-       boost::shared_ptr<ChannelList> c = channels.reader();
-
-       for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-               (*chan)->rbuf[other_rbuf]->reset ();
-               cerr << name() << " after switch/reset, other has " << (*chan)->rbuf[other_rbuf]->write_space() << " of " << (*chan)->rbuf[other_rbuf]->bufsize() << endl;
-       }
-
-       _switch_rbuf = false;
-       file_sample[DataType::AUDIO] = new_file_sample;
-
-       cerr << "switched, pbuf now " << process_rbuf << " size " << c->front()->rbuf[process_rbuf]->bufsize() << " other " << other_rbuf << " size " << c->front()->rbuf[other_rbuf]->bufsize() << endl;
-}
-
index ad5079ee85273858bcd599586f6a0afaa05508fa..5e33891aa81e1fb45c8b816d82aee89ab5120e8e 100644 (file)
@@ -1448,7 +1448,7 @@ Session::auto_loop_changed (Location* location)
 
                                // schedule a buffer overwrite to refill buffers with the new loop.
 
-                               request_overwrite_buffer (boost::shared_ptr<Track>());
+                               request_overwrite_buffer (boost::shared_ptr<Track>(), LoopChanged);
                        }
                }
 
index e7c250833eaa77f3968e4e84f568ece7730cf0c4..0744df6233e674428869909c647b8759c26a891e 100644 (file)
@@ -78,15 +78,16 @@ Session::schedule_capture_buffering_adjustment ()
 }
 
 void
-Session::request_overwrite_buffer (boost::shared_ptr<Track> t)
+Session::request_overwrite_buffer (boost::shared_ptr<Track> t, OverwriteReason why)
 {
        SessionEvent *ev = new SessionEvent (SessionEvent::Overwrite, SessionEvent::Add, SessionEvent::Immediate, 0, 0, 0.0);
        ev->set_track (t);
+       ev->overwrite = why;
        queue_event (ev);
 }
 
 void
-Session::overwrite_some_buffers (boost::shared_ptr<Route> r)
+Session::overwrite_some_buffers (boost::shared_ptr<Route> r, OverwriteReason why)
 {
        /* this is called from the process thread while handling queued
         * SessionEvents. Therefore neither playback sample or read offsets in
@@ -102,7 +103,7 @@ Session::overwrite_some_buffers (boost::shared_ptr<Route> r)
        if (r) {
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (r);
                assert (t);
-               t->set_pending_overwrite ();
+               t->set_pending_overwrite (why);
 
        } else {
 
@@ -110,7 +111,7 @@ Session::overwrite_some_buffers (boost::shared_ptr<Route> r)
                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                        boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
                        if (tr) {
-                               tr->set_pending_overwrite ();
+                               tr->set_pending_overwrite (why);
                        }
                }
        }
index fee4145f2a42b8f78cd80589852731e88973c655..8345c3c79bc0941b8b063d06a5331c0118cd7b56 100644 (file)
@@ -934,7 +934,7 @@ Session::process_event (SessionEvent* ev)
                break;
 
        case SessionEvent::Overwrite:
-               overwrite_some_buffers (ev->track);
+               overwrite_some_buffers (ev->track, ev->overwrite);
                break;
 
        case SessionEvent::Audition:
index 13d99a9b1128ff9f2f647c2571d0f3598f3be425..2c93e10d47ae676238a480b0d5776981e3bc756f 100644 (file)
@@ -1647,7 +1647,7 @@ Session::unset_play_loop (bool change_transport_state)
                        TFSM_EVENT (TransportFSM::StopTransport);
                }
 
-               overwrite_some_buffers (boost::shared_ptr<Route>());
+               overwrite_some_buffers (boost::shared_ptr<Route>(), LoopDisabled);
 
                TransportStateChange (); /* EMIT SIGNAL */
        }
index e9c29ffa835a4500aff05a38148423ebd7c51988..f2cb9a5b3a63ef2b55b981944ae9343f5741c3f5 100644 (file)
@@ -503,9 +503,9 @@ Track::do_flush (RunContext c, bool force)
 }
 
 void
-Track::set_pending_overwrite ()
+Track::set_pending_overwrite (OverwriteReason why)
 {
-       _disk_reader->set_pending_overwrite ();
+       _disk_reader->set_pending_overwrite (why);
 }
 
 int
index 932f9224b3f91c8998eb0957822cfd00f7f10c2e..1981adcdd8263b6c8ca588a8f423bd68acd1856a 100644 (file)
@@ -119,6 +119,13 @@ public:
        guint write (T const * src, guint cnt);
        /* write-thead */
        guint write_zero (guint cnt);
+       /* read-thead */
+       guint increment_write_ptr (guint cnt)
+       {
+               cnt = std::min (cnt, write_space ());
+               g_atomic_int_set (&write_idx, (g_atomic_int_get (&write_idx) + cnt) & size_mask);
+               return cnt;
+       }
 
        /* read-thead */
        void read_flush ()
@@ -171,6 +178,9 @@ public:
                }
        }
 
+       guint read_ptr() const { return read_idx; }
+       guint reserved_size() const { return reserved; }
+
 private:
        T *buf;
        guint reservation;