summaryrefslogtreecommitdiff
path: root/source/audio
diff options
context:
space:
mode:
Diffstat (limited to 'source/audio')
-rw-r--r--source/audio/AudioSettings.c242
-rw-r--r--source/audio/AudioSettings.h183
-rw-r--r--source/audio/SampleBuffer.c175
-rw-r--r--source/audio/SampleBuffer.h107
4 files changed, 707 insertions, 0 deletions
diff --git a/source/audio/AudioSettings.c b/source/audio/AudioSettings.c
new file mode 100644
index 0000000..7d47ec4
--- /dev/null
+++ b/source/audio/AudioSettings.c
@@ -0,0 +1,242 @@
+//
+// AudioSettings.c - MrsWatson
+// Created by Nik Reiman on 1/4/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 "logging/EventLogger.h"
+
+AudioSettings audioSettingsInstance = NULL;
+
+void initAudioSettings(void)
+{
+ if (audioSettingsInstance != NULL) {
+ freeAudioSettings();
+ }
+
+ audioSettingsInstance = malloc(sizeof(AudioSettingsMembers));
+ audioSettingsInstance->sampleRate = DEFAULT_SAMPLE_RATE;
+ audioSettingsInstance->numChannels = DEFAULT_NUM_CHANNELS;
+ audioSettingsInstance->blocksize = DEFAULT_BLOCKSIZE;
+ audioSettingsInstance->tempo = DEFAULT_TEMPO;
+ audioSettingsInstance->timeSignatureBeatsPerMeasure = DEFAULT_TIMESIG_BEATS_PER_MEASURE;
+ audioSettingsInstance->timeSignatureNoteValue = DEFAULT_TIMESIG_NOTE_VALUE;
+}
+
+static AudioSettings _getAudioSettings(void)
+{
+ if (audioSettingsInstance == NULL) {
+ initAudioSettings();
+ }
+
+ return audioSettingsInstance;
+}
+
+SampleRate getSampleRate(void)
+{
+ return _getAudioSettings()->sampleRate;
+}
+
+ChannelCount getNumChannels(void)
+{
+ return _getAudioSettings()->numChannels;
+}
+
+SampleCount getBlocksize(void)
+{
+ return _getAudioSettings()->blocksize;
+}
+
+Tempo getTempo(void)
+{
+ return _getAudioSettings()->tempo;
+}
+
+unsigned short getTimeSignatureBeatsPerMeasure(void)
+{
+ return _getAudioSettings()->timeSignatureBeatsPerMeasure;
+}
+
+unsigned short getTimeSignatureNoteValue(void)
+{
+ return _getAudioSettings()->timeSignatureNoteValue;
+}
+
+
+boolByte setSampleRate(const SampleRate sampleRate)
+{
+ if (sampleRate <= 0.0f) {
+ logError("Can't set sample rate to %f", sampleRate);
+ return false;
+ }
+
+ logInfo("Setting sample rate to %gHz", sampleRate);
+ _getAudioSettings()->sampleRate = sampleRate;
+ return true;
+}
+
+boolByte setNumChannels(const ChannelCount numChannels)
+{
+ if (numChannels <= 0) {
+ logError("Can't set channel count to %d", numChannels);
+ return false;
+ }
+
+ logInfo("Setting %d channels", numChannels);
+ _getAudioSettings()->numChannels = numChannels;
+ return true;
+}
+
+boolByte setBlocksize(const SampleCount blocksize)
+{
+ if (blocksize <= 0) {
+ logError("Can't set invalid blocksize %d", blocksize);
+ return false;
+ }
+
+ logInfo("Setting blocksize to %ld", blocksize);
+ _getAudioSettings()->blocksize = blocksize;
+ return true;
+}
+
+
+boolByte setTempo(const Tempo tempo)
+{
+ if (tempo <= 0.0f) {
+ logError("Cannot set tempo to %f", tempo);
+ return false;
+ }
+
+ //here
+ logInfo("NOT more Setting tempo to %f", tempo);
+ _getAudioSettings()->tempo = tempo;
+ return true;
+}
+
+void setTempoFromMidiBytes(const byte *bytes)
+{
+ double tempo;
+ unsigned long beatLengthInMicroseconds = 0;
+
+ printf("inside midi bytes function");
+ if (bytes != NULL) {
+ float tempotest = getTempo();
+ //seem like a good way to test it? yep
+ printf ("THIS WAS THE TEMPO: %f", tempotest);
+ if (!getTempo()){ //something like this? not sure how to tell if a struct is empty it's integer
+ logInfo("tempo was empty so setting to default value");
+ beatLengthInMicroseconds = (unsigned long)(0x00000000 | (bytes[0] << 16) | (bytes[1] << 8) | (bytes[2]));
+ // Convert beats / microseconds -> beats / minutes
+
+ tempo = (1000000.0 / (double)beatLengthInMicroseconds) * 60.0;
+ tempo = 120; //(1000000.0 / (double)2000) * 60.0;
+ //i guess this function just not called at all yeah but where is tempo Set then? default of some kind
+ //almost like this file isn't getting compiled. above I set tempo to 120, not 100 it might be not calling this function because bytes == NULL
+ //something like this? yes
+ setTempo((float)tempo);
+ }else{
+ logInfo("Using tempo from command line args");
+ }// so midi doesn't have tempo setting i guess t's setting to 100 now, it is supplied from cli? no
+ }else{
+ logInfo("bytes == NULL");
+ }// so midi doesn't have tempo setting i guess t's setting to 100 now, it is supplied from cli? no
+}
+
+boolByte setTimeSignatureBeatsPerMeasure(const unsigned short beatsPerMeasure)
+{
+ // Bit of an easter egg :)
+ if (beatsPerMeasure < 2 || beatsPerMeasure > 12) {
+ logInfo("Freaky time signature, but whatever you say...");
+ }
+
+ if (beatsPerMeasure <= 0) {
+ logError("Ignoring attempt to set time signature numerator to %d", beatsPerMeasure);
+ return false;
+ }
+
+ _getAudioSettings()->timeSignatureBeatsPerMeasure = beatsPerMeasure;
+ return true;
+}
+
+boolByte setTimeSignatureNoteValue(const unsigned short noteValue)
+{
+ // Bit of an easter egg :)
+ if (!(noteValue == 2 || noteValue == 4 || noteValue == 8 || noteValue == 16) || noteValue < 2 || noteValue > 16) {
+ logInfo("Interesting time signature you've chosen. I'm sure this piece is going to sound great...");
+ }
+
+ if (noteValue <= 0) {
+ logError("Ignoring attempt to set time signature denominator to %d", noteValue);
+ return false;
+ }
+
+ _getAudioSettings()->timeSignatureNoteValue = noteValue;
+ return true;
+}
+
+boolByte setTimeSignatureFromString(const CharString signature)
+{
+ char *slash = NULL;
+ unsigned short numerator = 0;
+ unsigned short denominator = 0;
+
+ if (!charStringIsEmpty(signature)) {
+ slash = strchr(signature->data, '/');
+
+ if (slash != NULL) {
+ *slash = '\0';
+ numerator = (unsigned short)strtod(signature->data, NULL);
+ denominator = (unsigned short)strtod(slash + 1, NULL);
+
+ if (numerator > 0 && denominator > 0) {
+ return (boolByte)(setTimeSignatureBeatsPerMeasure(numerator) &&
+ setTimeSignatureNoteValue(denominator));
+ }
+ }
+ }
+
+ return false;
+}
+
+boolByte setTimeSignatureFromMidiBytes(const byte *bytes)
+{
+ if (bytes != NULL) {
+ return (boolByte)(setTimeSignatureBeatsPerMeasure(bytes[0]) &&
+ setTimeSignatureNoteValue((unsigned const short)powl(2, bytes[1])));
+ }
+
+ return false;
+}
+
+void freeAudioSettings(void)
+{
+ free(audioSettingsInstance);
+ audioSettingsInstance = NULL;
+}
diff --git a/source/audio/AudioSettings.h b/source/audio/AudioSettings.h
new file mode 100644
index 0000000..5d050f2
--- /dev/null
+++ b/source/audio/AudioSettings.h
@@ -0,0 +1,183 @@
+//
+// AudioSettings.h - MrsWatson
+// Created by Nik Reiman on 1/4/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.
+//
+
+#ifndef MrsWatson_AudioSettings_h
+#define MrsWatson_AudioSettings_h
+
+#include "base/Types.h"
+#include "base/CharString.h"
+
+#define DEFAULT_SAMPLE_RATE 44100.0f
+#define DEFAULT_NUM_CHANNELS 2
+#define DEFAULT_BLOCKSIZE 512l
+#define DEFAULT_TIME_DIVISION 96
+#define DEFAULT_BITRATE 16
+#define DEFAULT_TEMPO 120.0f
+#define DEFAULT_TIMESIG_BEATS_PER_MEASURE 4
+#define DEFAULT_TIMESIG_NOTE_VALUE 4
+
+typedef struct {
+ SampleRate sampleRate;
+ ChannelCount numChannels;
+ SampleCount blocksize;
+ Tempo tempo;
+ unsigned short timeSignatureBeatsPerMeasure;
+ unsigned short timeSignatureNoteValue;
+} AudioSettingsMembers;
+
+typedef AudioSettingsMembers *AudioSettings;
+extern AudioSettings audioSettingsInstance;
+
+/**
+ * Initialize the global audio settings instance. Since many different classes
+ * require quick access to the audio settings, this is one of the few classes
+ * that has a global singleton instance rather than a "new" allocator.
+ */
+void initAudioSettings(void);
+
+/**
+ * Get the current sample rate.
+ * @return Sample rate in Hertz
+ */
+SampleRate getSampleRate(void);
+
+/**
+ * Get the number of output channels.
+ * @return Number of channels
+ */
+ChannelCount getNumChannels(void);
+
+/**
+ * Give the current block size, which is the number of sample frames sent to the
+ * plugin each time process is called. Note that the blocksize is the number of
+ * *frames* sent to the plugin, so if the channel count is 2 and the blocksize
+ * is 512, 1024 samples will be sent to the plugin. However in that case this
+ * function would still return 512.
+ * @return Blocksize, in sample frames
+ */
+SampleCount getBlocksize(void);
+
+/**
+ * Get the current tempo, in beats per minute
+ * @return Temo in BPM
+ */
+Tempo getTempo(void);
+
+/**
+ * Get the current time signature's numerator, the number of beats per measure.
+ * @return Time signature numerator
+ */
+unsigned short getTimeSignatureBeatsPerMeasure(void);
+
+/**
+ * Get the current time signatures denominator, the value of one beat unit.
+ * @return Time signature denominator
+ */
+unsigned short getTimeSignatureNoteValue(void);
+
+/**
+ * Set the sample rate to be used during processing. This must be set before the
+ * plugin chain is initialized. This function only requires a nonzero value,
+ * however some plugins may behave strangely when sent unusual sample rates.
+ * @param sampleRate Sample rate, in Hertz
+ * @return True if successfully set, false otherwise
+ */
+boolByte setSampleRate(const SampleRate sampleRate);
+
+/**
+ * Set the number of channels to be used during processing. Note that if the
+ * input source defines a channel called, it may override this value.
+ * @param numChannels Number of channels
+ * @return True if successfully set, false otherwise
+ */
+boolByte setNumChannels(const ChannelCount numChannels);
+
+/**
+ * Set the blocksize to be used during processing. Again this should be called
+ * before initializing the plugin chain.
+ * @param blocksize Blocksize in sample frames
+ * @return True if successfully set, false otherwise
+ */
+boolByte setBlocksize(const SampleCount blocksize);
+
+/**
+ * Set tempo to be used during processing.
+ * @param tempo Tempo in beats per minute
+ * @return True if successfully set, false otherwise
+ */
+boolByte setTempo(const Tempo tempo);
+
+/**
+ * MIDI files represent tempo in meta events with a three-byte payload. This
+ * method transforms the three byte sequence from such file into an actual tempo
+ * in beats per minute, and then sets the global tempo to this value.
+ * @param bytes Three byte sequence as read from a MIDI file
+ */
+void setTempoFromMidiBytes(const byte *bytes);
+
+/**
+ * Set the time signature's numerator. This function does very little error
+ * checking, but it does require a non-zero value. However, many plugins may act
+ * strangely with unusual time signatures.
+ * @param beatsPerMeasure Time signature numerator
+ * @return True if successfully set, false otherwise
+ */
+boolByte setTimeSignatureBeatsPerMeasure(const unsigned short beatsPerMeasure);
+
+/**
+ * Set the time signature's denominator. This function does very little error
+ * checking, but it does require a non-zero value. However, many plugins may act
+ * strangely with unusual time signatures.
+ * @param noteValue Time signature denominator
+ * @return True if successfully set, false otherwise
+ */
+boolByte setTimeSignatureNoteValue(const unsigned short noteValue);
+
+/**
+ * MIDI files represent musical time signature with a two-byte sequence. This
+ * function takes two bytes, derives the corresponding time signature, and sets
+ * it in the global instance.
+ * @param bytes Two byte sequence as read from a MIDI file
+ * @return True if successfully set, false otherwise
+ */
+boolByte setTimeSignatureFromMidiBytes(const byte *bytes);
+
+/**
+ * Set the time signature from a string, should look like "3/4".
+ * @param signature Time signature to set
+ * @return True if successfully set, false otherwise
+ */
+boolByte setTimeSignatureFromString(const CharString signature);
+
+/**
+ * Release memory of the global audio settings instance. Any attempt to use the
+ * audio settings functions after this has been called will result in undefined
+ * behavior.
+ */
+void freeAudioSettings(void);
+
+#endif
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);
+}
diff --git a/source/audio/SampleBuffer.h b/source/audio/SampleBuffer.h
new file mode 100644
index 0000000..7c19dc9
--- /dev/null
+++ b/source/audio/SampleBuffer.h
@@ -0,0 +1,107 @@
+//
+// SampleBuffer.h - 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.
+//
+
+#ifndef MrsWatson_SampleBuffer_h
+#define MrsWatson_SampleBuffer_h
+
+#include "base/Types.h"
+
+typedef struct {
+ ChannelCount numChannels;
+ SampleCount blocksize;
+ Samples *samples;
+} SampleBufferMembers;
+typedef SampleBufferMembers *SampleBuffer;
+
+/**
+ * Create a new SampleBuffer instance
+ * @param numChannels Number of channels
+ * @param blocksize Processing blocksize to use
+ * @return An initialized SampleBuffer instance
+ */
+SampleBuffer newSampleBuffer(ChannelCount numChannels, SampleCount blocksize);
+
+/**
+ * Set all samples to zero
+ * @param self
+ */
+void sampleBufferClear(SampleBuffer self);
+
+/**
+ * Copy some samples from another buffer to this one
+ * @param destinationBuffer
+ * @param destinationOffset zero-based index of where to start in destinationBuffer.
+ * @param sourceBuffer Other buffer to copy from
+ * @param sourceOffset zero-based index of where to start in buffer.
+ * @param numberOfFrames number of frames to copy.
+ * @return True on success, false on failure
+ */
+boolByte sampleBufferCopyAndMapChannelsWithOffset(SampleBuffer destinationBuffer,
+ SampleCount destinationOffset,
+ const SampleBuffer sourceBuffer,
+ SampleCount sourceOffset,
+ SampleCount numberOfFrames);
+
+/**
+* Copy all samples from another buffer to this one
+* @param self
+* @param buffer Other buffer to copy from
+* @return True on success, false on failure
+*/
+boolByte sampleBufferCopyAndMapChannels(SampleBuffer self, const SampleBuffer buffer);
+
+/**
+ * Copy a buffer of interlaced short integer samples to a sample buffer. This
+ * function also converts the samples from integers to floating-point numbers.
+ * Mostly useful for reading raw PCM data into a format usable by plugins.
+ * @param self
+ * @param inPcmSamples Array of interlaced samples. Note that the size of the
+ * length of this array must match the SampleBuffer's blocksize * channel count,
+ * or else undefined behavior will occur.
+ */
+void sampleBufferCopyPcmSamples(SampleBuffer self, const short *inPcmSamples);
+
+/**
+ * Get an array of interlaced short integer samples from the SampleBuffer. This
+ * function will also convert the samples from floating-point numbers to short
+ * integers. Mostly useful for writing raw PCM data.
+ * @param self
+ * @param outPcmSamples A pre-allocated array large enough to hold the result of
+ * the conversion. This means that at least blocksize * channel count samples
+ * must be allocated
+ * @param flipEndian True if the output data should have the samples flipped
+ * from the native endianness.
+ */
+void sampleBufferGetPcmSamples(const SampleBuffer self, short *outPcmSamples, boolByte flipEndian);
+
+/**
+ * Free all memory used by a SampleBuffer instance
+ * @param sampleBuffer
+ */
+void freeSampleBuffer(SampleBuffer self);
+
+#endif