diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index c52d8f1447..ab0948e328 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -26,6 +26,7 @@ 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::AudioRingBufferTemplate(int numFrameSamples, int numFramesCapacity) : _numFrameSamples(numFrameSamples), _frameCapacity(numFramesCapacity), @@ -41,22 +42,26 @@ AudioRingBufferTemplate::AudioRingBufferTemplate(int numFrameSamples, i static QString repeatedOverflowMessage = LogHandler::getInstance().addRepeatedMessageRegex(RING_BUFFER_OVERFLOW_DEBUG); static QString repeatedDroppedMessage = LogHandler::getInstance().addRepeatedMessageRegex(DROPPED_SILENT_DEBUG); -}; +} +template<> AudioRingBufferTemplate::~AudioRingBufferTemplate() { delete[] _buffer; } +template<> void AudioRingBufferTemplate::clear() { _endOfLastWrite = _buffer; _nextOutput = _buffer; } +template<> void AudioRingBufferTemplate::reset() { clear(); _overflowCount = 0; } +template<> void AudioRingBufferTemplate::resizeForFrameSize(int numFrameSamples) { delete[] _buffer; _numFrameSamples = numFrameSamples; @@ -73,14 +78,17 @@ void AudioRingBufferTemplate::resizeForFrameSize(int numFrameSamples) { reset(); } +template<> int AudioRingBufferTemplate::readSamples(Sample* destination, int maxSamples) { return readData((char*)destination, maxSamples * SampleSize) / SampleSize; } +template<> int AudioRingBufferTemplate::writeSamples(const Sample* source, int maxSamples) { return writeData((char*)source, maxSamples * SampleSize) / SampleSize; } +template<> int AudioRingBufferTemplate::readData(char *data, int maxSize) { // only copy up to the number of samples we have available int maxSamples = maxSize / SampleSize; @@ -104,6 +112,7 @@ int AudioRingBufferTemplate::readData(char *data, int maxSize) { return numReadSamples * SampleSize; } +template<> int AudioRingBufferTemplate::writeData(const char* data, int maxSize) { // only copy up to the number of samples we have capacity for int maxSamples = maxSize / SampleSize; @@ -137,6 +146,7 @@ int AudioRingBufferTemplate::writeData(const char* data, int maxSize) { return numWriteSamples * SampleSize; } +template<> int AudioRingBufferTemplate::samplesAvailable() const { if (!_endOfLastWrite) { return 0; @@ -149,6 +159,7 @@ int AudioRingBufferTemplate::samplesAvailable() const { return sampleDifference; } +template<> int16_t* AudioRingBufferTemplate::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) { @@ -162,6 +173,7 @@ int16_t* AudioRingBufferTemplate::shiftedPositionAccomodatingWrap(Sampl } } +template<> int AudioRingBufferTemplate::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); @@ -186,6 +198,7 @@ int AudioRingBufferTemplate::addSilentSamples(int silentSamples) { return numWriteSamples; } +template<> float AudioRingBufferTemplate::getFrameLoudness(const Sample* frameStart) const { // FIXME: This is a bad measure of loudness - normal estimation uses sqrt(sum(x*x)) float loudness = 0.0f; @@ -203,6 +216,7 @@ float AudioRingBufferTemplate::getFrameLoudness(const Sample* frameStar return loudness; } +template<> float AudioRingBufferTemplate::getFrameLoudness(ConstIterator frameStart) const { if (frameStart.isNull()) { return 0.0f; @@ -210,6 +224,7 @@ float AudioRingBufferTemplate::getFrameLoudness(ConstIterator frameStar return getFrameLoudness(&(*frameStart)); } +template<> int AudioRingBufferTemplate::writeSamples(ConstIterator source, int maxSamples) { int samplesToCopy = std::min(maxSamples, _sampleCapacity); int samplesRoomFor = _sampleCapacity - samplesAvailable(); @@ -231,6 +246,7 @@ int AudioRingBufferTemplate::writeSamples(ConstIterator source, int max return samplesToCopy; } +template<> int AudioRingBufferTemplate::writeSamplesWithFade(ConstIterator source, int maxSamples, float fade) { int samplesToCopy = std::min(maxSamples, _sampleCapacity); int samplesRoomFor = _sampleCapacity - samplesAvailable(); @@ -251,3 +267,192 @@ int AudioRingBufferTemplate::writeSamplesWithFade(ConstIterator source, return samplesToCopy; } + +template<> +AudioRingBufferTemplate::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::~AudioRingBufferTemplate() { + delete[] _buffer; +} + +template<> +void AudioRingBufferTemplate::clear() { + _endOfLastWrite = _buffer; + _nextOutput = _buffer; +} + +template<> +void AudioRingBufferTemplate::reset() { + clear(); + _overflowCount = 0; +} + +template<> +void AudioRingBufferTemplate::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::readSamples(Sample* destination, int maxSamples) { + return readData((char*)destination, maxSamples * SampleSize) / SampleSize; +} + +template<> +int AudioRingBufferTemplate::appendSamples(Sample* destination, int maxSamples, bool append) { + if (append) { + return appendData((char*)destination, maxSamples * SampleSize) / SampleSize; + } else { + return readData((char*)destination, maxSamples * SampleSize) / SampleSize; + } +} + +template<> +int AudioRingBufferTemplate::writeSamples(const Sample* source, int maxSamples) { + return writeData((char*)source, maxSamples * SampleSize) / SampleSize; +} + +template<> +int AudioRingBufferTemplate::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::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()); + + Sample* dest = reinterpret_cast(data); + Sample* output = _nextOutput; + 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 + for (int i = 0; i < numSamplesToEnd; i++) { + *dest++ = *output++; + } + + // read the rest from the beginning of the buffer + output = _buffer; + for (int i = 0; i < (numReadSamples - numSamplesToEnd); i++) { + *dest++ = *output++; + } + } else { + for (int i = 0; i < numReadSamples; i++) { + *dest++ = *output++; + } + } + + shiftReadPosition(numReadSamples); + + return numReadSamples * SampleSize; +} + +template<> +int AudioRingBufferTemplate::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::samplesAvailable() const { + if (!_endOfLastWrite) { + return 0; + } + + int sampleDifference = _endOfLastWrite - _nextOutput; + if (sampleDifference < 0) { + sampleDifference += _bufferLength; + } + return sampleDifference; +} + +template<> +float* AudioRingBufferTemplate::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; + } +} \ No newline at end of file diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index b1f65b8a8d..92c6dcc336 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -24,7 +24,7 @@ const int DEFAULT_RING_BUFFER_FRAME_CAPACITY = 10; template class AudioRingBufferTemplate { using Sample = T; - static size_t SampleSize = sizeof(Sample); + static const int SampleSize = sizeof(Sample); public: AudioRingBufferTemplate(int numFrameSamples, int numFramesCapacity = DEFAULT_RING_BUFFER_FRAME_CAPACITY); @@ -49,6 +49,14 @@ public: /// Returns number of read samples int readSamples(Sample* destination, int maxSamples); + /// Append up to maxSamples into destination (will only read up to samplesAvailable()) + /// If append == false, behaves as readSamples + /// Returns number of appended samples + int appendSamples(Sample* destination, int maxSamples, bool append = true); + + /// Skip up to maxSamples (will only skip up to samplesAvailable()) + void skipSamples(int maxSamples) { shiftReadPosition(std::min(maxSamples, samplesAvailable())); } + /// Write up to maxSamples from source (will only write up to sample capacity) /// Returns number of written samples int writeSamples(const Sample* source, int maxSamples); @@ -62,6 +70,10 @@ public: /// Returns number of read bytes int readData(char* destination, int maxSize); + /// Append up to maxSize into destination + /// Returns number of read bytes + int appendData(char* destination, int maxSize); + /// Write up to maxSize from source /// Returns number of written bytes int writeData(const char* source, int maxSize); @@ -148,19 +160,19 @@ using AudioRingBuffer = AudioRingBufferTemplate; using AudioRingMixBuffer = AudioRingBufferTemplate; // inline the iterator: -inline AudioRingBufferTemplate::ConstIterator::ConstIterator() : +template<> inline AudioRingBufferTemplate::ConstIterator::ConstIterator() : _bufferLength(0), _bufferFirst(NULL), _bufferLast(NULL), _at(NULL) {} -inline AudioRingBufferTemplate::ConstIterator::ConstIterator(Sample* bufferFirst, int capacity, Sample* at) : +template<> inline AudioRingBufferTemplate::ConstIterator::ConstIterator(Sample* bufferFirst, int capacity, Sample* at) : _bufferLength(capacity), _bufferFirst(bufferFirst), _bufferLast(bufferFirst + capacity - 1), _at(at) {} -inline AudioRingBufferTemplate::ConstIterator& AudioRingBufferTemplate::ConstIterator::operator=(const ConstIterator& rhs) { +template<> inline AudioRingBufferTemplate::ConstIterator& AudioRingBufferTemplate::ConstIterator::operator=(const ConstIterator& rhs) { _bufferLength = rhs._bufferLength; _bufferFirst = rhs._bufferFirst; _bufferLast = rhs._bufferLast; @@ -168,41 +180,41 @@ inline AudioRingBufferTemplate::ConstIterator& AudioRingBufferTemplate< return *this; } -inline AudioRingBufferTemplate::ConstIterator& AudioRingBufferTemplate::ConstIterator::operator++() { +template<> inline AudioRingBufferTemplate::ConstIterator& AudioRingBufferTemplate::ConstIterator::operator++() { _at = (_at == _bufferLast) ? _bufferFirst : _at + 1; return *this; } -inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator++(int) { +template<> inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator++(int) { ConstIterator tmp(*this); ++(*this); return tmp; } -inline AudioRingBufferTemplate::ConstIterator& AudioRingBufferTemplate::ConstIterator::operator--() { +template<> inline AudioRingBufferTemplate::ConstIterator& AudioRingBufferTemplate::ConstIterator::operator--() { _at = (_at == _bufferFirst) ? _bufferLast : _at - 1; return *this; } -inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator--(int) { +template<> inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator--(int) { ConstIterator tmp(*this); --(*this); return tmp; } -inline const int16_t& AudioRingBufferTemplate::ConstIterator::operator[] (int i) { +template<> inline const int16_t& AudioRingBufferTemplate::ConstIterator::operator[] (int i) { return *atShiftedBy(i); } -inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator+(int i) { +template<> inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator+(int i) { return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(i)); } -inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator-(int i) { +template<> inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::ConstIterator::operator-(int i) { return ConstIterator(_bufferFirst, _bufferLength, atShiftedBy(-i)); } -inline int16_t* AudioRingBufferTemplate::ConstIterator::atShiftedBy(int i) { +template<> inline int16_t* AudioRingBufferTemplate::ConstIterator::atShiftedBy(int i) { i = (_at - _bufferFirst + i) % _bufferLength; if (i < 0) { i += _bufferLength; @@ -210,7 +222,7 @@ inline int16_t* AudioRingBufferTemplate::ConstIterator::atShiftedBy(int return _bufferFirst + i; } -inline void AudioRingBufferTemplate::ConstIterator::readSamples(Sample* dest, int numSamples) { +template<> inline void AudioRingBufferTemplate::ConstIterator::readSamples(Sample* dest, int numSamples) { auto samplesToEnd = _bufferLast - _at + 1; if (samplesToEnd >= numSamples) { @@ -225,7 +237,7 @@ inline void AudioRingBufferTemplate::ConstIterator::readSamples(Sample* } } -inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithFade(Sample* dest, int numSamples, float fade) { +template<> inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithFade(Sample* dest, int numSamples, float fade) { Sample* at = _at; for (int i = 0; i < numSamples; i++) { *dest = (float)*at * fade; @@ -234,7 +246,7 @@ inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithFade } } -inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithUpmix(Sample* dest, int numSamples, int numExtraChannels) { +template<> inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithUpmix(Sample* dest, int numSamples, int numExtraChannels) { Sample* at = _at; for (int i = 0; i < numSamples/2; i++) { @@ -253,7 +265,7 @@ inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithUpmi } } -inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithDownmix(Sample* dest, int numSamples) { +template<> inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithDownmix(Sample* dest, int numSamples) { Sample* at = _at; for (int i = 0; i < numSamples/2; i++) { @@ -268,11 +280,11 @@ inline void AudioRingBufferTemplate::ConstIterator::readSamplesWithDown } } -inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::nextOutput() const { +template<> inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::nextOutput() const { return ConstIterator(_buffer, _bufferLength, _nextOutput); } -inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::lastFrameWritten() const { +template<> inline AudioRingBufferTemplate::ConstIterator AudioRingBufferTemplate::lastFrameWritten() const { return ConstIterator(_buffer, _bufferLength, _endOfLastWrite) - _numFrameSamples; }