2 Copyright (C) 2009-2016 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "ardour/audioplaylist.h"
23 #include "ardour/audio_buffer.h"
24 #include "ardour/butler.h"
25 #include "ardour/debug.h"
26 #include "ardour/disk_reader.h"
27 #include "ardour/playlist.h"
28 #include "ardour/playlist_factory.h"
29 #include "ardour/session.h"
30 #include "ardour/session_playlists.h"
32 using namespace ARDOUR;
36 ARDOUR::framecnt_t DiskReader::_chunk_frames = default_chunk_frames ();
38 DiskReader::DiskReader (Session& s, string const & str, DiskIOProcessor::Flag f)
39 : DiskIOProcessor (s, str, f)
42 , overwrite_offset (0)
43 , _pending_overwrite (false)
44 , overwrite_queued (false)
47 , _monitoring_choice (MonitorDisk)
48 , channels (new ChannelList)
52 DiskReader::~DiskReader ()
54 DEBUG_TRACE (DEBUG::Destruction, string_compose ("DiskReader %1 deleted\n", _name));
57 _playlist->release ();
61 RCUWriter<ChannelList> writer (channels);
62 boost::shared_ptr<ChannelList> c = writer.get_copy();
64 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
75 DiskReader::allocate_working_buffers()
77 /* with varifill buffer refilling, we compute the read size in bytes (to optimize
78 for disk i/o bandwidth) and then convert back into samples. These buffers
79 need to reflect the maximum size we could use, which is 4MB reads, or 2M samples
82 _mixdown_buffer = new Sample[2*1048576];
83 _gain_buffer = new gain_t[2*1048576];
87 DiskReader::free_working_buffers()
89 delete [] _mixdown_buffer;
90 delete [] _gain_buffer;
96 DiskReader::default_chunk_frames()
102 DiskReader::set_name (string const & str)
106 _playlist->set_name (str);
107 SessionObject::set_name(str);
114 DiskReader::set_roll_delay (ARDOUR::framecnt_t nframes)
116 _roll_delay = nframes;
120 DiskReader::set_state (const XMLNode& node, int version)
122 XMLProperty const * prop;
124 if (DiskIOProcessor::set_state (node, version)) {
128 if ((prop = node.property ("playlist")) == 0) {
132 if (find_and_use_playlist (prop->value())) {
139 /* Processor interface */
142 DiskReader::configure_io (ChanCount in, ChanCount out)
148 DiskReader::can_support_io_configuration (const ChanCount& in, ChanCount& out)
154 DiskReader::realtime_handle_transport_stopped ()
159 DiskReader::realtime_locate ()
164 DiskReader::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many)
167 c->push_back (new ChannelInfo(
168 _session.butler()->audio_diskstream_playback_buffer_size(),
169 speed_buffer_size, wrap_buffer_size));
170 interpolation.add_channel_to (
171 _session.butler()->audio_diskstream_playback_buffer_size(),
175 _n_channels.set (DataType::AUDIO, c->size());
181 DiskReader::add_channel (uint32_t how_many)
183 RCUWriter<ChannelList> writer (channels);
184 boost::shared_ptr<ChannelList> c = writer.get_copy();
186 return add_channel_to (c, how_many);
190 DiskReader::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
192 while (how_many-- && !c->empty()) {
195 interpolation.remove_channel_from ();
198 _n_channels.set(DataType::AUDIO, c->size());
204 DiskReader::remove_channel (uint32_t how_many)
206 RCUWriter<ChannelList> writer (channels);
207 boost::shared_ptr<ChannelList> c = writer.get_copy();
209 return remove_channel_from (c, how_many);
213 DiskReader::buffer_load () const
215 boost::shared_ptr<ChannelList> c = channels.reader();
221 return (float) ((double) c->front()->buf->read_space()/
222 (double) c->front()->buf->bufsize());
226 DiskReader::adjust_buffering ()
228 boost::shared_ptr<ChannelList> c = channels.reader();
230 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
231 (*chan)->resize (_session.butler()->audio_diskstream_playback_buffer_size());
235 DiskReader::ChannelInfo::ChannelInfo (framecnt_t bufsize, framecnt_t speed_size, framecnt_t wrap_size)
239 speed_buffer = new Sample[speed_size];
240 wrap_buffer = new Sample[wrap_size];
242 buf = new RingBufferNPT<Sample> (bufsize);
244 /* touch the ringbuffer buffer, which will cause
245 them to be mapped into locked physical RAM if
246 we're running with mlockall(). this doesn't do
250 memset (buf->buffer(), 0, sizeof (Sample) * buf->bufsize());
254 DiskReader::ChannelInfo::resize (framecnt_t bufsize)
257 buf = new RingBufferNPT<Sample> (bufsize);
258 memset (buf->buffer(), 0, sizeof (Sample) * buf->bufsize());
261 DiskReader::ChannelInfo::~ChannelInfo ()
263 delete [] speed_buffer;
266 delete [] wrap_buffer;
274 DiskReader::set_block_size (pframes_t /*nframes*/)
276 if (_session.get_block_size() > speed_buffer_size) {
277 speed_buffer_size = _session.get_block_size();
278 boost::shared_ptr<ChannelList> c = channels.reader();
280 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
281 delete [] (*chan)->speed_buffer;
282 (*chan)->speed_buffer = new Sample[speed_buffer_size];
285 allocate_temporary_buffers ();
290 DiskReader::allocate_temporary_buffers ()
292 /* make sure the wrap buffer is at least large enough to deal
293 with the speeds up to 1.2, to allow for micro-variation
294 when slaving to MTC, Timecode etc.
297 double const sp = max (fabs (_actual_speed), 1.2);
298 framecnt_t required_wrap_size = (framecnt_t) ceil (_session.get_block_size() * sp) + 2;
300 if (required_wrap_size > wrap_buffer_size) {
302 boost::shared_ptr<ChannelList> c = channels.reader();
304 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
305 if ((*chan)->wrap_buffer) {
306 delete [] (*chan)->wrap_buffer;
308 (*chan)->wrap_buffer = new Sample[required_wrap_size];
311 wrap_buffer_size = required_wrap_size;
317 DiskReader::playlist_changed (const PropertyChange&)
319 playlist_modified ();
323 DiskReader::playlist_modified ()
325 if (!i_am_the_modifier && !overwrite_queued) {
326 // !!!! _session.request_overwrite_buffer (this);
327 overwrite_queued = true;
332 DiskReader::playlist_deleted (boost::weak_ptr<Playlist> wpl)
334 boost::shared_ptr<Playlist> pl (wpl.lock());
336 if (pl == _playlist) {
338 /* this catches an ordering issue with session destruction. playlists
339 are destroyed before disk readers. we have to invalidate any handles
340 we have to the playlist.
350 DiskReader::use_playlist (boost::shared_ptr<Playlist> playlist)
356 bool prior_playlist = false;
359 Glib::Threads::Mutex::Lock lm (state_lock);
361 if (playlist == _playlist) {
365 playlist_connections.drop_connections ();
368 _playlist->release();
369 prior_playlist = true;
372 _playlist = playlist;
375 _playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&DiskReader::playlist_modified, this));
376 _playlist->LayeringChanged.connect_same_thread (playlist_connections, boost::bind (&DiskReader::playlist_modified, this));
377 _playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&DiskReader::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
378 _playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&DiskReader::playlist_ranges_moved, this, _1, _2));
381 /* don't do this if we've already asked for it *or* if we are setting up
382 the diskstream for the very first time - the input changed handling will
383 take care of the buffer refill.
386 if (!overwrite_queued && prior_playlist) {
387 // !!! _session.request_overwrite_buffer (this);
388 overwrite_queued = true;
391 PlaylistChanged (); /* EMIT SIGNAL */
392 _session.set_dirty ();
398 DiskReader::find_and_use_playlist (const string& name)
400 boost::shared_ptr<AudioPlaylist> playlist;
402 if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist> (_session.playlists->by_name (name))) == 0) {
403 playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (DataType::AUDIO, _session, name));
407 error << string_compose(_("DiskReader: Playlist \"%1\" isn't an audio playlist"), name) << endmsg;
411 return use_playlist (playlist);
415 DiskReader::use_new_playlist ()
418 boost::shared_ptr<AudioPlaylist> playlist;
421 newname = Playlist::bump_name (_playlist->name(), _session);
423 newname = Playlist::bump_name (_name, _session);
426 if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (DataType::AUDIO, _session, newname, hidden()))) != 0) {
428 return use_playlist (playlist);
436 DiskReader::use_copy_playlist ()
438 assert(audio_playlist());
440 if (_playlist == 0) {
441 error << string_compose(_("DiskReader %1: there is no existing playlist to make a copy of!"), _name) << endmsg;
446 boost::shared_ptr<AudioPlaylist> playlist;
448 newname = Playlist::bump_name (_playlist->name(), _session);
450 if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist>(PlaylistFactory::create (audio_playlist(), newname))) != 0) {
451 playlist->reset_shares();
452 return use_playlist (playlist);
459 /** Do some record stuff [not described in this comment!]
462 * - Setup playback_distance with the nframes, or nframes adjusted
463 * for current varispeed, if appropriate.
464 * - Setup current_buffer in each ChannelInfo to point to data
465 * that someone can read playback_distance worth of data from.
468 DiskReader::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
469 double speed, pframes_t nframes, bool result_required)
472 DiskReader::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes,
473 framecnt_t& playback_distance, bool need_disk_signal)
477 boost::shared_ptr<ChannelList> c = channels.reader();
478 ChannelList::iterator chan;
479 framecnt_t playback_distance = 0;
481 Glib::Threads::Mutex::Lock sm (state_lock, Glib::Threads::TRY_LOCK);
487 for (chan = c->begin(); chan != c->end(); ++chan) {
488 (*chan)->current_buffer = 0;
491 if (result_required || _monitoring_choice == MonitorDisk || _monitoring_choice == MonitorCue) {
493 /* we're doing playback */
495 framecnt_t necessary_samples;
497 if (_actual_speed != 1.0) {
498 necessary_samples = (framecnt_t) ceil ((nframes * fabs (_actual_speed))) + 2;
500 necessary_samples = nframes;
503 for (chan = c->begin(); chan != c->end(); ++chan) {
504 (*chan)->buf->get_read_vector (&(*chan)->read_vector);
509 /* Setup current_buffer in each ChannelInfo to point to data that someone
510 can read necessary_samples (== nframes at a transport speed of 1) worth of data
514 for (chan = c->begin(); chan != c->end(); ++chan, ++n) {
516 ChannelInfo* chaninfo (*chan);
518 if (necessary_samples <= (framecnt_t) chaninfo->read_vector.len[0]) {
519 /* There are enough samples in the first part of the ringbuffer */
520 chaninfo->current_buffer = chaninfo->read_vector.buf[0];
523 framecnt_t total = chaninfo->read_vector.len[0] + chaninfo->read_vector.len[1];
525 if (necessary_samples > total) {
526 cerr << _name << " Need " << necessary_samples << " total = " << total << endl;
527 cerr << "underrun for " << _name << endl;
528 DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 underrun in %2, total space = %3\n",
529 DEBUG_THREAD_SELF, name(), total));
535 /* We have enough samples, but not in one lump. Coalesce the two parts
536 into one in wrap_buffer in our ChannelInfo, and specify that
537 as our current_buffer.
540 assert(wrap_buffer_size >= necessary_samples);
542 /* Copy buf[0] from buf */
543 memcpy ((char *) chaninfo->wrap_buffer,
544 chaninfo->read_vector.buf[0],
545 chaninfo->read_vector.len[0] * sizeof (Sample));
547 /* Copy buf[1] from buf */
548 memcpy (chaninfo->wrap_buffer + chaninfo->read_vector.len[0],
549 chaninfo->read_vector.buf[1],
550 (necessary_samples - chaninfo->read_vector.len[0])
553 chaninfo->current_buffer = chaninfo->wrap_buffer;
558 if (_actual_speed != 1.0f && _actual_speed != -1.0f) {
560 interpolation.set_speed (_target_speed);
563 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) {
564 ChannelInfo* chaninfo (*chan);
566 playback_distance = interpolation.interpolate (
567 channel, nframes, chaninfo->current_buffer, chaninfo->speed_buffer);
569 chaninfo->current_buffer = chaninfo->speed_buffer;
573 playback_distance = nframes;
576 _speed = _target_speed;
579 if (result_required || _monitoring_choice == MonitorDisk || _monitoring_choice == MonitorCue) {
581 /* copy data over to buffer set */
583 size_t n_buffers = bufs.count().n_audio();
584 size_t n_chans = c->size();
585 gain_t scaling = 1.0f;
587 if (n_chans > n_buffers) {
588 scaling = ((float) n_buffers)/n_chans;
591 for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
593 AudioBuffer& buf (bufs.get_audio (n%n_buffers));
594 ChannelInfo* chaninfo (*chan);
597 if (scaling != 1.0f) {
598 buf.read_from_with_gain (chaninfo->current_buffer, nframes, scaling);
600 buf.read_from (chaninfo->current_buffer, nframes);
603 if (scaling != 1.0f) {
604 buf.accumulate_with_gain_from (chaninfo->current_buffer, nframes, scaling);
606 buf.accumulate_from (chaninfo->current_buffer, nframes);
611 /* leave the MIDI count alone */
612 ChanCount cnt (DataType::AUDIO, n_chans);
613 cnt.set (DataType::MIDI, bufs.count().n_midi());
614 bufs.set_count (cnt);
616 /* extra buffers will already be silent, so leave them alone */
619 bool need_butler = false;
621 if (_actual_speed < 0.0) {
622 playback_sample -= playback_distance;
624 playback_sample += playback_distance;
627 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
628 (*chan)->buf->increment_read_ptr (playback_distance);
633 need_butler = c->front()->buf->write_space() >= c->front()->buf->bufsize() / 2;
635 need_butler = (framecnt_t) c->front()->buf->write_space() >= _chunk_frames;
639 //return need_butler;
643 DiskReader::calculate_playback_distance (pframes_t nframes)
645 frameoffset_t playback_distance = nframes;
647 if (_actual_speed != 1.0f && _actual_speed != -1.0f) {
648 interpolation.set_speed (_target_speed);
649 boost::shared_ptr<ChannelList> c = channels.reader();
651 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) {
652 playback_distance = interpolation.interpolate (channel, nframes, NULL, NULL);
655 playback_distance = nframes;
658 if (_actual_speed < 0.0) {
659 return -playback_distance;
661 return playback_distance;
666 DiskReader::set_pending_overwrite (bool yn)
668 /* called from audio thread, so we can use the read ptr and playback sample as we wish */
670 _pending_overwrite = yn;
672 overwrite_frame = playback_sample;
674 boost::shared_ptr<ChannelList> c = channels.reader ();
676 overwrite_offset = c->front()->buf->get_read_ptr();
681 DiskReader::overwrite_existing_buffers ()
683 boost::shared_ptr<ChannelList> c = channels.reader();
685 _pending_overwrite = false;
689 Sample* mixdown_buffer;
692 bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
694 overwrite_queued = false;
696 /* assume all are the same size */
697 framecnt_t size = c->front()->buf->bufsize();
699 mixdown_buffer = new Sample[size];
700 gain_buffer = new float[size];
702 /* reduce size so that we can fill the buffer correctly (ringbuffers
703 can only handle size-1, otherwise they appear to be empty)
710 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) {
712 start = overwrite_frame;
713 framecnt_t cnt = size;
715 /* to fill the buffer without resetting the playback sample, we need to
716 do it one or two chunks (normally two).
718 |----------------------------------------------------------------------|
722 |<- second chunk->||<----------------- first chunk ------------------>|
726 framecnt_t to_read = size - overwrite_offset;
728 if (read ((*chan)->buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, start, to_read, n, reversed)) {
729 error << string_compose(_("DiskReader %1: when refilling, cannot read %2 from playlist at frame %3"),
730 id(), size, playback_sample) << endmsg;
738 if (read ((*chan)->buf->buffer(), mixdown_buffer, gain_buffer, start, cnt, n, reversed)) {
739 error << string_compose(_("DiskReader %1: when refilling, cannot read %2 from playlist at frame %3"),
740 id(), size, playback_sample) << endmsg;
749 _pending_overwrite = false;
750 delete [] gain_buffer;
751 delete [] mixdown_buffer;
756 DiskReader::non_realtime_locate (framepos_t location)
758 /* now refill channel buffers */
760 if (speed() != 1.0f || speed() != -1.0f) {
761 seek ((framepos_t) (location * (double) speed()), true);
763 seek (location, true);
768 DiskReader::seek (framepos_t frame, bool complete_refill)
772 ChannelList::iterator chan;
773 boost::shared_ptr<ChannelList> c = channels.reader();
775 Glib::Threads::Mutex::Lock lm (state_lock);
777 for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
778 (*chan)->buf->reset ();
781 playback_sample = frame;
784 if (complete_refill) {
785 /* call _do_refill() to refill the entire buffer, using
786 the largest reads possible.
788 while ((ret = do_refill_with_alloc (false)) > 0) ;
790 /* call _do_refill() to refill just one chunk, and then
793 ret = do_refill_with_alloc (true);
800 DiskReader::can_internal_playback_seek (framecnt_t distance)
802 ChannelList::iterator chan;
803 boost::shared_ptr<ChannelList> c = channels.reader();
805 for (chan = c->begin(); chan != c->end(); ++chan) {
806 if ((*chan)->buf->read_space() < (size_t) distance) {
814 DiskReader::internal_playback_seek (framecnt_t distance)
816 ChannelList::iterator chan;
817 boost::shared_ptr<ChannelList> c = channels.reader();
819 for (chan = c->begin(); chan != c->end(); ++chan) {
820 (*chan)->buf->increment_read_ptr (::llabs(distance));
823 playback_sample += distance;
829 void swap_by_ptr (Sample *first, Sample *last)
831 while (first < last) {
838 /** Read some data for 1 channel from our playlist into a buffer.
839 * @param buf Buffer to write to.
840 * @param start Session frame to start reading from; updated to where we end up
842 * @param cnt Count of samples to read.
843 * @param reversed true if we are running backwards, otherwise false.
846 DiskReader::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
847 framepos_t& start, framecnt_t cnt,
848 int channel, bool reversed)
850 framecnt_t this_read = 0;
852 framepos_t loop_end = 0;
853 framepos_t loop_start = 0;
854 framecnt_t offset = 0;
857 /* XXX we don't currently play loops in reverse. not sure why */
861 framecnt_t loop_length = 0;
863 /* Make the use of a Location atomic for this read operation.
865 Note: Locations don't get deleted, so all we care about
866 when I say "atomic" is that we are always pointing to
867 the same one and using a start/length values obtained
871 if ((loc = loop_location) != 0) {
872 loop_start = loc->start();
873 loop_end = loc->end();
874 loop_length = loop_end - loop_start;
877 /* if we are looping, ensure that the first frame we read is at the correct
878 position within the loop.
881 if (loc && start >= loop_end) {
882 start = loop_start + ((start - loop_start) % loop_length);
891 /* We need this while loop in case we hit a loop boundary, in which case our read from
892 the playlist must be split into more than one section.
897 /* take any loop into account. we can't read past the end of the loop. */
899 if (loc && (loop_end - start < cnt)) {
900 this_read = loop_end - start;
907 if (this_read == 0) {
911 this_read = min(cnt,this_read);
913 if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, start, this_read, channel) != this_read) {
914 error << string_compose(_("DiskReader %1: cannot read %2 from playlist at frame %3"), id(), this_read,
921 swap_by_ptr (buf, buf + this_read - 1);
925 /* if we read to the end of the loop, go back to the beginning */
942 DiskReader::_do_refill_with_alloc (bool partial_fill)
944 /* We limit disk reads to at most 4MB chunks, which with floating point
945 samples would be 1M samples. But we might use 16 or 14 bit samples,
946 in which case 4MB is more samples than that. Therefore size this for
947 the smallest sample value .. 4MB = 2M samples (16 bit).
950 Sample* mix_buf = new Sample[2*1048576];
951 float* gain_buf = new float[2*1048576];
953 int ret = _do_refill (mix_buf, gain_buf, (partial_fill ? _chunk_frames : 0));
961 /** Get some more data from disk and put it in our channels' bufs,
962 * if there is suitable space in them.
964 * If fill_level is non-zero, then we will refill the buffer so that there is
965 * still at least fill_level samples of space left to be filled. This is used
966 * after locates so that we do not need to wait to fill the entire buffer.
971 DiskReader::_do_refill (Sample* mixdown_buffer, float* gain_buffer, framecnt_t fill_level)
973 if (_session.state_of_the_state() & Session::Loading) {
979 RingBufferNPT<Sample>::rw_vector vector;
980 bool const reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
981 framecnt_t total_space;
982 framecnt_t zero_fill;
984 ChannelList::iterator i;
985 boost::shared_ptr<ChannelList> c = channels.reader();
988 /* do not read from disk while session is marked as Loading, to avoid
989 useless redundant I/O.
996 assert(mixdown_buffer);
1004 c->front()->buf->get_write_vector (&vector);
1006 if ((total_space = vector.len[0] + vector.len[1]) == 0) {
1007 /* nowhere to write to */
1012 if (fill_level < total_space) {
1013 total_space -= fill_level;
1015 /* we can't do anything with it */
1020 /* if we're running close to normal speed and there isn't enough
1021 space to do disk_read_chunk_frames of I/O, then don't bother.
1023 at higher speeds, just do it because the sync between butler
1024 and audio thread may not be good enough.
1026 Note: it is a design assumption that disk_read_chunk_frames is smaller
1027 than the playback buffer size, so this check should never trip when
1028 the playback buffer is empty.
1031 if ((total_space < _chunk_frames) && fabs (_actual_speed) < 2.0f) {
1035 /* when slaved, don't try to get too close to the read pointer. this
1036 leaves space for the buffer reversal to have something useful to
1040 if (_slaved && total_space < (framecnt_t) (c->front()->buf->bufsize() / 2)) {
1046 if (file_frame == 0) {
1048 /* at start: nothing to do but fill with silence */
1050 for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
1052 ChannelInfo* chan (*i);
1053 chan->buf->get_write_vector (&vector);
1054 memset (vector.buf[0], 0, sizeof(Sample) * vector.len[0]);
1055 if (vector.len[1]) {
1056 memset (vector.buf[1], 0, sizeof(Sample) * vector.len[1]);
1058 chan->buf->increment_write_ptr (vector.len[0] + vector.len[1]);
1063 if (file_frame < total_space) {
1065 /* too close to the start: read what we can,
1066 and then zero fill the rest
1069 zero_fill = total_space - file_frame;
1070 total_space = file_frame;
1079 if (file_frame == max_framepos) {
1081 /* at end: nothing to do but fill with silence */
1083 for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
1085 ChannelInfo* chan (*i);
1086 chan->buf->get_write_vector (&vector);
1087 memset (vector.buf[0], 0, sizeof(Sample) * vector.len[0]);
1088 if (vector.len[1]) {
1089 memset (vector.buf[1], 0, sizeof(Sample) * vector.len[1]);
1091 chan->buf->increment_write_ptr (vector.len[0] + vector.len[1]);
1096 if (file_frame > max_framepos - total_space) {
1098 /* to close to the end: read what we can, and zero fill the rest */
1100 zero_fill = total_space - (max_framepos - file_frame);
1101 total_space = max_framepos - file_frame;
1108 framepos_t file_frame_tmp = 0;
1110 /* total_space is in samples. We want to optimize read sizes in various sizes using bytes */
1112 const size_t bits_per_sample = format_data_width (_session.config.get_native_file_data_format());
1113 size_t total_bytes = total_space * bits_per_sample / 8;
1115 /* chunk size range is 256kB to 4MB. Bigger is faster in terms of MB/sec, but bigger chunk size always takes longer
1117 size_t byte_size_for_read = max ((size_t) (256 * 1024), min ((size_t) (4 * 1048576), total_bytes));
1119 /* find nearest (lower) multiple of 16384 */
1121 byte_size_for_read = (byte_size_for_read / 16384) * 16384;
1123 /* now back to samples */
1125 framecnt_t samples_to_read = byte_size_for_read / (bits_per_sample / 8);
1127 //cerr << name() << " will read " << byte_size_for_read << " out of total bytes " << total_bytes << " in buffer of "
1128 // << c->front()->buf->bufsize() * bits_per_sample / 8 << " bps = " << bits_per_sample << endl;
1129 // cerr << name () << " read samples = " << samples_to_read << " out of total space " << total_space << " in buffer of " << c->front()->buf->bufsize() << " samples\n";
1131 // uint64_t before = g_get_monotonic_time ();
1132 // uint64_t elapsed;
1134 for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
1136 ChannelInfo* chan (*i);
1139 framecnt_t len1, len2;
1141 chan->buf->get_write_vector (&vector);
1143 if ((framecnt_t) vector.len[0] > samples_to_read) {
1145 /* we're not going to fill the first chunk, so certainly do not bother with the
1146 other part. it won't be connected with the part we do fill, as in:
1148 .... => writable space
1149 ++++ => readable space
1150 ^^^^ => 1 x disk_read_chunk_frames that would be filled
1152 |......|+++++++++++++|...............................|
1157 So, just pretend that the buf1 part isn't there.
1167 file_frame_tmp = file_frame;
1169 buf1 = vector.buf[0];
1170 len1 = vector.len[0];
1171 buf2 = vector.buf[1];
1172 len2 = vector.len[1];
1174 to_read = min (ts, len1);
1175 to_read = min (to_read, (framecnt_t) samples_to_read);
1177 assert (to_read >= 0);
1181 if (read (buf1, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan_n, reversed)) {
1186 chan->buf->increment_write_ptr (to_read);
1190 to_read = min (ts, len2);
1194 /* we read all of vector.len[0], but it wasn't the
1195 entire samples_to_read of data, so read some or
1196 all of vector.len[1] as well.
1199 if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan_n, reversed)) {
1204 chan->buf->increment_write_ptr (to_read);
1208 /* XXX: do something */
1213 // elapsed = g_get_monotonic_time () - before;
1214 // cerr << "\tbandwidth = " << (byte_size_for_read / 1048576.0) / (elapsed/1000000.0) << "MB/sec\n";
1216 file_frame = file_frame_tmp;
1217 assert (file_frame >= 0);
1219 ret = ((total_space - samples_to_read) > _chunk_frames);
1221 c->front()->buf->get_write_vector (&vector);