summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/audio/mac
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/audio/mac')
-rw-r--r--Source/WebCore/platform/audio/mac/AudioBusMac.mm66
-rw-r--r--Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp171
-rw-r--r--Source/WebCore/platform/audio/mac/AudioDestinationMac.h69
-rw-r--r--Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp258
-rw-r--r--Source/WebCore/platform/audio/mac/AudioFileReaderMac.h71
-rw-r--r--Source/WebCore/platform/audio/mac/FFTFrameMac.cpp191
6 files changed, 826 insertions, 0 deletions
diff --git a/Source/WebCore/platform/audio/mac/AudioBusMac.mm b/Source/WebCore/platform/audio/mac/AudioBusMac.mm
new file mode 100644
index 0000000..3d454a9
--- /dev/null
+++ b/Source/WebCore/platform/audio/mac/AudioBusMac.mm
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#import "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#import "AudioBus.h"
+
+#import "AudioFileReader.h"
+#import <wtf/OwnPtr.h>
+#import <wtf/PassOwnPtr.h>
+#import <Foundation/Foundation.h>
+
+@interface WebCoreAudioBundleClass : NSObject
+@end
+
+@implementation WebCoreAudioBundleClass
+@end
+
+namespace WebCore {
+
+PassOwnPtr<AudioBus> AudioBus::loadPlatformResource(const char* name, double sampleRate)
+{
+ // This method can be called from other than the main thread, so we need an auto-release pool.
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ NSBundle *bundle = [NSBundle bundleForClass:[WebCoreAudioBundleClass class]];
+ NSString *audioFilePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"wav" inDirectory:@"audio"];
+ NSData *audioData = [NSData dataWithContentsOfFile:audioFilePath];
+
+ if (audioData) {
+ OwnPtr<AudioBus> bus(createBusFromInMemoryAudioFile([audioData bytes], [audioData length], false, sampleRate));
+ [pool release];
+ return bus.release();
+ }
+
+ ASSERT_NOT_REACHED();
+ [pool release];
+ return 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp b/Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp
new file mode 100644
index 0000000..523729f
--- /dev/null
+++ b/Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioDestinationMac.h"
+
+#include "AudioSourceProvider.h"
+#include <CoreAudio/AudioHardware.h>
+
+namespace WebCore {
+
+const int kBufferSize = 128;
+
+// Factory method: Mac-implementation
+PassOwnPtr<AudioDestination> AudioDestination::create(AudioSourceProvider& provider, double sampleRate)
+{
+ return adoptPtr(new AudioDestinationMac(provider, sampleRate));
+}
+
+double AudioDestination::hardwareSampleRate()
+{
+ // Determine the default output device's sample-rate.
+ AudioDeviceID deviceID = kAudioDeviceUnknown;
+ UInt32 infoSize = sizeof(deviceID);
+
+ AudioObjectPropertyAddress defaultInputDeviceAddress = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+ OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultInputDeviceAddress, 0, 0, &infoSize, (void*)&deviceID);
+ if (result)
+ return 0.0; // error
+
+ Float64 nominalSampleRate;
+ infoSize = sizeof(Float64);
+
+ AudioObjectPropertyAddress nominalSampleRateAddress = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+ result = AudioObjectGetPropertyData(deviceID, &nominalSampleRateAddress, 0, 0, &infoSize, (void*)&nominalSampleRate);
+ if (result)
+ return 0.0; // error
+
+ return nominalSampleRate;
+}
+
+AudioDestinationMac::AudioDestinationMac(AudioSourceProvider& provider, double sampleRate)
+ : m_outputUnit(0)
+ , m_provider(provider)
+ , m_renderBus(2, kBufferSize, false)
+ , m_sampleRate(sampleRate)
+ , m_isPlaying(false)
+{
+ // Open and initialize DefaultOutputUnit
+ Component comp;
+ ComponentDescription desc;
+
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+ comp = FindNextComponent(0, &desc);
+
+ ASSERT(comp);
+
+ OSStatus result = OpenAComponent(comp, &m_outputUnit);
+ ASSERT(!result);
+
+ result = AudioUnitInitialize(m_outputUnit);
+ ASSERT(!result);
+
+ configure();
+}
+
+AudioDestinationMac::~AudioDestinationMac()
+{
+ if (m_outputUnit)
+ CloseComponent(m_outputUnit);
+}
+
+void AudioDestinationMac::configure()
+{
+ // Set render callback
+ AURenderCallbackStruct input;
+ input.inputProc = inputProc;
+ input.inputProcRefCon = this;
+ OSStatus result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &input, sizeof(input));
+ ASSERT(!result);
+
+ // Set stream format
+ AudioStreamBasicDescription streamFormat;
+ streamFormat.mSampleRate = m_sampleRate;
+ streamFormat.mFormatID = kAudioFormatLinearPCM;
+ streamFormat.mFormatFlags = kAudioFormatFlagsCanonical | kAudioFormatFlagIsNonInterleaved;
+ streamFormat.mBitsPerChannel = 8 * sizeof(AudioSampleType);
+ streamFormat.mChannelsPerFrame = 2;
+ streamFormat.mFramesPerPacket = 1;
+ streamFormat.mBytesPerPacket = sizeof(AudioSampleType);
+ streamFormat.mBytesPerFrame = sizeof(AudioSampleType);
+
+ result = AudioUnitSetProperty(m_outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, (void*)&streamFormat, sizeof(AudioStreamBasicDescription));
+ ASSERT(!result);
+
+ // Set the buffer frame size.
+ UInt32 bufferSize = kBufferSize;
+ result = AudioUnitSetProperty(m_outputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Output, 0, (void*)&bufferSize, sizeof(bufferSize));
+ ASSERT(!result);
+}
+
+void AudioDestinationMac::start()
+{
+ OSStatus result = AudioOutputUnitStart(m_outputUnit);
+
+ if (!result)
+ m_isPlaying = true;
+}
+
+void AudioDestinationMac::stop()
+{
+ OSStatus result = AudioOutputUnitStop(m_outputUnit);
+
+ if (!result)
+ m_isPlaying = false;
+}
+
+// Pulls on our provider to get rendered audio stream.
+OSStatus AudioDestinationMac::render(UInt32 numberOfFrames, AudioBufferList* ioData)
+{
+ AudioBuffer* buffers = ioData->mBuffers;
+ m_renderBus.setChannelMemory(0, (float*)buffers[0].mData, numberOfFrames);
+ m_renderBus.setChannelMemory(1, (float*)buffers[1].mData, numberOfFrames);
+
+ m_provider.provideInput(&m_renderBus, numberOfFrames);
+
+ return noErr;
+}
+
+// DefaultOutputUnit callback
+OSStatus AudioDestinationMac::inputProc(void* userData, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32 /*busNumber*/, UInt32 numberOfFrames, AudioBufferList* ioData)
+{
+ AudioDestinationMac* audioOutput = static_cast<AudioDestinationMac*>(userData);
+ return audioOutput->render(numberOfFrames, ioData);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/mac/AudioDestinationMac.h b/Source/WebCore/platform/audio/mac/AudioDestinationMac.h
new file mode 100644
index 0000000..197440c
--- /dev/null
+++ b/Source/WebCore/platform/audio/mac/AudioDestinationMac.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 AudioDestinationMac_h
+#define AudioDestinationMac_h
+
+#include "AudioBus.h"
+#include "AudioDestination.h"
+#include <AudioUnit/AudioUnit.h>
+
+namespace WebCore {
+
+// An AudioDestination using CoreAudio's default output AudioUnit
+
+class AudioDestinationMac : public AudioDestination {
+public:
+ AudioDestinationMac(AudioSourceProvider&, double sampleRate);
+ virtual ~AudioDestinationMac();
+
+ virtual void start();
+ virtual void stop();
+ bool isPlaying() { return m_isPlaying; }
+
+ double sampleRate() const { return m_sampleRate; }
+
+private:
+ void configure();
+
+ // DefaultOutputUnit callback
+ static OSStatus inputProc(void* userData, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32 busNumber, UInt32 numberOfFrames, AudioBufferList* ioData);
+
+ OSStatus render(UInt32 numberOfFrames, AudioBufferList* ioData);
+
+ AudioUnit m_outputUnit;
+ AudioSourceProvider& m_provider;
+ AudioBus m_renderBus;
+
+ double m_sampleRate;
+ bool m_isPlaying;
+};
+
+} // namespace WebCore
+
+#endif // AudioDestinationMac_h
diff --git a/Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp b/Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp
new file mode 100644
index 0000000..6d17152
--- /dev/null
+++ b/Source/WebCore/platform/audio/mac/AudioFileReaderMac.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioFileReaderMac.h"
+
+#include "AudioBus.h"
+#include "AudioFileReader.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+
+namespace WebCore {
+
+static AudioBufferList* createAudioBufferList(size_t numberOfBuffers)
+{
+ size_t bufferListSize = sizeof(AudioBufferList) - sizeof(AudioBuffer);
+ bufferListSize += numberOfBuffers * sizeof(AudioBuffer);
+
+ AudioBufferList* bufferList = static_cast<AudioBufferList*>(calloc(1, bufferListSize));
+ if (bufferList)
+ bufferList->mNumberBuffers = numberOfBuffers;
+
+ return bufferList;
+}
+
+static void destroyAudioBufferList(AudioBufferList* bufferList)
+{
+ free(bufferList);
+}
+
+AudioFileReader::AudioFileReader(const char* filePath)
+ : m_data(0)
+ , m_dataSize(0)
+ , m_filePath(filePath)
+ , m_audioFileID(0)
+ , m_extAudioFileRef(0)
+{
+ FSRef fsref;
+ OSStatus result = FSPathMakeRef((UInt8*)filePath, &fsref, 0);
+ if (result != noErr)
+ return;
+
+ CFURLRef urlRef = CFURLCreateFromFSRef(0, &fsref);
+ if (!urlRef)
+ return;
+
+ ExtAudioFileOpenURL(urlRef, &m_extAudioFileRef);
+
+ if (urlRef)
+ CFRelease(urlRef);
+}
+
+AudioFileReader::AudioFileReader(const void* data, size_t dataSize)
+ : m_data(data)
+ , m_dataSize(dataSize)
+ , m_filePath(0)
+ , m_audioFileID(0)
+ , m_extAudioFileRef(0)
+{
+ OSStatus result = AudioFileOpenWithCallbacks(this, readProc, 0, getSizeProc, 0, 0, &m_audioFileID);
+
+ if (result != noErr)
+ return;
+
+ result = ExtAudioFileWrapAudioFileID(m_audioFileID, false, &m_extAudioFileRef);
+ if (result != noErr)
+ m_extAudioFileRef = 0;
+}
+
+AudioFileReader::~AudioFileReader()
+{
+ if (m_extAudioFileRef)
+ ExtAudioFileDispose(m_extAudioFileRef);
+
+ m_extAudioFileRef = 0;
+
+ if (m_audioFileID)
+ AudioFileClose(m_audioFileID);
+
+ m_audioFileID = 0;
+}
+
+OSStatus AudioFileReader::readProc(void* clientData, SInt64 position, UInt32 requestCount, void* buffer, UInt32* actualCount)
+{
+ AudioFileReader* audioFileReader = static_cast<AudioFileReader*>(clientData);
+
+ size_t dataSize = audioFileReader->dataSize();
+ const void* data = audioFileReader->data();
+ size_t bytesToRead = 0;
+
+ if (static_cast<UInt64>(position) < dataSize) {
+ size_t bytesAvailable = dataSize - static_cast<size_t>(position);
+ bytesToRead = requestCount <= bytesAvailable ? requestCount : bytesAvailable;
+ memcpy(buffer, static_cast<const char*>(data) + position, bytesToRead);
+ } else
+ bytesToRead = 0;
+
+ if (actualCount)
+ *actualCount = bytesToRead;
+
+ return noErr;
+}
+
+SInt64 AudioFileReader::getSizeProc(void* clientData)
+{
+ AudioFileReader* audioFileReader = static_cast<AudioFileReader*>(clientData);
+ return audioFileReader->dataSize();
+}
+
+PassOwnPtr<AudioBus> AudioFileReader::createBus(double sampleRate, bool mixToMono)
+{
+ if (!m_extAudioFileRef)
+ return 0;
+
+ // Get file's data format
+ UInt32 size = sizeof(m_fileDataFormat);
+ OSStatus result = ExtAudioFileGetProperty(m_extAudioFileRef, kExtAudioFileProperty_FileDataFormat, &size, &m_fileDataFormat);
+ if (result != noErr)
+ return 0;
+
+ // Number of channels
+ size_t numberOfChannels = m_fileDataFormat.mChannelsPerFrame;
+
+ // Number of frames
+ SInt64 numberOfFrames64 = 0;
+ size = sizeof(numberOfFrames64);
+ result = ExtAudioFileGetProperty(m_extAudioFileRef, kExtAudioFileProperty_FileLengthFrames, &size, &numberOfFrames64);
+ if (result != noErr)
+ return 0;
+
+ // Sample-rate
+ double fileSampleRate = m_fileDataFormat.mSampleRate;
+
+ // Make client format same number of channels as file format, but tweak a few things.
+ // Client format will be linear PCM (canonical), and potentially change sample-rate.
+ m_clientDataFormat = m_fileDataFormat;
+
+ m_clientDataFormat.mFormatID = kAudioFormatLinearPCM;
+ m_clientDataFormat.mFormatFlags = kAudioFormatFlagsCanonical;
+ m_clientDataFormat.mBitsPerChannel = 8 * sizeof(AudioSampleType);
+ m_clientDataFormat.mChannelsPerFrame = numberOfChannels;
+ m_clientDataFormat.mFramesPerPacket = 1;
+ m_clientDataFormat.mBytesPerPacket = sizeof(AudioSampleType);
+ m_clientDataFormat.mBytesPerFrame = sizeof(AudioSampleType);
+ m_clientDataFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
+
+ if (sampleRate)
+ m_clientDataFormat.mSampleRate = sampleRate;
+
+ result = ExtAudioFileSetProperty(m_extAudioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &m_clientDataFormat);
+ if (result != noErr)
+ return 0;
+
+ // Change numberOfFrames64 to destination sample-rate
+ numberOfFrames64 = numberOfFrames64 * (m_clientDataFormat.mSampleRate / fileSampleRate);
+ size_t numberOfFrames = static_cast<size_t>(numberOfFrames64);
+
+ size_t busChannelCount = mixToMono ? 1 : numberOfChannels;
+
+ // Create AudioBus where we'll put the PCM audio data
+ OwnPtr<AudioBus> audioBus = adoptPtr(new AudioBus(busChannelCount, numberOfFrames));
+ audioBus->setSampleRate(m_clientDataFormat.mSampleRate); // save for later
+
+ // Only allocated in the mixToMono case
+ AudioFloatArray bufL;
+ AudioFloatArray bufR;
+ float* bufferL = 0;
+ float* bufferR = 0;
+
+ // Setup AudioBufferList in preparation for reading
+ AudioBufferList* bufferList = createAudioBufferList(numberOfChannels);
+
+ if (mixToMono && numberOfChannels == 2) {
+ bufL.resize(numberOfFrames);
+ bufR.resize(numberOfFrames);
+ bufferL = bufL.data();
+ bufferR = bufR.data();
+
+ bufferList->mBuffers[0].mNumberChannels = 1;
+ bufferList->mBuffers[0].mDataByteSize = numberOfFrames * sizeof(float);
+ bufferList->mBuffers[0].mData = bufferL;
+
+ bufferList->mBuffers[1].mNumberChannels = 1;
+ bufferList->mBuffers[1].mDataByteSize = numberOfFrames * sizeof(float);
+ bufferList->mBuffers[1].mData = bufferR;
+ } else {
+ ASSERT(!mixToMono || numberOfChannels == 1);
+
+ // for True-stereo (numberOfChannels == 4)
+ for (size_t i = 0; i < numberOfChannels; ++i) {
+ bufferList->mBuffers[i].mNumberChannels = 1;
+ bufferList->mBuffers[i].mDataByteSize = numberOfFrames * sizeof(float);
+ bufferList->mBuffers[i].mData = audioBus->channel(i)->data();
+ }
+ }
+
+ // Read from the file (or in-memory version)
+ UInt32 framesToRead = numberOfFrames;
+ result = ExtAudioFileRead(m_extAudioFileRef, &framesToRead, bufferList);
+ if (result != noErr)
+ return 0;
+
+ if (mixToMono && numberOfChannels == 2) {
+ // Mix stereo down to mono
+ float* destL = audioBus->channel(0)->data();
+ for (size_t i = 0; i < numberOfFrames; i++)
+ destL[i] = 0.5f * (bufferL[i] + bufferR[i]);
+ }
+
+ // Cleanup
+ destroyAudioBufferList(bufferList);
+
+ return audioBus.release();
+}
+
+PassOwnPtr<AudioBus> createBusFromAudioFile(const char* filePath, bool mixToMono, double sampleRate)
+{
+ AudioFileReader reader(filePath);
+ return reader.createBus(sampleRate, mixToMono);
+}
+
+PassOwnPtr<AudioBus> createBusFromInMemoryAudioFile(const void* data, size_t dataSize, bool mixToMono, double sampleRate)
+{
+ AudioFileReader reader(data, dataSize);
+ return reader.createBus(sampleRate, mixToMono);
+}
+
+} // WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/mac/AudioFileReaderMac.h b/Source/WebCore/platform/audio/mac/AudioFileReaderMac.h
new file mode 100644
index 0000000..d531266
--- /dev/null
+++ b/Source/WebCore/platform/audio/mac/AudioFileReaderMac.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 AudioFileReaderMac_h
+#define AudioFileReaderMac_h
+
+#include <AudioToolbox/AudioFile.h>
+#include <AudioToolbox/ExtendedAudioFile.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class AudioBus;
+
+// Wrapper class for AudioFile and ExtAudioFile CoreAudio APIs for reading files and in-memory versions of them...
+
+class AudioFileReader {
+public:
+ AudioFileReader(const char* filePath);
+ AudioFileReader(const void* data, size_t dataSize);
+ ~AudioFileReader();
+
+ // Returns 0 if error
+ PassOwnPtr<AudioBus> createBus(double sampleRate, bool mixToMono);
+
+ const void* data() const { return m_data; }
+ size_t dataSize() const { return m_dataSize; }
+
+private:
+ static OSStatus readProc(void* clientData, SInt64 position, UInt32 requestCount, void* buffer, UInt32* actualCount);
+ static SInt64 getSizeProc(void* clientData);
+
+ const void* m_data;
+ size_t m_dataSize;
+ const char* m_filePath;
+
+ AudioFileID m_audioFileID;
+ ExtAudioFileRef m_extAudioFileRef;
+
+ AudioStreamBasicDescription m_fileDataFormat;
+ AudioStreamBasicDescription m_clientDataFormat;
+};
+
+} // namespace WebCore
+
+#endif // AudioFileReaderMac_h
diff --git a/Source/WebCore/platform/audio/mac/FFTFrameMac.cpp b/Source/WebCore/platform/audio/mac/FFTFrameMac.cpp
new file mode 100644
index 0000000..0f7efb7
--- /dev/null
+++ b/Source/WebCore/platform/audio/mac/FFTFrameMac.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+// Mac OS X - specific FFTFrame implementation
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "FFTFrame.h"
+
+namespace WebCore {
+
+const int kMaxFFTPow2Size = 24;
+
+FFTSetup* FFTFrame::fftSetups = 0;
+
+// Normal constructor: allocates for a given fftSize
+FFTFrame::FFTFrame(unsigned fftSize)
+ : m_realData(fftSize)
+ , m_imagData(fftSize)
+{
+ m_FFTSize = fftSize;
+ m_log2FFTSize = static_cast<unsigned>(log2(fftSize));
+
+ // We only allow power of two
+ ASSERT(1UL << m_log2FFTSize == m_FFTSize);
+
+ // Lazily create and share fftSetup with other frames
+ m_FFTSetup = fftSetupForSize(fftSize);
+
+ // Setup frame data
+ m_frame.realp = m_realData.data();
+ m_frame.imagp = m_imagData.data();
+}
+
+// Creates a blank/empty frame (interpolate() must later be called)
+FFTFrame::FFTFrame()
+ : m_realData(0)
+ , m_imagData(0)
+{
+ // Later will be set to correct values when interpolate() is called
+ m_frame.realp = 0;
+ m_frame.imagp = 0;
+
+ m_FFTSize = 0;
+ m_log2FFTSize = 0;
+}
+
+// Copy constructor
+FFTFrame::FFTFrame(const FFTFrame& frame)
+ : m_FFTSize(frame.m_FFTSize)
+ , m_log2FFTSize(frame.m_log2FFTSize)
+ , m_FFTSetup(frame.m_FFTSetup)
+ , m_realData(frame.m_FFTSize)
+ , m_imagData(frame.m_FFTSize)
+{
+ // Setup frame data
+ m_frame.realp = m_realData.data();
+ m_frame.imagp = m_imagData.data();
+
+ // Copy/setup frame data
+ unsigned nbytes = sizeof(float) * m_FFTSize;
+ memcpy(realData(), frame.m_frame.realp, nbytes);
+ memcpy(imagData(), frame.m_frame.imagp, nbytes);
+}
+
+FFTFrame::~FFTFrame()
+{
+}
+
+void FFTFrame::multiply(const FFTFrame& frame)
+{
+ FFTFrame& frame1 = *this;
+ const FFTFrame& frame2 = frame;
+
+ float* realP1 = frame1.realData();
+ float* imagP1 = frame1.imagData();
+ const float* realP2 = frame2.realData();
+ const float* imagP2 = frame2.imagData();
+
+ // Scale accounts for vecLib's peculiar scaling
+ // This ensures the right scaling all the way back to inverse FFT
+ float scale = 0.5f;
+
+ // Multiply packed DC/nyquist component
+ realP1[0] *= scale * realP2[0];
+ imagP1[0] *= scale * imagP2[0];
+
+ // Multiply the rest, skipping packed DC/Nyquist components
+ DSPSplitComplex sc1 = frame1.dspSplitComplex();
+ sc1.realp++;
+ sc1.imagp++;
+
+ DSPSplitComplex sc2 = frame2.dspSplitComplex();
+ sc2.realp++;
+ sc2.imagp++;
+
+ unsigned halfSize = m_FFTSize / 2;
+
+ // Complex multiply
+ vDSP_zvmul(&sc1, 1, &sc2, 1, &sc1, 1, halfSize - 1, 1 /* normal multiplication */);
+
+ // We've previously scaled the packed part, now scale the rest.....
+ vDSP_vsmul(sc1.realp, 1, &scale, sc1.realp, 1, halfSize - 1);
+ vDSP_vsmul(sc1.imagp, 1, &scale, sc1.imagp, 1, halfSize - 1);
+}
+
+void FFTFrame::doFFT(float* data)
+{
+ vDSP_ctoz((DSPComplex*)data, 2, &m_frame, 1, m_FFTSize / 2);
+ vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_FORWARD);
+}
+
+void FFTFrame::doInverseFFT(float* data)
+{
+ vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_INVERSE);
+ vDSP_ztoc(&m_frame, 1, (DSPComplex*)data, 2, m_FFTSize / 2);
+
+ // Do final scaling so that x == IFFT(FFT(x))
+ float scale = 0.5f / m_FFTSize;
+ vDSP_vsmul(data, 1, &scale, data, 1, m_FFTSize);
+}
+
+FFTSetup FFTFrame::fftSetupForSize(unsigned fftSize)
+{
+ if (!fftSetups) {
+ fftSetups = (FFTSetup*)malloc(sizeof(FFTSetup) * kMaxFFTPow2Size);
+ memset(fftSetups, 0, sizeof(FFTSetup) * kMaxFFTPow2Size);
+ }
+
+ int pow2size = static_cast<int>(log2(fftSize));
+ ASSERT(pow2size < kMaxFFTPow2Size);
+ if (!fftSetups[pow2size])
+ fftSetups[pow2size] = vDSP_create_fftsetup(pow2size, FFT_RADIX2);
+
+ return fftSetups[pow2size];
+}
+
+void FFTFrame::cleanup()
+{
+ if (!fftSetups)
+ return;
+
+ for (int i = 0; i < kMaxFFTPow2Size; ++i) {
+ if (fftSetups[i])
+ vDSP_destroy_fftsetup(fftSetups[i]);
+ }
+
+ free(fftSetups);
+ fftSetups = 0;
+}
+
+float* FFTFrame::realData() const
+{
+ return m_frame.realp;
+}
+
+float* FFTFrame::imagData() const
+{
+ return m_frame.imagp;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)