Overte C++ Documentation
AudioRingBuffer.h
1 //
2 // AudioRingBuffer.h
3 // libraries/audio/src
4 //
5 // Created by Stephen Birarda on 2/1/13.
6 // Copyright 2013 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_AudioRingBuffer_h
13 #define hifi_AudioRingBuffer_h
14 
15 #include "AudioConstants.h"
16 
17 #include <QtCore/QIODevice>
18 
19 #include <SharedUtil.h>
20 #include <NodeData.h>
21 
22 const int DEFAULT_RING_BUFFER_FRAME_CAPACITY = 10;
23 
24 template <class T>
25 class AudioRingBufferTemplate {
26  using Sample = T;
27  static const int SampleSize = sizeof(Sample);
28 
29 public:
30  AudioRingBufferTemplate(int numFrameSamples, int numFramesCapacity = DEFAULT_RING_BUFFER_FRAME_CAPACITY);
31  ~AudioRingBufferTemplate();
32 
33  // disallow copying
34  AudioRingBufferTemplate(const AudioRingBufferTemplate&) = delete;
35  AudioRingBufferTemplate(AudioRingBufferTemplate&&) = delete;
36  AudioRingBufferTemplate& operator=(const AudioRingBufferTemplate&) = delete;
37 
39  void clear();
40 
42  void reset();
43 
45  // FIXME: discards any data in the buffer
46  void resizeForFrameSize(int numFrameSamples);
47 
48  // Reading and writing to the buffer uses minimal shared data, such that
49  // in cases that avoid overwriting the buffer, a single producer/consumer
50  // may use this as a lock-free pipe (see audio-client/src/AudioClient.cpp).
51  // IMPORTANT: Avoid changes to the implementation that touch shared data unless you can
52  // maintain this behavior.
53 
56  int readSamples(Sample* destination, int maxSamples);
57 
61  int appendSamples(Sample* destination, int maxSamples, bool append = true);
62 
64  void skipSamples(int maxSamples) { shiftReadPosition(std::min(maxSamples, samplesAvailable())); }
65 
68  int writeSamples(const Sample* source, int maxSamples);
69 
73  int addSilentSamples(int maxSamples);
74 
77  int readData(char* destination, int maxSize);
78 
81  int appendData(char* destination, int maxSize);
82 
85  int writeData(const char* source, int maxSize);
86 
88  Sample& operator[](const int index) { return *shiftedPositionAccomodatingWrap(_nextOutput, index); }
89  const Sample& operator[] (const int index) const { return *shiftedPositionAccomodatingWrap(_nextOutput, index); }
90 
94  void shiftReadPosition(unsigned int numSamples) { _nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, numSamples); }
95 
96  int samplesAvailable() const;
97  int framesAvailable() const { return (_numFrameSamples == 0) ? 0 : samplesAvailable() / _numFrameSamples; }
98  float getNextOutputFrameLoudness() const { return getFrameLoudness(_nextOutput); }
99 
100 
101  int getNumFrameSamples() const { return _numFrameSamples; }
102  int getFrameCapacity() const { return _frameCapacity; }
103  int getSampleCapacity() const { return _sampleCapacity; }
105  int getOverflowCount() const { return _overflowCount; }
106 
107  class ConstIterator {
108  public:
109  ConstIterator() :
110  _bufferLength(0),
111  _bufferFirst(NULL),
112  _bufferLast(NULL),
113  _at(NULL) {}
114  ConstIterator(Sample* bufferFirst, int capacity, Sample* at) :
115  _bufferLength(capacity),
116  _bufferFirst(bufferFirst),
117  _bufferLast(bufferFirst + capacity - 1),
118  _at(at) {}
119  ConstIterator(const ConstIterator& rhs) = default;
120 
121  bool isNull() const { return _at == NULL; }
122 
123  bool operator==(const ConstIterator& rhs) { return _at == rhs._at; }
124  bool operator!=(const ConstIterator& rhs) { return _at != rhs._at; }
125  const Sample& operator*() { return *_at; }
126 
127  ConstIterator& operator=(const ConstIterator& rhs) {
128  _bufferLength = rhs._bufferLength;
129  _bufferFirst = rhs._bufferFirst;
130  _bufferLast = rhs._bufferLast;
131  _at = rhs._at;
132  return *this;
133  }
134  ConstIterator& operator++() {
135  _at = (_at == _bufferLast) ? _bufferFirst : _at + 1;
136  return *this;
137  }
138  ConstIterator operator++(int) {
139  ConstIterator tmp(*this);
140  ++(*this);
141  return tmp;
142  }
143  ConstIterator& operator--() {
144  _at = (_at == _bufferFirst) ? _bufferLast : _at - 1;
145  return *this;
146  }
147  ConstIterator operator--(int) {
148  ConstIterator tmp(*this);
149  --(*this);
150  return tmp;
151  }
152  const Sample& operator[] (int i) {
153  return *atShiftedBy(i);
154  }
155  ConstIterator operator+(int i) {
156  return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(i));
157  }
158  ConstIterator operator-(int i) {
159  return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(-i));
160  }
161 
162  void readSamples(Sample* dest, int numSamples) {
163  auto samplesToEnd = _bufferLast - _at + 1;
164 
165  if (samplesToEnd >= numSamples) {
166  memcpy(dest, _at, numSamples * SampleSize);
167  _at += numSamples;
168  } else {
169  auto samplesFromStart = numSamples - samplesToEnd;
170  memcpy(dest, _at, samplesToEnd * SampleSize);
171  memcpy(dest + samplesToEnd, _bufferFirst, samplesFromStart * SampleSize);
172 
173  _at = _bufferFirst + samplesFromStart;
174  }
175  }
176  void readSamplesWithFade(Sample* dest, int numSamples, float fade) {
177  Sample* at = _at;
178  for (int i = 0; i < numSamples; i++) {
179  *dest = (float)*at * fade;
180  ++dest;
181  at = (at == _bufferLast) ? _bufferFirst : at + 1;
182  }
183  }
184 
185 
186  private:
187  Sample* atShiftedBy(int i) {
188  i = (_at - _bufferFirst + i) % _bufferLength;
189  if (i < 0) {
190  i += _bufferLength;
191  }
192  return _bufferFirst + i;
193  }
194 
195  int _bufferLength;
196  Sample* _bufferFirst;
197  Sample* _bufferLast;
198  Sample* _at;
199  };
200 
201  ConstIterator nextOutput() const {
202  return ConstIterator(_buffer, _bufferLength, _nextOutput);
203  }
204  ConstIterator lastFrameWritten() const {
205  return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples;
206  }
207 
208  int writeSamples(ConstIterator source, int maxSamples);
209  int writeSamplesWithFade(ConstIterator source, int maxSamples, float fade);
210 
211  float getFrameLoudness(ConstIterator frameStart) const;
212 
213 protected:
214  Sample* shiftedPositionAccomodatingWrap(Sample* position, int numSamplesShift) const;
215  float getFrameLoudness(const Sample* frameStart) const;
216 
217  int _numFrameSamples;
218  int _frameCapacity;
219  int _sampleCapacity;
220  int _bufferLength; // actual _buffer length (_sampleCapacity + 1)
221  int _overflowCount{ 0 }; // times the ring buffer has overwritten data
222 
223  Sample* _nextOutput{ nullptr };
224  Sample* _endOfLastWrite{ nullptr };
225  Sample* _buffer{ nullptr };
226 };
227 
228 // expose explicit instantiations for scratch/mix buffers
229 using AudioRingBuffer = AudioRingBufferTemplate<int16_t>;
230 using AudioMixRingBuffer = AudioRingBufferTemplate<float>;
231 
232 #endif // hifi_AudioRingBuffer_h