// // SampleBuffer.c - MrsWatson // Created by Nik Reiman on 1/2/12. // Copyright (c) 2012 Teragon Audio. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // #include #include #include #include #include "audio/AudioSettings.h" #include "audio/SampleBuffer.h" #include "base/Endian.h" #include "logging/EventLogger.h" #include "SampleBuffer.h" SampleBuffer newSampleBuffer(ChannelCount numChannels, SampleCount blocksize) { SampleBuffer sampleBuffer = (SampleBuffer)malloc(sizeof(SampleBufferMembers)); sampleBuffer->numChannels = numChannels; sampleBuffer->blocksize = blocksize; sampleBuffer->samples = (Samples *)malloc(sizeof(Samples) * numChannels); for (ChannelCount i = 0; i < numChannels; i++) { sampleBuffer->samples[i] = (Samples)malloc(sizeof(Sample) * blocksize); } sampleBufferClear(sampleBuffer); return sampleBuffer; } void sampleBufferClear(SampleBuffer self) { for (ChannelCount i = 0; i < self->numChannels; i++) { memset(self->samples[i], 0, sizeof(Sample) * self->blocksize); } } boolByte sampleBufferCopyAndMapChannelsWithOffset(SampleBuffer destinationBuffer, SampleCount destinationOffset, const SampleBuffer sourceBuffer, SampleCount sourceOffset, SampleCount numberOfFrames) { // Definitely not supported. if (destinationBuffer->blocksize < destinationOffset + numberOfFrames) { logInternalError("Destination buffer size %d < %d", destinationBuffer->blocksize, destinationOffset + numberOfFrames); return false; } // Definitely not supported. if (sourceBuffer->blocksize < sourceOffset + numberOfFrames) { logInternalError("Source buffer size %d < %d", sourceBuffer->blocksize, sourceOffset + numberOfFrames); return false; } if (sourceBuffer->numChannels != destinationBuffer->numChannels) { logDebug("Mapping channels from %d -> %d", sourceBuffer->numChannels, destinationBuffer->numChannels); } // If the other buffer is bigger (or the same size) as this buffer, then only // copy up to the channel count of this buffer. Any other data will be lost, // sorry about that! if (sourceBuffer->numChannels >= destinationBuffer->numChannels) { for (ChannelCount i = 0; i < destinationBuffer->numChannels; ++i) { memcpy(destinationBuffer->samples[i] + destinationOffset, sourceBuffer->samples[i] + sourceOffset, sizeof(Sample) * numberOfFrames); } } // But if this buffer is bigger than the other buffer, then copy all channels // to this one. For example, if this buffer is 4 channels and the other buffer // is 2 channels, then we copy the stereo pair to this channel (L R L R). else { for (ChannelCount i = 0; i < destinationBuffer->numChannels; ++i) { if (sourceBuffer->numChannels > 0) { memcpy(destinationBuffer->samples[i] + destinationOffset, sourceBuffer->samples[i % sourceBuffer->numChannels] + sourceOffset, sizeof(Sample) * numberOfFrames); } else { // If the other buffer has zero channels just clear this buffer. memset(destinationBuffer->samples[i] + destinationOffset, 0, sizeof(Sample) * numberOfFrames); } } } return true; } boolByte sampleBufferCopyAndMapChannels(SampleBuffer self, const SampleBuffer buffer) { // Definitely not supported, otherwise it would be hard to deal with partial // copies and so forth. if (self->blocksize != buffer->blocksize) { logInternalError("Source and destination buffer are not the same size"); return false; } return sampleBufferCopyAndMapChannelsWithOffset(self, 0, buffer, 0, self->blocksize); } void sampleBufferCopyPcmSamples(SampleBuffer self, const short *inPcmSamples) { const unsigned int numChannels = self->numChannels; const unsigned long numInterlacedSamples = numChannels * self->blocksize; unsigned int currentInterlacedSample = 0; unsigned int currentDeinterlacedSample = 0; unsigned int currentChannel; while (currentInterlacedSample < numInterlacedSamples) { for (currentChannel = 0; currentChannel < numChannels; ++currentChannel) { Sample convertedSample = (Sample)inPcmSamples[currentInterlacedSample++] / 32767.0f; self->samples[currentChannel][currentDeinterlacedSample] = convertedSample; } ++currentDeinterlacedSample; } } void sampleBufferGetPcmSamples(const SampleBuffer self, short *outPcmSamples, boolByte flipEndian) { const unsigned long blocksize = self->blocksize; const unsigned int numChannels = self->numChannels; unsigned int currentInterlacedSample = 0; unsigned int currentSample = 0; unsigned int currentChannel = 0; short shortValue; Sample sample; for (currentSample = 0; currentSample < blocksize; ++currentSample) { for (currentChannel = 0; currentChannel < numChannels; ++currentChannel) { sample = self->samples[currentChannel][currentSample]; shortValue = (short)(sample * 32767.0f); if (flipEndian) { outPcmSamples[currentInterlacedSample++] = flipShortEndian(shortValue); } else { outPcmSamples[currentInterlacedSample++] = shortValue; } } } } void freeSampleBuffer(SampleBuffer self) { if (self == NULL) { return; } for (ChannelCount channel = 0; channel < self->numChannels; ++channel) { free(self->samples[channel]); } free(self->samples); free(self); }