You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
8.3 KiB
275 lines
8.3 KiB
//////////////////////////////////////////////////////////////////////////////// |
|
/// |
|
/// A buffer class for temporarily storaging sound samples, operates as a |
|
/// first-in-first-out pipe. |
|
/// |
|
/// Samples are added to the end of the sample buffer with the 'putSamples' |
|
/// function, and are received from the beginning of the buffer by calling |
|
/// the 'receiveSamples' function. The class automatically removes the |
|
/// outputted samples from the buffer, as well as grows the buffer size |
|
/// whenever necessary. |
|
/// |
|
/// Author : Copyright (c) Olli Parviainen |
|
/// Author e-mail : oparviai 'at' iki.fi |
|
/// SoundTouch WWW: http://www.surina.net/soundtouch |
|
/// |
|
//////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// License : |
|
// |
|
// SoundTouch audio processing library |
|
// Copyright (c) Olli Parviainen |
|
// |
|
// This library is free software; you can redistribute it and/or |
|
// modify it under the terms of the GNU Lesser General Public |
|
// License as published by the Free Software Foundation; either |
|
// version 2.1 of the License, or (at your option) any later version. |
|
// |
|
// This library is distributed in the hope that it will be useful, |
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
// Lesser General Public License for more details. |
|
// |
|
// You should have received a copy of the GNU Lesser General Public |
|
// License along with this library; if not, write to the Free Software |
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
// |
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
#include <stdlib.h> |
|
#include <memory.h> |
|
#include <string.h> |
|
#include <assert.h> |
|
|
|
#include "FIFOSampleBuffer.h" |
|
|
|
using namespace soundtouch; |
|
|
|
// Constructor |
|
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) |
|
{ |
|
assert(numChannels > 0); |
|
sizeInBytes = 0; // reasonable initial value |
|
buffer = nullptr; |
|
bufferUnaligned = nullptr; |
|
samplesInBuffer = 0; |
|
bufferPos = 0; |
|
channels = (uint)numChannels; |
|
ensureCapacity(32); // allocate initial capacity |
|
} |
|
|
|
|
|
// destructor |
|
FIFOSampleBuffer::~FIFOSampleBuffer() |
|
{ |
|
delete[] bufferUnaligned; |
|
bufferUnaligned = nullptr; |
|
buffer = nullptr; |
|
} |
|
|
|
|
|
// Sets number of channels, 1 = mono, 2 = stereo |
|
void FIFOSampleBuffer::setChannels(int numChannels) |
|
{ |
|
uint usedBytes; |
|
|
|
if (!verifyNumberOfChannels(numChannels)) return; |
|
|
|
usedBytes = channels * samplesInBuffer; |
|
channels = (uint)numChannels; |
|
samplesInBuffer = usedBytes / channels; |
|
} |
|
|
|
|
|
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and |
|
// zeroes this pointer by copying samples from the 'bufferPos' pointer |
|
// location on to the beginning of the buffer. |
|
void FIFOSampleBuffer::rewind() |
|
{ |
|
if (buffer && bufferPos) |
|
{ |
|
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); |
|
bufferPos = 0; |
|
} |
|
} |
|
|
|
|
|
// Adds 'numSamples' pcs of samples from the 'samples' memory position to |
|
// the sample buffer. |
|
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) |
|
{ |
|
memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); |
|
samplesInBuffer += nSamples; |
|
} |
|
|
|
|
|
// Increases the number of samples in the buffer without copying any actual |
|
// samples. |
|
// |
|
// This function is used to update the number of samples in the sample buffer |
|
// when accessing the buffer directly with 'ptrEnd' function. Please be |
|
// careful though! |
|
void FIFOSampleBuffer::putSamples(uint nSamples) |
|
{ |
|
uint req; |
|
|
|
req = samplesInBuffer + nSamples; |
|
ensureCapacity(req); |
|
samplesInBuffer += nSamples; |
|
} |
|
|
|
|
|
// Returns a pointer to the end of the used part of the sample buffer (i.e. |
|
// where the new samples are to be inserted). This function may be used for |
|
// inserting new samples into the sample buffer directly. Please be careful! |
|
// |
|
// Parameter 'slackCapacity' tells the function how much free capacity (in |
|
// terms of samples) there _at least_ should be, in order to the caller to |
|
// successfully insert all the required samples to the buffer. When necessary, |
|
// the function grows the buffer size to comply with this requirement. |
|
// |
|
// When using this function as means for inserting new samples, also remember |
|
// to increase the sample count afterwards, by calling the |
|
// 'putSamples(numSamples)' function. |
|
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) |
|
{ |
|
ensureCapacity(samplesInBuffer + slackCapacity); |
|
return buffer + samplesInBuffer * channels; |
|
} |
|
|
|
|
|
// Returns a pointer to the beginning of the currently non-outputted samples. |
|
// This function is provided for accessing the output samples directly. |
|
// Please be careful! |
|
// |
|
// When using this function to output samples, also remember to 'remove' the |
|
// outputted samples from the buffer by calling the |
|
// 'receiveSamples(numSamples)' function |
|
SAMPLETYPE *FIFOSampleBuffer::ptrBegin() |
|
{ |
|
assert(buffer); |
|
return buffer + bufferPos * channels; |
|
} |
|
|
|
|
|
// Ensures that the buffer has enough capacity, i.e. space for _at least_ |
|
// 'capacityRequirement' number of samples. The buffer is grown in steps of |
|
// 4 kilobytes to eliminate the need for frequently growing up the buffer, |
|
// as well as to round the buffer size up to the virtual memory page size. |
|
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) |
|
{ |
|
SAMPLETYPE *tempUnaligned, *temp; |
|
|
|
if (capacityRequirement > getCapacity()) |
|
{ |
|
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary) |
|
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; |
|
assert(sizeInBytes % 2 == 0); |
|
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; |
|
if (tempUnaligned == nullptr) |
|
{ |
|
ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); |
|
} |
|
// Align the buffer to begin at 16byte cache line boundary for optimal performance |
|
temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); |
|
if (samplesInBuffer) |
|
{ |
|
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); |
|
} |
|
delete[] bufferUnaligned; |
|
buffer = temp; |
|
bufferUnaligned = tempUnaligned; |
|
bufferPos = 0; |
|
} |
|
else |
|
{ |
|
// simply rewind the buffer (if necessary) |
|
rewind(); |
|
} |
|
} |
|
|
|
|
|
// Returns the current buffer capacity in terms of samples |
|
uint FIFOSampleBuffer::getCapacity() const |
|
{ |
|
return sizeInBytes / (channels * sizeof(SAMPLETYPE)); |
|
} |
|
|
|
|
|
// Returns the number of samples currently in the buffer |
|
uint FIFOSampleBuffer::numSamples() const |
|
{ |
|
return samplesInBuffer; |
|
} |
|
|
|
|
|
// Output samples from beginning of the sample buffer. Copies demanded number |
|
// of samples to output and removes them from the sample buffer. If there |
|
// are less than 'numsample' samples in the buffer, returns all available. |
|
// |
|
// Returns number of samples copied. |
|
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) |
|
{ |
|
uint num; |
|
|
|
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; |
|
|
|
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); |
|
return receiveSamples(num); |
|
} |
|
|
|
|
|
// Removes samples from the beginning of the sample buffer without copying them |
|
// anywhere. Used to reduce the number of samples in the buffer, when accessing |
|
// the sample buffer with the 'ptrBegin' function. |
|
uint FIFOSampleBuffer::receiveSamples(uint maxSamples) |
|
{ |
|
if (maxSamples >= samplesInBuffer) |
|
{ |
|
uint temp; |
|
|
|
temp = samplesInBuffer; |
|
samplesInBuffer = 0; |
|
return temp; |
|
} |
|
|
|
samplesInBuffer -= maxSamples; |
|
bufferPos += maxSamples; |
|
|
|
return maxSamples; |
|
} |
|
|
|
|
|
// Returns nonzero if the sample buffer is empty |
|
int FIFOSampleBuffer::isEmpty() const |
|
{ |
|
return (samplesInBuffer == 0) ? 1 : 0; |
|
} |
|
|
|
|
|
// Clears the sample buffer |
|
void FIFOSampleBuffer::clear() |
|
{ |
|
samplesInBuffer = 0; |
|
bufferPos = 0; |
|
} |
|
|
|
|
|
/// allow trimming (downwards) amount of samples in pipeline. |
|
/// Returns adjusted amount of samples |
|
uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) |
|
{ |
|
if (numSamples < samplesInBuffer) |
|
{ |
|
samplesInBuffer = numSamples; |
|
} |
|
return samplesInBuffer; |
|
} |
|
|
|
|
|
/// Add silence to end of buffer |
|
void FIFOSampleBuffer::addSilent(uint nSamples) |
|
{ |
|
memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels); |
|
samplesInBuffer += nSamples; |
|
}
|
|
|