diff options
| author | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
|---|---|---|
| committer | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
| commit | d53fa8a169832563c62262078b8d2ffe5cab8473 (patch) | |
| tree | b911d06d357d009c976709780f10e92ce915228a /source/audio/SampleBuffer.c | |
first
Diffstat (limited to 'source/audio/SampleBuffer.c')
| -rw-r--r-- | source/audio/SampleBuffer.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/source/audio/SampleBuffer.c b/source/audio/SampleBuffer.c new file mode 100644 index 0000000..610cd95 --- /dev/null +++ b/source/audio/SampleBuffer.c @@ -0,0 +1,175 @@ +// +// 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#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); +} |
