123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- ////////////////////////////////////////////////////////////////////////////////
- ///
- /// 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;
- }
|