Permalink
Browse files

New class, AudioSampleBufferAudioFormat.

  • Loading branch information...
drowaudio committed Mar 17, 2012
1 parent fe58c58 commit efc5211357a642d1f5157f6e7d115c8e602fdfdc
View
@@ -19,7 +19,7 @@ juce_audio_formats/
juce_audio_processors/
juce_audio_utils/
juce_core/
-juce_cprytography/
+juce_cryptography/
juce_data_structures/
juce_events/
juce_graphics/
@@ -32,6 +32,7 @@ AudioFilePlayer::AudioFilePlayer()
masterSource = audioTransportSource;
formatManager->registerBasicFormats();
+ formatManager->registerFormat (new AudioSampleBufferAudioFormat(), false);
}
AudioFilePlayer::~AudioFilePlayer()
@@ -123,7 +124,7 @@ MemoryInputStream* AudioFilePlayer::getInputStream()
bool AudioFilePlayer::sourceIsMemoryBlock()
{
- return currentMemoryBlock != nullptr;
+ return file == File::nonexistent;
}
void AudioFilePlayer::setAudioFormatManager (AudioFormatManager* newManager, bool deleteWhenNotNeeded)
@@ -0,0 +1,151 @@
+/*
+ ==============================================================================
+
+ This file is part of the dRowAudio JUCE module
+ Copyright 2004-12 by dRowAudio.
+
+ ------------------------------------------------------------------------------
+
+ dRowAudio can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the module distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ dRowAudio 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 General Public License for more details.
+
+ ==============================================================================
+*/
+
+BEGIN_JUCE_NAMESPACE
+
+//==============================================================================
+namespace
+{
+ const char* const audioSampleBufferAudioFormatName = "AudioSampleBuffer format stream";
+}
+
+//==============================================================================
+class AudioSampleBufferReader : public AudioFormatReader
+{
+public:
+ AudioSampleBufferReader (InputStream* const inp)
+ : AudioFormatReader (inp, TRANS (audioSampleBufferAudioFormatName)),
+ ok (false)
+ {
+ usesFloatingPointData = true;
+
+ if (inp != nullptr)
+ {
+ ok = isAudioSampleBuffer (*inp, numChannels, lengthInSamples);
+ sampleRate = 44100;
+ bitsPerSample = 32;
+ }
+ }
+
+ ~AudioSampleBufferReader()
+ {
+ }
+
+ //==============================================================================
+ bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
+ int64 startSampleInFile, int numSamples)
+ {
+ jassert (destSamples != nullptr);
+ const int64 samplesAvailable = lengthInSamples - startSampleInFile;
+
+ if (samplesAvailable < numSamples)
+ {
+ for (int i = numDestChannels; --i >= 0;)
+ if (destSamples[i] != nullptr)
+ zeromem (destSamples[i] + startOffsetInDestBuffer, sizeof (int) * numSamples);
+
+ numSamples = (int) samplesAvailable;
+ }
+
+ if (numSamples <= 0)
+ return true;
+
+ while (numSamples > 0)
+ {
+ const int numThisTime = jmin (8192, numSamples);
+ const int numBytes = numThisTime * sizeof (float);
+
+ for (int c = numChannels; --c >= 0;)
+ {
+ const int64 pos = sampleToReadPosition (c, startSampleInFile);
+ input->setPosition (pos);
+
+ if (destSamples[c] != nullptr)
+ {
+ if (c < numChannels)
+ input->read (destSamples[c] + startOffsetInDestBuffer, numBytes);
+ else
+ zeromem (destSamples[c] + startOffsetInDestBuffer, numBytes);
+ }
+ }
+
+ startOffsetInDestBuffer += numThisTime;
+ numSamples -= numThisTime;
+ }
+
+ return true;
+ }
+
+ bool ok;
+
+private:
+ int64 sampleToReadPosition (int channel, int64 samplePosition)
+ {
+ const size_t startPosition = (numChannels + 1) * sizeof (float*);
+ const int64 channelStartByte = startPosition + (channel * lengthInSamples * sizeof (float));
+ const int64 sampleStartByte = channelStartByte + (samplePosition * sizeof (float));
+
+ return sampleStartByte;
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSampleBufferReader);
+};
+
+//==============================================================================
+AudioSampleBufferAudioFormat::AudioSampleBufferAudioFormat()
+: AudioFormat (TRANS (audioSampleBufferAudioFormatName), StringArray())
+{
+}
+
+AudioSampleBufferAudioFormat::~AudioSampleBufferAudioFormat() {}
+
+Array<int> AudioSampleBufferAudioFormat::getPossibleSampleRates() { return Array<int>(); }
+Array<int> AudioSampleBufferAudioFormat::getPossibleBitDepths() { return Array<int>(); }
+
+bool AudioSampleBufferAudioFormat::canDoStereo() { return true; }
+bool AudioSampleBufferAudioFormat::canDoMono() { return true; }
+
+//==============================================================================
+AudioFormatReader* AudioSampleBufferAudioFormat::createReaderFor (InputStream* sourceStream,
+ bool deleteStreamIfOpeningFails)
+{
+ ScopedPointer<AudioSampleBufferReader> r (new AudioSampleBufferReader (sourceStream));
+
+ if (r->ok)
+ return r.release();
+
+ if (! deleteStreamIfOpeningFails)
+ r->input = nullptr;
+
+ return nullptr;
+}
+
+AudioFormatWriter* AudioSampleBufferAudioFormat::createWriterFor (OutputStream* streamToWriteTo,
+ double sampleRateToUse,
+ unsigned int numberOfChannels,
+ int bitsPerSample,
+ const StringPairArray& metadataValues,
+ int qualityOptionIndex)
+{
+ jassertfalse; // not yet implemented!
+ return nullptr;
+}
+
+END_JUCE_NAMESPACE
@@ -0,0 +1,67 @@
+/*
+ ==============================================================================
+
+ This file is part of the dRowAudio JUCE module
+ Copyright 2004-12 by dRowAudio.
+
+ ------------------------------------------------------------------------------
+
+ dRowAudio can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the module distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ dRowAudio 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 General Public License for more details.
+
+ ==============================================================================
+*/
+
+#ifndef __DROWAUDIO_AUDIOSAMPLEBUFFERAUDIOFORMAT_H__
+#define __DROWAUDIO_AUDIOSAMPLEBUFFERAUDIOFORMAT_H__
+
+//==============================================================================
+/**
+ Streams data from an AudioSampleBuffer.
+
+ This reads from a stream that has been initialised from the AudioSampleBuffer
+ method getArrayOfChannels(). The AudioSampleBuffer needs to stay in exisistance
+ for the duration of this object and not be changed as the stream is unique to
+ the memory layout of the buffer.
+
+ @see AudioFormat
+ */
+class AudioSampleBufferAudioFormat : public AudioFormat
+{
+public:
+ //==============================================================================
+ /** Creates a format object. */
+ AudioSampleBufferAudioFormat();
+
+ /** Destructor. */
+ ~AudioSampleBufferAudioFormat();
+
+ //==============================================================================
+ Array<int> getPossibleSampleRates();
+ Array<int> getPossibleBitDepths();
+ bool canDoStereo();
+ bool canDoMono();
+
+ //==============================================================================
+ AudioFormatReader* createReaderFor (InputStream* sourceStream,
+ bool deleteStreamIfOpeningFails);
+
+ AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo,
+ double sampleRateToUse,
+ unsigned int numberOfChannels,
+ int bitsPerSample,
+ const StringPairArray& metadataValues,
+ int qualityOptionIndex);
+
+private:
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSampleBufferAudioFormat);
+};
+
+
+#endif // __DROWAUDIO_AUDIOSAMPLEBUFFERAUDIOFORMAT_H__
@@ -229,4 +229,132 @@ static void convertToFloat (AudioFormatReader* reader, void* sourceBuffer, float
}
}
+//==============================================================================
+/** Returns the number bytes needed to store an AudioSampleBuffer with its
+ channel header and sample data.
+
+ This can be used to find out how many bytes to pass to isAudioSampleBuffer().
+ */
+static size_t getNumBytesForAudioSampleBuffer (const AudioSampleBuffer& buffer)
+{
+ const size_t channelListSize = (buffer.getNumChannels() + 1) * sizeof (float*);
+ const size_t sampleDataSize = buffer.getNumSamples() * buffer.getNumChannels() * sizeof (float);
+
+ return channelListSize + sampleDataSize;
+}
+
+/** Parses a block of memory to see if it represents an AudioSampleBuffer.
+
+ This uses the memory layout of an AudioSampleBuffer to make an eductated
+ guess at whether the memory represents an AudioSampleBuffer. For speed
+ this will only check for buffers up to maxNumChannels channels.
+
+ @param sourceData The start of the likely AudioSampleBuffer to be
+ tested e.g. AudioSampleBuffer::getArrayOfChannels()
+ @param sourceDataSize The number of bytes of the sourceData
+ @param maxNumChannels An optional maximum number of channels to search
+ @returns true if the sourceData likey represents an AudioSampleBuffer
+
+ @see AudioSampleBufferAudioFormat, getNumBytesForAudioSampleBuffer, AudioSampleBuffer
+ */
+static bool isAudioSampleBuffer (void* sourceData, size_t sourceDataSize, int maxNumChannels = 128)
+{
+ const float** channelList = reinterpret_cast<const float**> (sourceData);
+
+ // get channel list pointers
+ Array<const float*> channelPointers;
+ for (int i = 0; i < maxNumChannels; i++)
+ {
+ const float* channelPointer = channelList[i];
+
+ if (channelPointer == nullptr) // found end of channel list
+ break;
+
+ channelPointers.add (channelPointer);
+ }
+
+ if (channelPointers.size() == 0)
+ return false;
+
+ const size_t channelListSize = (channelPointers.size() + 1) * sizeof (float*);
+ const int expectedNumSamples = (sourceDataSize - channelListSize) / (channelPointers.size() * sizeof (float));
+ const size_t bytesPerChannel = expectedNumSamples * sizeof (float);
+
+ const float* startOfChannels = reinterpret_cast<float*> (addBytesToPointer (sourceData, channelListSize));
+
+ // compare to sample data pointers
+ for (int i = 0; i < channelPointers.size(); i++)
+ {
+ const float* channelPointer = addBytesToPointer (startOfChannels, (i * bytesPerChannel));
+ if (channelPointer != channelPointers[i])
+ return false;
+ }
+
+ return true;
+}
+
+/** Parses an InputStream to see if it represents an AudioSampleBuffer.
+
+ This uses the memory layout of an AudioSampleBuffer to make an eductated
+ guess at whether the stream represents an AudioSampleBuffer. For speed
+ this will only check for buffers up to maxNumChannels channels.
+
+ @param inputStream The stream to check for AudioSampleBuffer contents
+ @param maxNumChannels An optional maximum number of channels to search
+ @returns true if the stream likey represents an AudioSampleBuffer
+
+ @see AudioSampleBufferAudioFormat, getNumBytesForAudioSampleBuffer, AudioSampleBuffer
+ */
+static bool isAudioSampleBuffer (InputStream& inputStream,
+ unsigned int &numChannels, int64 &numSamples,
+ int maxNumChannels = 128)
+{
+ // get start samples
+ Array<float> channelStartSamples;
+ for (int i = 0; i < maxNumChannels; i++)
+ {
+ float* channelPointer;
+ inputStream.read (&channelPointer, sizeof (float*));
+
+ if (channelPointer == nullptr) // found end of channel list
+ break;
+
+ channelStartSamples.add (*channelPointer);
+ }
+
+ if (channelStartSamples.size() == 0)
+ return false;
+
+ const size_t channelListSize = (channelStartSamples.size() + 1) * sizeof (float*);
+ const int expectedNumSamples = (inputStream.getTotalLength() - channelListSize) / (channelStartSamples.size() * sizeof (float));
+ const size_t bytesPerChannel = expectedNumSamples * sizeof (float);
+
+ // compare sample values
+ for (int i = 0; i < channelStartSamples.size(); i++)
+ {
+ float sample;
+ inputStream.setPosition (channelListSize + (i * bytesPerChannel));
+ inputStream.read (&sample, sizeof (float));
+
+ if (sample != channelStartSamples[i])
+ return false;
+ }
+
+ // slower but possibly more reliable method
+// for (int i = 0; i < channelStartSamples.size(); i++)
+// {
+// float sample;
+// inputStream.read (&sample, sizeof (float));
+// inputStream.skipNextBytes (bytesPerChannel);
+//
+// if (sample != channelStartSamples[i])
+// return false;
+// }
+
+ numChannels = channelStartSamples.size();
+ numSamples = expectedNumSamples;
+
+ return true;
+}
+
#endif //__DROWAUDIO_AUDIOUTILITY_H__
Oops, something went wrong.

0 comments on commit efc5211

Please sign in to comment.