don't bother to re-seek/locate/refill buffers when disk IO processor config changes...
[ardour.git] / libs / ardour / disk_io.cc
index 1516933e321c9c4e3e20381e5088b0a5310b7d2a..64c645bdc35110e3a5eb01322cd0f9831f1ae7c8 100644 (file)
 
 */
 
+#include "pbd/debug.h"
 #include "pbd/error.h"
 #include "pbd/i18n.h"
 
 #include "ardour/audioplaylist.h"
 #include "ardour/butler.h"
+#include "ardour/debug.h"
 #include "ardour/disk_io.h"
 #include "ardour/disk_reader.h"
 #include "ardour/disk_writer.h"
@@ -47,23 +49,22 @@ DiskIOProcessor::DiskIOProcessor (Session& s, string const & str, Flag f)
        : Processor (s, str)
        , _flags (f)
        , i_am_the_modifier (false)
-       , _visible_speed (0.0)
-       , _actual_speed (0.0)
-       , _speed (0.0)
-       , _target_speed (0.0)
        , _buffer_reallocation_required (false)
        , _seek_required (false)
        , _slaved (false)
        , loop_location (0)
        , in_set_state (false)
+        , file_frame (0)
+        , playback_sample (0)
         , wrap_buffer_size (0)
         , speed_buffer_size (0)
        , _need_butler (false)
        , channels (new ChannelList)
-       , _midi_buf (0)
+       , _midi_buf (new MidiRingBuffer<framepos_t> (s.butler()->midi_diskstream_buffer_size()))
        , _frames_written_to_ringbuffer (0)
        , _frames_read_from_ringbuffer (0)
 {
+       midi_interpolation.add_channel_to (0,0);
 }
 
 void
@@ -135,10 +136,8 @@ DiskIOProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& o
                return false;
        }
 
-       if (in != out) {
-               /* currently no way to deliver different channels that we receive */
-               return false;
-       }
+       /* currently no way to deliver different channels that we receive */
+       out = in;
 
        return true;
 }
@@ -146,28 +145,30 @@ DiskIOProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& o
 bool
 DiskIOProcessor::configure_io (ChanCount in, ChanCount out)
 {
-       Glib::Threads::Mutex::Lock lm (state_lock);
+       DEBUG_TRACE (DEBUG::DiskIO, string_compose ("Configuring %1 for in:%2 out:%3\n", name(), in, out));
 
        RCUWriter<ChannelList> writer (channels);
        boost::shared_ptr<ChannelList> c = writer.get_copy();
 
        uint32_t n_audio = in.n_audio();
+       bool changed = false;
 
        if (n_audio > c->size()) {
                add_channel_to (c, n_audio - c->size());
+               changed = true;
        } else if (n_audio < c->size()) {
                remove_channel_from (c, c->size() - n_audio);
+               changed = true;
        }
 
        if (in.n_midi() > 0 && !_midi_buf) {
                const size_t size = _session.butler()->midi_diskstream_buffer_size();
                _midi_buf = new MidiRingBuffer<framepos_t>(size);
                midi_interpolation.add_channel_to (0,0);
+               changed = true;
        }
 
-       if (speed() != 1.0f || speed() != -1.0f) {
-               seek ((framepos_t) (_session.transport_frame() * (double) speed()));
-       } else {
+       if (changed) {
                seek (_session.transport_frame());
        }
 
@@ -201,66 +202,35 @@ DiskIOProcessor::non_realtime_locate (framepos_t location)
 {
        /* now refill channel buffers */
 
-       if (speed() != 1.0f || speed() != -1.0f) {
-               seek ((framepos_t) (location * (double) speed()), true);
-       } else {
-               seek (location, true);
-       }
+       seek (location, true);
 }
 
 void
-DiskIOProcessor::non_realtime_set_speed ()
+DiskIOProcessor::non_realtime_speed_change ()
 {
-       if (_buffer_reallocation_required)
-       {
-               Glib::Threads::Mutex::Lock lm (state_lock);
+       if (_buffer_reallocation_required) {
                _buffer_reallocation_required = false;
        }
 
        if (_seek_required) {
-               if (speed() != 1.0f || speed() != -1.0f) {
-                       seek ((framepos_t) (_session.transport_frame() * (double) speed()), true);
-               }
-               else {
-                       seek (_session.transport_frame(), true);
-               }
-
+               seek (_session.transport_frame(), true);
                _seek_required = false;
        }
 }
 
 bool
-DiskIOProcessor::realtime_set_speed (double sp, bool global)
+DiskIOProcessor::realtime_speed_change ()
 {
-       bool changed = false;
-       double new_speed = sp * _session.transport_speed();
-
-       if (_visible_speed != sp) {
-               _visible_speed = sp;
-               changed = true;
-       }
-
-       if (new_speed != _actual_speed) {
-
-               framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() *
-                                                                  fabs (new_speed)) + 2;
-
-               if (required_wrap_size > wrap_buffer_size) {
-                       _buffer_reallocation_required = true;
-               }
-
-               _actual_speed = new_speed;
-               _target_speed = fabs(_actual_speed);
-       }
+       const framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() * fabs (_session.transport_speed())) + 2;
+       bool _buffer_reallocation_required;
 
-       if (changed) {
-               if (!global) {
-                       _seek_required = true;
-               }
-               SpeedChanged (); /* EMIT SIGNAL */
+       if (required_wrap_size > wrap_buffer_size) {
+               _buffer_reallocation_required = true;
+       } else {
+               _buffer_reallocation_required = false;
        }
 
-       return _buffer_reallocation_required || _seek_required;
+       return _buffer_reallocation_required;
 }
 
 int
@@ -274,13 +244,6 @@ DiskIOProcessor::set_state (const XMLNode& node, int version)
                _flags = Flag (string_2_enum (prop->value(), _flags));
        }
 
-       if ((prop = node.property ("speed")) != 0) {
-               double sp = atof (prop->value().c_str());
-
-               if (realtime_set_speed (sp, false)) {
-                       non_realtime_set_speed ();
-               }
-       }
        return 0;
 }
 
@@ -290,6 +253,10 @@ DiskIOProcessor::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_
        while (how_many--) {
                c->push_back (new ChannelInfo (_session.butler()->audio_diskstream_playback_buffer_size()));
                interpolation.add_channel_to (_session.butler()->audio_diskstream_playback_buffer_size(), speed_buffer_size);
+               DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: new channel, write space = %2 read = %3\n",
+                                                           name(),
+                                                           c->back()->buf->write_space(),
+                                                           c->back()->buf->read_space()));
        }
 
        return 0;
@@ -366,27 +333,28 @@ DiskIOProcessor::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist
                 return 0;
         }
 
-       {
-               Glib::Threads::Mutex::Lock lm (state_lock);
+        DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: set to use playlist %2 (%3)\n", name(), playlist->name(), dt.to_string()));
 
-               if (playlist == _playlists[dt]) {
-                       return 0;
-               }
+        if (playlist == _playlists[dt]) {
+               DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: already using that playlist\n", name()));
+               return 0;
+        }
 
-               playlist_connections.drop_connections ();
+        playlist_connections.drop_connections ();
 
-               if (_playlists[dt]) {
-                       _playlists[dt]->release();
-               }
+        if (_playlists[dt]) {
+               _playlists[dt]->release();
+        }
 
-               _playlists[dt] = playlist;
-               playlist->use();
+        _playlists[dt] = playlist;
+        playlist->use();
 
-               playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
-               playlist->LayeringChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
-               playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_deleted, this, boost::weak_ptr<Playlist>(playlist)));
-               playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_ranges_moved, this, _1, _2));
-       }
+        playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
+        playlist->LayeringChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
+        playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_deleted, this, boost::weak_ptr<Playlist>(playlist)));
+        playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_ranges_moved, this, _1, _2));
+
+       DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 now using playlist %1 (%2)\n", name(), playlist->name(), playlist->id()));
 
        PlaylistChanged (dt); /* EMIT SIGNAL */
        _session.set_dirty ();
@@ -394,68 +362,6 @@ DiskIOProcessor::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist
        return 0;
 }
 
-int
-DiskIOProcessor::find_and_use_playlist (DataType dt, const string& name)
-{
-       boost::shared_ptr<Playlist> playlist;
-
-       if ((playlist = _session.playlists->by_name (name)) == 0) {
-               playlist = PlaylistFactory::create (dt, _session, name);
-       }
-
-       if (!playlist) {
-               error << string_compose(_("DiskIOProcessor: \"%1\" isn't an playlist"), name) << endmsg;
-               return -1;
-       }
-
-       return use_playlist (dt, playlist);
-}
-
-int
-DiskIOProcessor::use_new_playlist (DataType dt)
-{
-       string newname;
-       boost::shared_ptr<Playlist> playlist = _playlists[dt];
-
-       if (playlist) {
-               newname = Playlist::bump_name (playlist->name(), _session);
-       } else {
-               newname = Playlist::bump_name (_name, _session);
-       }
-
-       playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (dt, _session, newname, hidden()));
-
-       if (!playlist) {
-               return -1;
-       }
-
-       return use_playlist (dt, playlist);
-}
-
-int
-DiskIOProcessor::use_copy_playlist (DataType dt)
-{
-       assert (_playlists[dt]);
-
-       if (_playlists[dt] == 0) {
-               error << string_compose(_("DiskIOProcessor %1: there is no existing playlist to make a copy of!"), _name) << endmsg;
-               return -1;
-       }
-
-       string newname;
-       boost::shared_ptr<Playlist> playlist;
-
-       newname = Playlist::bump_name (_playlists[dt]->name(), _session);
-
-       if ((playlist = PlaylistFactory::create (_playlists[dt], newname)) == 0) {
-               return -1;
-       }
-
-       playlist->reset_shares();
-
-       return use_playlist (dt, playlist);
-}
-
 DiskIOProcessor::ChannelInfo::ChannelInfo (framecnt_t bufsize)
 {
        buf = new RingBufferNPT<Sample> (bufsize);
@@ -487,8 +393,38 @@ DiskIOProcessor::ChannelInfo::~ChannelInfo ()
        capture_transition_buf = 0;
 }
 
+void
+DiskIOProcessor::drop_route ()
+{
+       _route.reset ();
+}
+
 void
 DiskIOProcessor::set_route (boost::shared_ptr<Route> r)
 {
        _route = r;
+
+       if (_route) {
+               _route->DropReferences.connect_same_thread (*this, boost::bind (&DiskIOProcessor::drop_route, this));
+       }
+}
+
+/** Get the start, end, and length of a location "atomically".
+ *
+ * Note: Locations don't get deleted, so all we care about when I say "atomic"
+ * is that we are always pointing to the same one and using start/length values
+ * obtained just once.  Use this function to achieve this since location being
+ * a parameter achieves this.
+ */
+void
+DiskIOProcessor::get_location_times(const Location* location,
+                   framepos_t*     start,
+                   framepos_t*     end,
+                   framepos_t*     length)
+{
+       if (location) {
+               *start  = location->start();
+               *end    = location->end();
+               *length = *end - *start;
+       }
 }