mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-25 16:07:49 +01:00
add initial support for vari-fill
When refilling playback buffer, try to fill it completely, or at least using the next-lowest power-of-2 as the amount to read. When locating, where we use do_refill_with_alloc(), only partially fill the buffer. Work not yet finished, but possibly promising. Conflicts: libs/ardour/ardour/midi_diskstream.h libs/ardour/diskstream.cc
This commit is contained in:
parent
0ffc6cef5d
commit
a846c8fc0e
7 changed files with 89 additions and 47 deletions
|
|
@ -209,9 +209,8 @@ class LIBARDOUR_API AudioDiskstream : public Diskstream
|
|||
|
||||
/* The two central butler operations */
|
||||
int do_flush (RunContext context, bool force = false);
|
||||
int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer); }
|
||||
int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer, 0); }
|
||||
|
||||
int do_refill_with_alloc ();
|
||||
|
||||
int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
|
||||
framepos_t& start, framecnt_t cnt,
|
||||
|
|
@ -258,9 +257,12 @@ class LIBARDOUR_API AudioDiskstream : public Diskstream
|
|||
|
||||
SerializedRCUManager<ChannelList> channels;
|
||||
|
||||
protected:
|
||||
int _do_refill_with_alloc (bool one_chunk_only);
|
||||
|
||||
/* really */
|
||||
private:
|
||||
int _do_refill (Sample *mixdown_buffer, float *gain_buffer);
|
||||
int _do_refill (Sample *mixdown_buffer, float *gain_buffer, framecnt_t fill_level);
|
||||
|
||||
int add_channel_to (boost::shared_ptr<ChannelList>, uint32_t how_many);
|
||||
int remove_channel_from (boost::shared_ptr<ChannelList>, uint32_t how_many);
|
||||
|
|
|
|||
|
|
@ -173,8 +173,15 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream
|
|||
void move_processor_automation (boost::weak_ptr<Processor>,
|
||||
std::list<Evoral::RangeMove<framepos_t> > const &);
|
||||
|
||||
/** For non-butler contexts (allocates temporary working buffers) */
|
||||
virtual int do_refill_with_alloc() = 0;
|
||||
/** For non-butler contexts (allocates temporary working buffers)
|
||||
*
|
||||
* This accessible method has a default argument; derived classes
|
||||
* must inherit the virtual method that we call which does NOT
|
||||
* have a default argument, to avoid complications with inheritance
|
||||
*/
|
||||
int do_refill_with_alloc(bool partial_fill = true) {
|
||||
return _do_refill_with_alloc (partial_fill);
|
||||
}
|
||||
virtual void set_block_size (pframes_t) = 0;
|
||||
|
||||
bool pending_overwrite () const {
|
||||
|
|
@ -206,6 +213,11 @@ class LIBARDOUR_API Diskstream : public SessionObject, public PublicDiskstream
|
|||
virtual int can_internal_playback_seek (framecnt_t distance) = 0;
|
||||
virtual void reset_write_sources (bool, bool force = false) = 0;
|
||||
virtual void non_realtime_input_change () = 0;
|
||||
/* accessible method has default argument, so use standard C++ "trick"
|
||||
to avoid complications with inheritance, by adding this virtual
|
||||
method which does NOT have a default argument.
|
||||
*/
|
||||
virtual int _do_refill_with_alloc (bool partial_fill) = 0;
|
||||
|
||||
protected:
|
||||
friend class Auditioner;
|
||||
|
|
|
|||
|
|
@ -122,11 +122,13 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
|
|||
protected:
|
||||
friend class MidiTrack;
|
||||
friend class Auditioner;
|
||||
int seek (framepos_t which_sample, bool complete_refill = false);
|
||||
|
||||
int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_diskstream);
|
||||
frameoffset_t calculate_playback_distance (pframes_t nframes);
|
||||
bool commit (framecnt_t nframes);
|
||||
int seek (framepos_t which_sample, bool complete_refill = false);
|
||||
int _do_refill_with_alloc (bool one_chunk_only);
|
||||
int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_diskstream);
|
||||
frameoffset_t calculate_playback_distance (pframes_t nframes);
|
||||
bool commit (framecnt_t nframes);
|
||||
|
||||
static framecnt_t midi_readahead;
|
||||
|
||||
private:
|
||||
|
|
@ -135,8 +137,6 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
|
|||
int do_flush (RunContext context, bool force = false);
|
||||
int do_refill ();
|
||||
|
||||
int do_refill_with_alloc();
|
||||
|
||||
int read (framepos_t& start, framecnt_t cnt, bool reversed);
|
||||
|
||||
void finish_capture ();
|
||||
|
|
|
|||
|
|
@ -918,9 +918,15 @@ AudioDiskstream::seek (framepos_t frame, bool complete_refill)
|
|||
file_frame = frame;
|
||||
|
||||
if (complete_refill) {
|
||||
while ((ret = do_refill_with_alloc ()) > 0) ;
|
||||
/* call _do_refill() to refill the entire buffer, using
|
||||
the largest reads possible.
|
||||
*/
|
||||
while ((ret = do_refill_with_alloc (false)) > 0) ;
|
||||
} else {
|
||||
ret = do_refill_with_alloc ();
|
||||
/* call _do_refill() to refill just one chunk, and then
|
||||
return.
|
||||
*/
|
||||
ret = do_refill_with_alloc (true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -1061,12 +1067,13 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
|
|||
}
|
||||
|
||||
int
|
||||
AudioDiskstream::do_refill_with_alloc ()
|
||||
AudioDiskstream::_do_refill_with_alloc (bool partial_fill)
|
||||
{
|
||||
Sample* mix_buf = new Sample[disk_read_chunk_frames];
|
||||
float* gain_buf = new float[disk_read_chunk_frames];
|
||||
Sample* mix_buf = new Sample[1048576];
|
||||
float* gain_buf = new float[1048576];
|
||||
|
||||
int ret = _do_refill(mix_buf, gain_buf);
|
||||
int ret = _do_refill (mix_buf, gain_buf, (partial_fill ?
|
||||
(_session.butler()->audio_diskstream_playback_buffer_size() / 4.0) : 0));
|
||||
|
||||
delete [] mix_buf;
|
||||
delete [] gain_buf;
|
||||
|
|
@ -1076,9 +1083,15 @@ AudioDiskstream::do_refill_with_alloc ()
|
|||
|
||||
/** Get some more data from disk and put it in our channels' playback_bufs,
|
||||
* if there is suitable space in them.
|
||||
*
|
||||
* If fill_level is non-zero, then we will refill the buffer so that there is
|
||||
* still at least fill_level samples of space left to be filled. This is used
|
||||
* after locates so that we do not need to wait to fill the entire buffer.
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
||||
AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, framecnt_t fill_level)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
framecnt_t to_read;
|
||||
|
|
@ -1110,13 +1123,12 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* if there are 2+ chunks of disk i/o possible for
|
||||
this track, let the caller know so that it can arrange
|
||||
for us to be called again, ASAP.
|
||||
*/
|
||||
|
||||
if (total_space >= (_slaved ? 3 : 2) * disk_read_chunk_frames) {
|
||||
ret = 1;
|
||||
if (fill_level && (fill_level < total_space)) {
|
||||
cerr << name() << " adjust total space of " << total_space << " to leave " << fill_level << " to still refill\n";
|
||||
if (fill_level < 0) {
|
||||
PBD::stacktrace (cerr, 20);
|
||||
}
|
||||
total_space -= fill_level;
|
||||
}
|
||||
|
||||
/* if we're running close to normal speed and there isn't enough
|
||||
|
|
@ -1143,10 +1155,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* never do more than disk_read_chunk_frames worth of disk input per call (limit doesn't apply for memset) */
|
||||
|
||||
total_space = min (disk_read_chunk_frames, total_space);
|
||||
|
||||
if (reversed) {
|
||||
|
||||
if (file_frame == 0) {
|
||||
|
|
@ -1213,6 +1221,34 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
|||
|
||||
framepos_t file_frame_tmp = 0;
|
||||
|
||||
/* this needs to be 32 bit for the power-of-two hack below to work.
|
||||
Clever, but poses ugly casting problems since the value is
|
||||
semantically a framecnt_t.
|
||||
*/
|
||||
|
||||
uint32_t chunk_size_for_read = (uint32_t) max ((framecnt_t) 65536, min ((framecnt_t) 1048576, total_space));
|
||||
|
||||
/* if not already a power of 2, go to next lower power of 2 */
|
||||
|
||||
if ((chunk_size_for_read & (chunk_size_for_read - 1)) != 0) {
|
||||
|
||||
/* move to the next largest power of two. Hack from stanford bithacks page. */
|
||||
|
||||
chunk_size_for_read--;
|
||||
chunk_size_for_read |= chunk_size_for_read >> 1;
|
||||
chunk_size_for_read |= chunk_size_for_read >> 2;
|
||||
chunk_size_for_read |= chunk_size_for_read >> 4;
|
||||
chunk_size_for_read |= chunk_size_for_read >> 8;
|
||||
chunk_size_for_read |= chunk_size_for_read >> 16;
|
||||
chunk_size_for_read++;
|
||||
|
||||
/* go back to previous power */
|
||||
|
||||
chunk_size_for_read >>= 1;
|
||||
}
|
||||
|
||||
cerr << name() << " will read " << chunk_size_for_read << " out of total space " << total_space << " in buffer of " << c->front()->playback_buf->bufsize() << endl;
|
||||
|
||||
for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
|
||||
|
||||
ChannelInfo* chan (*i);
|
||||
|
|
@ -1222,7 +1258,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
|||
|
||||
chan->playback_buf->get_write_vector (&vector);
|
||||
|
||||
if ((framecnt_t) vector.len[0] > disk_read_chunk_frames) {
|
||||
if ((framecnt_t) vector.len[0] > chunk_size_for_read) {
|
||||
|
||||
/* we're not going to fill the first chunk, so certainly do not bother with the
|
||||
other part. it won't be connected with the part we do fill, as in:
|
||||
|
|
@ -1254,7 +1290,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
|||
len2 = vector.len[1];
|
||||
|
||||
to_read = min (ts, len1);
|
||||
to_read = min (to_read, disk_read_chunk_frames);
|
||||
to_read = min (to_read, (framecnt_t) chunk_size_for_read);
|
||||
|
||||
assert (to_read >= 0);
|
||||
|
||||
|
|
@ -1273,8 +1309,9 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
|||
|
||||
if (to_read) {
|
||||
|
||||
/* we read all of vector.len[0], but it wasn't an entire disk_read_chunk_frames of data,
|
||||
so read some or all of vector.len[1] as well.
|
||||
/* we read all of vector.len[0], but it wasn't the
|
||||
entire chunk_size_for_read of data, so read some or
|
||||
all of vector.len[1] as well.
|
||||
*/
|
||||
|
||||
if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan_n, reversed)) {
|
||||
|
|
@ -1294,8 +1331,9 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
|
|||
file_frame = file_frame_tmp;
|
||||
assert (file_frame >= 0);
|
||||
|
||||
ret = ((total_space - chunk_size_for_read) > disk_read_chunk_frames);
|
||||
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -803,22 +803,12 @@ Diskstream::set_own_replication_path (const std::string& path)
|
|||
framecnt_t
|
||||
Diskstream::default_disk_read_chunk_frames()
|
||||
{
|
||||
/*
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
return (2 * 1048576) / sizeof (Sample);
|
||||
#elif defined __APPLE__
|
||||
return (4 * 1048576) / sizeof (Sample);
|
||||
#else
|
||||
return 65536;
|
||||
#endif*/
|
||||
//GZ to Paul Davis FIX-ME restored old value which used to work with current ring buffer capacity
|
||||
return 65536;
|
||||
}
|
||||
|
||||
framecnt_t
|
||||
Diskstream::default_disk_write_chunk_frames ()
|
||||
{
|
||||
//GZ to Paul Davis FIX-ME restored old value which used to work with current ring buffer capacity
|
||||
return 65536;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
|
|||
}
|
||||
|
||||
int
|
||||
MidiDiskstream::do_refill_with_alloc ()
|
||||
MidiDiskstream::_do_refill_with_alloc (bool /* partial_fill */)
|
||||
{
|
||||
return do_refill();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ Session::butler_transport_work ()
|
|||
finished = true;
|
||||
ptw = post_transport_work();
|
||||
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1\n", enum_2_string (ptw)));
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1 at %2\n", enum_2_string (ptw), g_get_monotonic_time()));
|
||||
|
||||
if (ptw & PostTransportAdjustPlaybackBuffering) {
|
||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||
|
|
@ -409,7 +409,7 @@ Session::butler_transport_work ()
|
|||
|
||||
g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Transport, X_("Butler transport work all done\n"));
|
||||
DEBUG_TRACE (DEBUG::Transport, string_compose (X_("Butler transport work all done at %1\n"), g_get_monotonic_time()));
|
||||
DEBUG_TRACE (DEBUG::Transport, X_(string_compose ("Frame %1\n", _transport_frame)));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue