mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:35:08 +02:00
add conformant explicit instantiation for AudioRingBuffers
This commit is contained in:
parent
5927c089ac
commit
75281099bd
2 changed files with 207 additions and 415 deletions
|
@ -26,8 +26,8 @@
|
|||
static const QString RING_BUFFER_OVERFLOW_DEBUG { "AudioRingBuffer::writeData has overflown the buffer. Overwriting old data." };
|
||||
static const QString DROPPED_SILENT_DEBUG { "AudioRingBuffer::addSilentSamples dropping silent samples to prevent overflow." };
|
||||
|
||||
template<>
|
||||
AudioRingBufferTemplate<int16_t>::AudioRingBufferTemplate(int numFrameSamples, int numFramesCapacity) :
|
||||
template <class T>
|
||||
AudioRingBufferTemplate<T>::AudioRingBufferTemplate(int numFrameSamples, int numFramesCapacity) :
|
||||
_numFrameSamples(numFrameSamples),
|
||||
_frameCapacity(numFramesCapacity),
|
||||
_sampleCapacity(numFrameSamples * numFramesCapacity),
|
||||
|
@ -44,25 +44,25 @@ AudioRingBufferTemplate<int16_t>::AudioRingBufferTemplate(int numFrameSamples, i
|
|||
static QString repeatedDroppedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG);
|
||||
}
|
||||
|
||||
template<>
|
||||
AudioRingBufferTemplate<int16_t>::~AudioRingBufferTemplate() {
|
||||
template <class T>
|
||||
AudioRingBufferTemplate<T>::~AudioRingBufferTemplate() {
|
||||
delete[] _buffer;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AudioRingBufferTemplate<int16_t>::clear() {
|
||||
template <class T>
|
||||
void AudioRingBufferTemplate<T>::clear() {
|
||||
_endOfLastWrite = _buffer;
|
||||
_nextOutput = _buffer;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AudioRingBufferTemplate<int16_t>::reset() {
|
||||
template <class T>
|
||||
void AudioRingBufferTemplate<T>::reset() {
|
||||
clear();
|
||||
_overflowCount = 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AudioRingBufferTemplate<int16_t>::resizeForFrameSize(int numFrameSamples) {
|
||||
template <class T>
|
||||
void AudioRingBufferTemplate<T>::resizeForFrameSize(int numFrameSamples) {
|
||||
delete[] _buffer;
|
||||
_numFrameSamples = numFrameSamples;
|
||||
_sampleCapacity = numFrameSamples * _frameCapacity;
|
||||
|
@ -78,255 +78,13 @@ void AudioRingBufferTemplate<int16_t>::resizeForFrameSize(int numFrameSamples) {
|
|||
reset();
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::readSamples(Sample* destination, int maxSamples) {
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::readSamples(Sample* destination, int maxSamples) {
|
||||
return readData((char*)destination, maxSamples * SampleSize) / SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::writeSamples(const Sample* source, int maxSamples) {
|
||||
return writeData((char*)source, maxSamples * SampleSize) / SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::readData(char *data, int maxSize) {
|
||||
// only copy up to the number of samples we have available
|
||||
int maxSamples = maxSize / SampleSize;
|
||||
int numReadSamples = std::min(maxSamples, samplesAvailable());
|
||||
|
||||
if (_nextOutput + numReadSamples > _buffer + _bufferLength) {
|
||||
// we're going to need to do two reads to get this data, it wraps around the edge
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _nextOutput;
|
||||
|
||||
// read to the end of the buffer
|
||||
memcpy(data, _nextOutput, numSamplesToEnd * SampleSize);
|
||||
|
||||
// read the rest from the beginning of the buffer
|
||||
memcpy(data + (numSamplesToEnd * SampleSize), _buffer, (numReadSamples - numSamplesToEnd) * SampleSize);
|
||||
} else {
|
||||
memcpy(data, _nextOutput, numReadSamples * SampleSize);
|
||||
}
|
||||
|
||||
shiftReadPosition(numReadSamples);
|
||||
|
||||
return numReadSamples * SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::writeData(const char* data, int maxSize) {
|
||||
// only copy up to the number of samples we have capacity for
|
||||
int maxSamples = maxSize / SampleSize;
|
||||
int numWriteSamples = std::min(maxSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
|
||||
if (numWriteSamples > samplesRoomFor) {
|
||||
// there's not enough room for this write. erase old data to make room for this new data
|
||||
int samplesToDelete = numWriteSamples - samplesRoomFor;
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||
_overflowCount++;
|
||||
|
||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
}
|
||||
|
||||
if (_endOfLastWrite + numWriteSamples > _buffer + _bufferLength) {
|
||||
// we're going to need to do two writes to set this data, it wraps around the edge
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _endOfLastWrite;
|
||||
|
||||
// write to the end of the buffer
|
||||
memcpy(_endOfLastWrite, data, numSamplesToEnd * SampleSize);
|
||||
|
||||
// write the rest to the beginning of the buffer
|
||||
memcpy(_buffer, data + (numSamplesToEnd * SampleSize), (numWriteSamples - numSamplesToEnd) * SampleSize);
|
||||
} else {
|
||||
memcpy(_endOfLastWrite, data, numWriteSamples * SampleSize);
|
||||
}
|
||||
|
||||
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, numWriteSamples);
|
||||
|
||||
return numWriteSamples * SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::samplesAvailable() const {
|
||||
if (!_endOfLastWrite) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sampleDifference = _endOfLastWrite - _nextOutput;
|
||||
if (sampleDifference < 0) {
|
||||
sampleDifference += _bufferLength;
|
||||
}
|
||||
return sampleDifference;
|
||||
}
|
||||
|
||||
template<>
|
||||
int16_t* AudioRingBufferTemplate<int16_t>::shiftedPositionAccomodatingWrap(Sample* position, int numSamplesShift) const {
|
||||
// NOTE: It is possible to shift out-of-bounds if (|numSamplesShift| > 2 * _bufferLength), but this should not occur
|
||||
if (numSamplesShift > 0 && position + numSamplesShift >= _buffer + _bufferLength) {
|
||||
// this shift will wrap the position around to the beginning of the ring
|
||||
return position + numSamplesShift - _bufferLength;
|
||||
} else if (numSamplesShift < 0 && position + numSamplesShift < _buffer) {
|
||||
// this shift will go around to the end of the ring
|
||||
return position + numSamplesShift + _bufferLength;
|
||||
} else {
|
||||
return position + numSamplesShift;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::addSilentSamples(int silentSamples) {
|
||||
// NOTE: This implementation is nearly identical to writeData save for s/memcpy/memset, refer to comments there
|
||||
int numWriteSamples = std::min(silentSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
|
||||
if (numWriteSamples > samplesRoomFor) {
|
||||
numWriteSamples = samplesRoomFor;
|
||||
|
||||
qCDebug(audio) << qPrintable(DROPPED_SILENT_DEBUG);
|
||||
}
|
||||
|
||||
if (_endOfLastWrite + numWriteSamples > _buffer + _bufferLength) {
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _endOfLastWrite;
|
||||
memset(_endOfLastWrite, 0, numSamplesToEnd * SampleSize);
|
||||
memset(_buffer, 0, (numWriteSamples - numSamplesToEnd) * SampleSize);
|
||||
} else {
|
||||
memset(_endOfLastWrite, 0, numWriteSamples * SampleSize);
|
||||
}
|
||||
|
||||
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, numWriteSamples);
|
||||
|
||||
return numWriteSamples;
|
||||
}
|
||||
|
||||
template<>
|
||||
float AudioRingBufferTemplate<int16_t>::getFrameLoudness(const Sample* frameStart) const {
|
||||
// FIXME: This is a bad measure of loudness - normal estimation uses sqrt(sum(x*x))
|
||||
float loudness = 0.0f;
|
||||
const Sample* sampleAt = frameStart;
|
||||
const Sample* bufferLastAt = _buffer + _bufferLength - 1;
|
||||
|
||||
for (int i = 0; i < _numFrameSamples; ++i) {
|
||||
loudness += (float) std::abs(*sampleAt);
|
||||
// wrap if necessary
|
||||
sampleAt = sampleAt == bufferLastAt ? _buffer : sampleAt + 1;
|
||||
}
|
||||
loudness /= _numFrameSamples;
|
||||
loudness /= AudioConstants::MAX_SAMPLE_VALUE;
|
||||
|
||||
return loudness;
|
||||
}
|
||||
|
||||
template<>
|
||||
float AudioRingBufferTemplate<int16_t>::getFrameLoudness(ConstIterator frameStart) const {
|
||||
if (frameStart.isNull()) {
|
||||
return 0.0f;
|
||||
}
|
||||
return getFrameLoudness(&(*frameStart));
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::writeSamples(ConstIterator source, int maxSamples) {
|
||||
int samplesToCopy = std::min(maxSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
if (samplesToCopy > samplesRoomFor) {
|
||||
// there's not enough room for this write. erase old data to make room for this new data
|
||||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||
_overflowCount++;
|
||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
}
|
||||
|
||||
Sample* bufferLast = _buffer + _bufferLength - 1;
|
||||
for (int i = 0; i < samplesToCopy; i++) {
|
||||
*_endOfLastWrite = *source;
|
||||
_endOfLastWrite = (_endOfLastWrite == bufferLast) ? _buffer : _endOfLastWrite + 1;
|
||||
++source;
|
||||
}
|
||||
|
||||
return samplesToCopy;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<int16_t>::writeSamplesWithFade(ConstIterator source, int maxSamples, float fade) {
|
||||
int samplesToCopy = std::min(maxSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
if (samplesToCopy > samplesRoomFor) {
|
||||
// there's not enough room for this write. erase old data to make room for this new data
|
||||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||
_overflowCount++;
|
||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
}
|
||||
|
||||
Sample* bufferLast = _buffer + _bufferLength - 1;
|
||||
for (int i = 0; i < samplesToCopy; i++) {
|
||||
*_endOfLastWrite = (Sample)((float)(*source) * fade);
|
||||
_endOfLastWrite = (_endOfLastWrite == bufferLast) ? _buffer : _endOfLastWrite + 1;
|
||||
++source;
|
||||
}
|
||||
|
||||
return samplesToCopy;
|
||||
}
|
||||
|
||||
template<>
|
||||
AudioRingBufferTemplate<float>::AudioRingBufferTemplate(int numFrameSamples, int numFramesCapacity) :
|
||||
_numFrameSamples(numFrameSamples),
|
||||
_frameCapacity(numFramesCapacity),
|
||||
_sampleCapacity(numFrameSamples * numFramesCapacity),
|
||||
_bufferLength(numFrameSamples * (numFramesCapacity + 1))
|
||||
{
|
||||
if (numFrameSamples) {
|
||||
_buffer = new Sample[_bufferLength];
|
||||
memset(_buffer, 0, _bufferLength * SampleSize);
|
||||
_nextOutput = _buffer;
|
||||
_endOfLastWrite = _buffer;
|
||||
}
|
||||
|
||||
static QString repeatedOverflowMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
static QString repeatedDroppedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG);
|
||||
}
|
||||
|
||||
template<>
|
||||
AudioRingBufferTemplate<float>::~AudioRingBufferTemplate() {
|
||||
delete[] _buffer;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AudioRingBufferTemplate<float>::clear() {
|
||||
_endOfLastWrite = _buffer;
|
||||
_nextOutput = _buffer;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AudioRingBufferTemplate<float>::reset() {
|
||||
clear();
|
||||
_overflowCount = 0;
|
||||
}
|
||||
|
||||
template<>
|
||||
void AudioRingBufferTemplate<float>::resizeForFrameSize(int numFrameSamples) {
|
||||
delete[] _buffer;
|
||||
_numFrameSamples = numFrameSamples;
|
||||
_sampleCapacity = numFrameSamples * _frameCapacity;
|
||||
_bufferLength = numFrameSamples * (_frameCapacity + 1);
|
||||
|
||||
if (numFrameSamples) {
|
||||
_buffer = new Sample[_bufferLength];
|
||||
memset(_buffer, 0, _bufferLength * SampleSize);
|
||||
} else {
|
||||
_buffer = nullptr;
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<float>::readSamples(Sample* destination, int maxSamples) {
|
||||
return readData((char*)destination, maxSamples * SampleSize) / SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<float>::appendSamples(Sample* destination, int maxSamples, bool append) {
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::appendSamples(Sample* destination, int maxSamples, bool append) {
|
||||
if (append) {
|
||||
return appendData((char*)destination, maxSamples * SampleSize) / SampleSize;
|
||||
} else {
|
||||
|
@ -334,13 +92,13 @@ int AudioRingBufferTemplate<float>::appendSamples(Sample* destination, int maxSa
|
|||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<float>::writeSamples(const Sample* source, int maxSamples) {
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::writeSamples(const Sample* source, int maxSamples) {
|
||||
return writeData((char*)source, maxSamples * SampleSize) / SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<float>::readData(char *data, int maxSize) {
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::readData(char *data, int maxSize) {
|
||||
// only copy up to the number of samples we have available
|
||||
int maxSamples = maxSize / SampleSize;
|
||||
int numReadSamples = std::min(maxSamples, samplesAvailable());
|
||||
|
@ -363,8 +121,8 @@ int AudioRingBufferTemplate<float>::readData(char *data, int maxSize) {
|
|||
return numReadSamples * SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<float>::appendData(char *data, int maxSize) {
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::appendData(char *data, int maxSize) {
|
||||
// only copy up to the number of samples we have available
|
||||
int maxSamples = maxSize / SampleSize;
|
||||
int numReadSamples = std::min(maxSamples, samplesAvailable());
|
||||
|
@ -396,8 +154,8 @@ int AudioRingBufferTemplate<float>::appendData(char *data, int maxSize) {
|
|||
return numReadSamples * SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<float>::writeData(const char* data, int maxSize) {
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::writeData(const char* data, int maxSize) {
|
||||
// only copy up to the number of samples we have capacity for
|
||||
int maxSamples = maxSize / SampleSize;
|
||||
int numWriteSamples = std::min(maxSamples, _sampleCapacity);
|
||||
|
@ -430,8 +188,8 @@ int AudioRingBufferTemplate<float>::writeData(const char* data, int maxSize) {
|
|||
return numWriteSamples * SampleSize;
|
||||
}
|
||||
|
||||
template<>
|
||||
int AudioRingBufferTemplate<float>::samplesAvailable() const {
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::samplesAvailable() const {
|
||||
if (!_endOfLastWrite) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -443,8 +201,8 @@ int AudioRingBufferTemplate<float>::samplesAvailable() const {
|
|||
return sampleDifference;
|
||||
}
|
||||
|
||||
template<>
|
||||
float* AudioRingBufferTemplate<float>::shiftedPositionAccomodatingWrap(Sample* position, int numSamplesShift) const {
|
||||
template <class T>
|
||||
typename AudioRingBufferTemplate<T>::Sample* AudioRingBufferTemplate<T>::shiftedPositionAccomodatingWrap(Sample* position, int numSamplesShift) const {
|
||||
// NOTE: It is possible to shift out-of-bounds if (|numSamplesShift| > 2 * _bufferLength), but this should not occur
|
||||
if (numSamplesShift > 0 && position + numSamplesShift >= _buffer + _bufferLength) {
|
||||
// this shift will wrap the position around to the beginning of the ring
|
||||
|
@ -455,4 +213,103 @@ float* AudioRingBufferTemplate<float>::shiftedPositionAccomodatingWrap(Sample* p
|
|||
} else {
|
||||
return position + numSamplesShift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::addSilentSamples(int silentSamples) {
|
||||
// NOTE: This implementation is nearly identical to writeData save for s/memcpy/memset, refer to comments there
|
||||
int numWriteSamples = std::min(silentSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
|
||||
if (numWriteSamples > samplesRoomFor) {
|
||||
numWriteSamples = samplesRoomFor;
|
||||
|
||||
qCDebug(audio) << qPrintable(DROPPED_SILENT_DEBUG);
|
||||
}
|
||||
|
||||
if (_endOfLastWrite + numWriteSamples > _buffer + _bufferLength) {
|
||||
int numSamplesToEnd = (_buffer + _bufferLength) - _endOfLastWrite;
|
||||
memset(_endOfLastWrite, 0, numSamplesToEnd * SampleSize);
|
||||
memset(_buffer, 0, (numWriteSamples - numSamplesToEnd) * SampleSize);
|
||||
} else {
|
||||
memset(_endOfLastWrite, 0, numWriteSamples * SampleSize);
|
||||
}
|
||||
|
||||
_endOfLastWrite = shiftedPositionAccomodatingWrap(_endOfLastWrite, numWriteSamples);
|
||||
|
||||
return numWriteSamples;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
float AudioRingBufferTemplate<T>::getFrameLoudness(const Sample* frameStart) const {
|
||||
// FIXME: This is a bad measure of loudness - normal estimation uses sqrt(sum(x*x))
|
||||
float loudness = 0.0f;
|
||||
const Sample* sampleAt = frameStart;
|
||||
const Sample* bufferLastAt = _buffer + _bufferLength - 1;
|
||||
|
||||
for (int i = 0; i < _numFrameSamples; ++i) {
|
||||
loudness += (float) std::abs(*sampleAt);
|
||||
// wrap if necessary
|
||||
sampleAt = sampleAt == bufferLastAt ? _buffer : sampleAt + 1;
|
||||
}
|
||||
loudness /= _numFrameSamples;
|
||||
loudness /= AudioConstants::MAX_SAMPLE_VALUE;
|
||||
|
||||
return loudness;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
float AudioRingBufferTemplate<T>::getFrameLoudness(ConstIterator frameStart) const {
|
||||
if (frameStart.isNull()) {
|
||||
return 0.0f;
|
||||
}
|
||||
return getFrameLoudness(&(*frameStart));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::writeSamples(ConstIterator source, int maxSamples) {
|
||||
int samplesToCopy = std::min(maxSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
if (samplesToCopy > samplesRoomFor) {
|
||||
// there's not enough room for this write. erase old data to make room for this new data
|
||||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||
_overflowCount++;
|
||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
}
|
||||
|
||||
Sample* bufferLast = _buffer + _bufferLength - 1;
|
||||
for (int i = 0; i < samplesToCopy; i++) {
|
||||
*_endOfLastWrite = *source;
|
||||
_endOfLastWrite = (_endOfLastWrite == bufferLast) ? _buffer : _endOfLastWrite + 1;
|
||||
++source;
|
||||
}
|
||||
|
||||
return samplesToCopy;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int AudioRingBufferTemplate<T>::writeSamplesWithFade(ConstIterator source, int maxSamples, float fade) {
|
||||
int samplesToCopy = std::min(maxSamples, _sampleCapacity);
|
||||
int samplesRoomFor = _sampleCapacity - samplesAvailable();
|
||||
if (samplesToCopy > samplesRoomFor) {
|
||||
// there's not enough room for this write. erase old data to make room for this new data
|
||||
int samplesToDelete = samplesToCopy - samplesRoomFor;
|
||||
_nextOutput = shiftedPositionAccomodatingWrap(_nextOutput, samplesToDelete);
|
||||
_overflowCount++;
|
||||
qCDebug(audio) << qPrintable(RING_BUFFER_OVERFLOW_DEBUG);
|
||||
}
|
||||
|
||||
Sample* bufferLast = _buffer + _bufferLength - 1;
|
||||
for (int i = 0; i < samplesToCopy; i++) {
|
||||
*_endOfLastWrite = (Sample)((float)(*source) * fade);
|
||||
_endOfLastWrite = (_endOfLastWrite == bufferLast) ? _buffer : _endOfLastWrite + 1;
|
||||
++source;
|
||||
}
|
||||
|
||||
return samplesToCopy;
|
||||
}
|
||||
|
||||
// explicit instantiations for scratch/mix buffers
|
||||
template class AudioRingBufferTemplate<int16_t>;
|
||||
template class AudioRingBufferTemplate<float>;
|
||||
|
|
|
@ -100,8 +100,16 @@ public:
|
|||
|
||||
class ConstIterator {
|
||||
public:
|
||||
ConstIterator();
|
||||
ConstIterator(Sample* bufferFirst, int capacity, Sample* at);
|
||||
ConstIterator() :
|
||||
_bufferLength(0),
|
||||
_bufferFirst(NULL),
|
||||
_bufferLast(NULL),
|
||||
_at(NULL) {}
|
||||
ConstIterator(Sample* bufferFirst, int capacity, Sample* at) :
|
||||
_bufferLength(capacity),
|
||||
_bufferFirst(bufferFirst),
|
||||
_bufferLast(bufferFirst + capacity - 1),
|
||||
_at(at) {}
|
||||
ConstIterator(const ConstIterator& rhs) = default;
|
||||
|
||||
bool isNull() const { return _at == NULL; }
|
||||
|
@ -110,22 +118,73 @@ public:
|
|||
bool operator!=(const ConstIterator& rhs) { return _at != rhs._at; }
|
||||
const Sample& operator*() { return *_at; }
|
||||
|
||||
ConstIterator& operator=(const ConstIterator& rhs);
|
||||
ConstIterator& operator++();
|
||||
ConstIterator operator++(int);
|
||||
ConstIterator& operator--();
|
||||
ConstIterator operator--(int);
|
||||
const Sample& operator[] (int i);
|
||||
ConstIterator operator+(int i);
|
||||
ConstIterator operator-(int i);
|
||||
ConstIterator& operator=(const ConstIterator& rhs) {
|
||||
_bufferLength = rhs._bufferLength;
|
||||
_bufferFirst = rhs._bufferFirst;
|
||||
_bufferLast = rhs._bufferLast;
|
||||
_at = rhs._at;
|
||||
return *this;
|
||||
}
|
||||
ConstIterator& operator++() {
|
||||
_at = (_at == _bufferLast) ? _bufferFirst : _at + 1;
|
||||
return *this;
|
||||
}
|
||||
ConstIterator operator++(int) {
|
||||
ConstIterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
ConstIterator& operator--() {
|
||||
_at = (_at == _bufferFirst) ? _bufferLast : _at - 1;
|
||||
return *this;
|
||||
}
|
||||
ConstIterator operator--(int) {
|
||||
ConstIterator tmp(*this);
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
const Sample& operator[] (int i) {
|
||||
return *atShiftedBy(i);
|
||||
}
|
||||
ConstIterator operator+(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(i));
|
||||
}
|
||||
ConstIterator operator-(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(-i));
|
||||
}
|
||||
|
||||
void readSamples(Sample* dest, int numSamples) {
|
||||
auto samplesToEnd = _bufferLast - _at + 1;
|
||||
|
||||
if (samplesToEnd >= numSamples) {
|
||||
memcpy(dest, _at, numSamples * SampleSize);
|
||||
_at += numSamples;
|
||||
} else {
|
||||
auto samplesFromStart = numSamples - samplesToEnd;
|
||||
memcpy(dest, _at, samplesToEnd * SampleSize);
|
||||
memcpy(dest + samplesToEnd, _bufferFirst, samplesFromStart * SampleSize);
|
||||
|
||||
_at = _bufferFirst + samplesFromStart;
|
||||
}
|
||||
}
|
||||
void readSamplesWithFade(Sample* dest, int numSamples, float fade) {
|
||||
Sample* at = _at;
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
*dest = (float)*at * fade;
|
||||
++dest;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void readSamples(Sample* dest, int numSamples);
|
||||
void readSamplesWithFade(Sample* dest, int numSamples, float fade);
|
||||
void readSamplesWithUpmix(Sample* dest, int numSamples, int numExtraChannels);
|
||||
void readSamplesWithDownmix(Sample* dest, int numSamples);
|
||||
|
||||
private:
|
||||
Sample* atShiftedBy(int i);
|
||||
Sample* atShiftedBy(int i) {
|
||||
i = (_at - _bufferFirst + i) % _bufferLength;
|
||||
if (i < 0) {
|
||||
i += _bufferLength;
|
||||
}
|
||||
return _bufferFirst + i;
|
||||
}
|
||||
|
||||
int _bufferLength;
|
||||
Sample* _bufferFirst;
|
||||
|
@ -133,8 +192,12 @@ public:
|
|||
Sample* _at;
|
||||
};
|
||||
|
||||
ConstIterator nextOutput() const;
|
||||
ConstIterator lastFrameWritten() const;
|
||||
ConstIterator nextOutput() const {
|
||||
return ConstIterator(_buffer, _bufferLength, _nextOutput);
|
||||
}
|
||||
ConstIterator lastFrameWritten() const {
|
||||
return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples;
|
||||
}
|
||||
|
||||
int writeSamples(ConstIterator source, int maxSamples);
|
||||
int writeSamplesWithFade(ConstIterator source, int maxSamples, float fade);
|
||||
|
@ -156,136 +219,8 @@ protected:
|
|||
Sample* _buffer{ nullptr };
|
||||
};
|
||||
|
||||
// expose explicit instantiations for scratch/mix buffers
|
||||
using AudioRingBuffer = AudioRingBufferTemplate<int16_t>;
|
||||
using AudioRingMixBuffer = AudioRingBufferTemplate<float>;
|
||||
|
||||
// inline the iterator:
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator::ConstIterator() :
|
||||
_bufferLength(0),
|
||||
_bufferFirst(NULL),
|
||||
_bufferLast(NULL),
|
||||
_at(NULL) {}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator::ConstIterator(Sample* bufferFirst, int capacity, Sample* at) :
|
||||
_bufferLength(capacity),
|
||||
_bufferFirst(bufferFirst),
|
||||
_bufferLast(bufferFirst + capacity - 1),
|
||||
_at(at) {}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator& AudioRingBufferTemplate<int16_t>::ConstIterator::operator=(const ConstIterator& rhs) {
|
||||
_bufferLength = rhs._bufferLength;
|
||||
_bufferFirst = rhs._bufferFirst;
|
||||
_bufferLast = rhs._bufferLast;
|
||||
_at = rhs._at;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator& AudioRingBufferTemplate<int16_t>::ConstIterator::operator++() {
|
||||
_at = (_at == _bufferLast) ? _bufferFirst : _at + 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator AudioRingBufferTemplate<int16_t>::ConstIterator::operator++(int) {
|
||||
ConstIterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator& AudioRingBufferTemplate<int16_t>::ConstIterator::operator--() {
|
||||
_at = (_at == _bufferFirst) ? _bufferLast : _at - 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator AudioRingBufferTemplate<int16_t>::ConstIterator::operator--(int) {
|
||||
ConstIterator tmp(*this);
|
||||
--(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<> inline const int16_t& AudioRingBufferTemplate<int16_t>::ConstIterator::operator[] (int i) {
|
||||
return *atShiftedBy(i);
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator AudioRingBufferTemplate<int16_t>::ConstIterator::operator+(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(i));
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator AudioRingBufferTemplate<int16_t>::ConstIterator::operator-(int i) {
|
||||
return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(-i));
|
||||
}
|
||||
|
||||
template<> inline int16_t* AudioRingBufferTemplate<int16_t>::ConstIterator::atShiftedBy(int i) {
|
||||
i = (_at - _bufferFirst + i) % _bufferLength;
|
||||
if (i < 0) {
|
||||
i += _bufferLength;
|
||||
}
|
||||
return _bufferFirst + i;
|
||||
}
|
||||
|
||||
template<> inline void AudioRingBufferTemplate<int16_t>::ConstIterator::readSamples(Sample* dest, int numSamples) {
|
||||
auto samplesToEnd = _bufferLast - _at + 1;
|
||||
|
||||
if (samplesToEnd >= numSamples) {
|
||||
memcpy(dest, _at, numSamples * SampleSize);
|
||||
_at += numSamples;
|
||||
} else {
|
||||
auto samplesFromStart = numSamples - samplesToEnd;
|
||||
memcpy(dest, _at, samplesToEnd * SampleSize);
|
||||
memcpy(dest + samplesToEnd, _bufferFirst, samplesFromStart * SampleSize);
|
||||
|
||||
_at = _bufferFirst + samplesFromStart;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void AudioRingBufferTemplate<int16_t>::ConstIterator::readSamplesWithFade(Sample* dest, int numSamples, float fade) {
|
||||
Sample* at = _at;
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
*dest = (float)*at * fade;
|
||||
++dest;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void AudioRingBufferTemplate<int16_t>::ConstIterator::readSamplesWithUpmix(Sample* dest, int numSamples, int numExtraChannels) {
|
||||
Sample* at = _at;
|
||||
for (int i = 0; i < numSamples/2; i++) {
|
||||
|
||||
// read 2 samples
|
||||
Sample left = *at;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
Sample right = *at;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
|
||||
// write 2 + N samples
|
||||
*dest++ = left;
|
||||
*dest++ = right;
|
||||
for (int n = 0; n < numExtraChannels; n++) {
|
||||
*dest++ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void AudioRingBufferTemplate<int16_t>::ConstIterator::readSamplesWithDownmix(Sample* dest, int numSamples) {
|
||||
Sample* at = _at;
|
||||
for (int i = 0; i < numSamples/2; i++) {
|
||||
|
||||
// read 2 samples
|
||||
Sample left = *at;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
Sample right = *at;
|
||||
at = (at == _bufferLast) ? _bufferFirst : at + 1;
|
||||
|
||||
// write 1 sample
|
||||
*dest++ = (Sample)((left + right) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator AudioRingBufferTemplate<int16_t>::nextOutput() const {
|
||||
return ConstIterator(_buffer, _bufferLength, _nextOutput);
|
||||
}
|
||||
|
||||
template<> inline AudioRingBufferTemplate<int16_t>::ConstIterator AudioRingBufferTemplate<int16_t>::lastFrameWritten() const {
|
||||
return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples;
|
||||
}
|
||||
|
||||
#endif // hifi_AudioRingBuffer_h
|
||||
|
|
Loading…
Reference in a new issue