Audacity  3.0.3
Public Member Functions | Private Member Functions | Private Attributes | List of all members
RingBuffer Class Referencefinal

Holds streamed audio samples. More...

#include <RingBuffer.h>

Inheritance diagram for RingBuffer:
[legend]
Collaboration diagram for RingBuffer:
[legend]

Public Member Functions

 RingBuffer (sampleFormat format, size_t size)
 
 ~RingBuffer ()
 
size_t AvailForPut ()
 
size_t Put (constSamplePtr buffer, sampleFormat format, size_t samples, size_t padding=0)
 Does not apply dithering. More...
 
size_t Clear (sampleFormat format, size_t samples)
 
size_t AvailForGet ()
 
size_t Get (samplePtr buffer, sampleFormat format, size_t samples)
 Does not apply dithering. More...
 
size_t Discard (size_t samples)
 

Private Member Functions

size_t Filled (size_t start, size_t end)
 
size_t Free (size_t start, size_t end)
 

Private Attributes

NonInterfering< std::atomic< size_t > > mStart { 0 }
 
NonInterfering< std::atomic< size_t > > mEnd { 0 }
 
const size_t mBufferSize
 
sampleFormat mFormat
 
SampleBuffer mBuffer
 

Detailed Description

Holds streamed audio samples.

Assuming that there is only one thread writing, and one thread reading, this class implements a lock-free thread-safe bounded queue of samples with atomic variables that contain the first filled and free positions.

If two threads both need to read, or both need to write, they need to lock this class from outside using their own mutex.

AvailForPut and AvailForGet may underestimate but will never overestimate.

Definition at line 17 of file RingBuffer.h.

Constructor & Destructor Documentation

◆ RingBuffer()

RingBuffer::RingBuffer ( sampleFormat  format,
size_t  size 
)

Definition at line 31 of file RingBuffer.cpp.

32  : mFormat{ format }
33  , mBufferSize{ std::max<size_t>(size, 64) }
35 {
36 }

References format.

◆ ~RingBuffer()

RingBuffer::~RingBuffer ( )

Definition at line 38 of file RingBuffer.cpp.

39 {
40 }

Member Function Documentation

◆ AvailForGet()

size_t RingBuffer::AvailForGet ( )

Definition at line 145 of file RingBuffer.cpp.

146 {
147  auto end = mEnd.load( std::memory_order_relaxed ); // get away with it here
148  auto start = mStart.load( std::memory_order_relaxed );
149  return Filled( start, end );
150 
151  // Writer might increase the available samples after return, but will
152  // never decrease them, so reader can safely assume this much at least
153 }

References Filled(), mEnd, and mStart.

Here is the call graph for this function:

◆ AvailForPut()

size_t RingBuffer::AvailForPut ( )

Definition at line 62 of file RingBuffer.cpp.

63 {
64  auto start = mStart.load( std::memory_order_relaxed );
65  auto end = mEnd.load( std::memory_order_relaxed );
66  return Free( start, end );
67 
68  // Reader might increase the available free space after return, but will
69  // never decrease it, so writer can safely assume this much at least
70 }

References Free(), mEnd, and mStart.

Here is the call graph for this function:

◆ Clear()

size_t RingBuffer::Clear ( sampleFormat  format,
size_t  samples 
)

Definition at line 112 of file RingBuffer.cpp.

113 {
114  auto start = mStart.load( std::memory_order_acquire );
115  auto end = mEnd.load( std::memory_order_relaxed );
116  samplesToClear = std::min( samplesToClear, Free( start, end ) );
117  size_t cleared = 0;
118  auto pos = end;
119 
120  while(samplesToClear) {
121  auto block = std::min( samplesToClear, mBufferSize - pos );
122 
123  ClearSamples(mBuffer.ptr(), format, pos, block);
124 
125  pos = (pos + block) % mBufferSize;
126  samplesToClear -= block;
127  cleared += block;
128  }
129 
130  // Atomically update the end pointer with release, so the nonatomic writes
131  // just done to the buffer don't get reordered after
132  mEnd.store(pos, std::memory_order_release);
133 
134  return cleared;
135 }

References ClearSamples(), format, Free(), mBuffer, mBufferSize, mEnd, min(), mStart, and SampleBuffer::ptr().

Here is the call graph for this function:

◆ Discard()

size_t RingBuffer::Discard ( size_t  samples)

Definition at line 186 of file RingBuffer.cpp.

187 {
188  auto end = mEnd.load( std::memory_order_relaxed ); // get away with it here
189  auto start = mStart.load( std::memory_order_relaxed );
190  samplesToDiscard = std::min( samplesToDiscard, Filled( start, end ) );
191 
192  // Communicate to writer that we have skipped some data, and that's all
193  mStart.store((start + samplesToDiscard) % mBufferSize,
194  std::memory_order_relaxed);
195 
196  return samplesToDiscard;
197 }

References Filled(), mBufferSize, mEnd, min(), and mStart.

Here is the call graph for this function:

◆ Filled()

size_t RingBuffer::Filled ( size_t  start,
size_t  end 
)
private

Definition at line 45 of file RingBuffer.cpp.

46 {
47  return (end + mBufferSize - start) % mBufferSize;
48 }

References mBufferSize.

Referenced by AvailForGet(), Discard(), Free(), and Get().

Here is the caller graph for this function:

◆ Free()

size_t RingBuffer::Free ( size_t  start,
size_t  end 
)
private

Definition at line 50 of file RingBuffer.cpp.

51 {
52  return std::max<size_t>(mBufferSize - Filled( start, end ), 4) - 4;
53 }

References Filled(), and mBufferSize.

Referenced by AvailForPut(), Clear(), and Put().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Get()

size_t RingBuffer::Get ( samplePtr  buffer,
sampleFormat  format,
size_t  samples 
)

Does not apply dithering.

Definition at line 155 of file RingBuffer.cpp.

157 {
158  // Must match the writer's release with acquire for well defined reads of
159  // the buffer
160  auto end = mEnd.load( std::memory_order_acquire );
161  auto start = mStart.load( std::memory_order_relaxed );
162  samplesToCopy = std::min( samplesToCopy, Filled( start, end ) );
163  auto dest = buffer;
164  size_t copied = 0;
165 
166  while(samplesToCopy) {
167  auto block = std::min( samplesToCopy, mBufferSize - start );
168 
170  dest, format,
171  block, DitherType::none);
172 
173  dest += block * SAMPLE_SIZE(format);
174  start = (start + block) % mBufferSize;
175  samplesToCopy -= block;
176  copied += block;
177  }
178 
179  // Communicate to writer that we have consumed some data,
180  // with nonrelaxed ordering
181  mStart.store( start, std::memory_order_release );
182 
183  return copied;
184 }

References CopySamples(), Filled(), format, mBuffer, mBufferSize, mEnd, mFormat, min(), mStart, none, SampleBuffer::ptr(), and SAMPLE_SIZE.

Here is the call graph for this function:

◆ Put()

size_t RingBuffer::Put ( constSamplePtr  buffer,
sampleFormat  format,
size_t  samples,
size_t  padding = 0 
)

Does not apply dithering.

Definition at line 72 of file RingBuffer.cpp.

74 {
75  auto start = mStart.load( std::memory_order_acquire );
76  auto end = mEnd.load( std::memory_order_relaxed );
77  const auto free = Free( start, end );
78  samplesToCopy = std::min( samplesToCopy, free );
79  padding = std::min( padding, free - samplesToCopy );
80  auto src = buffer;
81  size_t copied = 0;
82  auto pos = end;
83 
84  while ( samplesToCopy ) {
85  auto block = std::min( samplesToCopy, mBufferSize - pos );
86 
87  CopySamples(src, format,
89  block, DitherType::none);
90 
91  src += block * SAMPLE_SIZE(format);
92  pos = (pos + block) % mBufferSize;
93  samplesToCopy -= block;
94  copied += block;
95  }
96 
97  while ( padding ) {
98  const auto block = std::min( padding, mBufferSize - pos );
99  ClearSamples( mBuffer.ptr(), mFormat, pos, block );
100  pos = (pos + block) % mBufferSize;
101  padding -= block;
102  copied += block;
103  }
104 
105  // Atomically update the end pointer with release, so the nonatomic writes
106  // just done to the buffer don't get reordered after
107  mEnd.store(pos, std::memory_order_release);
108 
109  return copied;
110 }

References ClearSamples(), CopySamples(), format, Free(), mBuffer, mBufferSize, mEnd, mFormat, min(), mStart, none, SampleBuffer::ptr(), and SAMPLE_SIZE.

Here is the call graph for this function:

Member Data Documentation

◆ mBuffer

SampleBuffer RingBuffer::mBuffer
private

Definition at line 52 of file RingBuffer.h.

Referenced by Clear(), Get(), and Put().

◆ mBufferSize

const size_t RingBuffer::mBufferSize
private

Definition at line 49 of file RingBuffer.h.

Referenced by Clear(), Discard(), Filled(), Free(), Get(), and Put().

◆ mEnd

NonInterfering< std::atomic<size_t> > RingBuffer::mEnd { 0 }
private

Definition at line 47 of file RingBuffer.h.

Referenced by AvailForGet(), AvailForPut(), Clear(), Discard(), Get(), and Put().

◆ mFormat

sampleFormat RingBuffer::mFormat
private

Definition at line 51 of file RingBuffer.h.

Referenced by Get(), and Put().

◆ mStart

NonInterfering< std::atomic<size_t> > RingBuffer::mStart { 0 }
private

Definition at line 47 of file RingBuffer.h.

Referenced by AvailForGet(), AvailForPut(), Clear(), Discard(), Get(), and Put().


The documentation for this class was generated from the following files:
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
ClearSamples
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
Definition: SampleFormat.cpp:77
RingBuffer::mFormat
sampleFormat mFormat
Definition: RingBuffer.h:51
RingBuffer::mStart
NonInterfering< std::atomic< size_t > > mStart
Definition: RingBuffer.h:47
SAMPLE_SIZE
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:44
RingBuffer::Free
size_t Free(size_t start, size_t end)
Definition: RingBuffer.cpp:50
RingBuffer::Filled
size_t Filled(size_t start, size_t end)
Definition: RingBuffer.cpp:45
RingBuffer::mEnd
NonInterfering< std::atomic< size_t > > mEnd
Definition: RingBuffer.h:47
RingBuffer::mBuffer
SampleBuffer mBuffer
Definition: RingBuffer.h:52
CopySamples
void CopySamples(constSamplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, size_t len, DitherType ditherType, unsigned int srcStride, unsigned int dstStride)
Copy samples from any format to any other format; apply dithering only if narrowing the format.
Definition: SampleFormat.cpp:111
none
@ none
Definition: Dither.h:20
format
int format
Definition: ExportPCM.cpp:56
RingBuffer::mBufferSize
const size_t mBufferSize
Definition: RingBuffer.h:49
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
SampleBuffer::ptr
samplePtr ptr() const
Definition: SampleFormat.h:98