+
+/** @return AudioBuffers object containing only the given channel from this AudioBuffers */
+shared_ptr<AudioBuffers>
+AudioBuffers::channel (int channel) const
+{
+ auto output = make_shared<AudioBuffers>(1, frames());
+ output->copy_channel_from (this, channel, 0);
+ return output;
+}
+
+
+/** Copy all the samples from a channel on another AudioBuffers to a channel on this one.
+ * @param from AudioBuffers to copy from.
+ * @param from_channel Channel index in `from' to copy from.
+ * @param to_channel Channel index in this to copy into, overwriting what's already there.
+ */
+void
+AudioBuffers::copy_channel_from (AudioBuffers const * from, int from_channel, int to_channel)
+{
+ DCPOMATIC_ASSERT (from->frames() == frames());
+ memcpy (data(to_channel), from->data(from_channel), frames() * sizeof (float));
+}
+
+
+/** Make a copy of these AudioBuffers */
+shared_ptr<AudioBuffers>
+AudioBuffers::clone () const
+{
+ auto b = make_shared<AudioBuffers>(channels(), frames());
+ b->copy_from (this, frames(), 0, 0);
+ return b;
+}
+
+
+/** Extend these buffers with the data from another. The AudioBuffers must have the same number of channels. */
+void
+AudioBuffers::append (shared_ptr<const AudioBuffers> other)
+{
+ DCPOMATIC_ASSERT (channels() == other->channels());
+ auto old_frames = frames();
+ set_frames(old_frames + other->frames());
+ copy_from (other.get(), other->frames(), 0, old_frames);
+}
+
+
+/** Remove some frames from the start of these AudioBuffers */
+void
+AudioBuffers::trim_start (int frames_to_trim)
+{
+ DCPOMATIC_ASSERT (frames_to_trim <= frames());
+ move (frames() - frames_to_trim, frames_to_trim, 0);
+ set_frames (frames() - frames_to_trim);
+}
+
+
+void
+AudioBuffers::update_data_pointers ()
+{
+ _data_pointers.resize (channels());
+ for (int i = 0; i < channels(); ++i) {
+ _data_pointers[i] = _data[i].data();
+ }
+}
+