summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/audio
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/audio')
-rw-r--r--Source/WebCore/platform/audio/AudioArray.h71
-rw-r--r--Source/WebCore/platform/audio/AudioBus.cpp365
-rw-r--r--Source/WebCore/platform/audio/AudioBus.h141
-rw-r--r--Source/WebCore/platform/audio/AudioChannel.cpp104
-rw-r--r--Source/WebCore/platform/audio/AudioChannel.h112
-rw-r--r--Source/WebCore/platform/audio/AudioDSPKernel.h73
-rw-r--r--Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp116
-rw-r--r--Source/WebCore/platform/audio/AudioDSPKernelProcessor.h76
-rw-r--r--Source/WebCore/platform/audio/AudioDestination.h59
-rw-r--r--Source/WebCore/platform/audio/AudioFileReader.h54
-rw-r--r--Source/WebCore/platform/audio/AudioProcessor.h75
-rw-r--r--Source/WebCore/platform/audio/AudioResampler.cpp128
-rw-r--r--Source/WebCore/platform/audio/AudioResampler.h68
-rw-r--r--Source/WebCore/platform/audio/AudioResamplerKernel.cpp143
-rw-r--r--Source/WebCore/platform/audio/AudioResamplerKernel.h76
-rw-r--r--Source/WebCore/platform/audio/AudioSourceProvider.h46
-rw-r--r--Source/WebCore/platform/audio/AudioUtilities.cpp63
-rw-r--r--Source/WebCore/platform/audio/AudioUtilities.h45
-rw-r--r--Source/WebCore/platform/audio/Biquad.cpp282
-rw-r--r--Source/WebCore/platform/audio/Biquad.h99
-rw-r--r--Source/WebCore/platform/audio/Cone.cpp85
-rw-r--r--Source/WebCore/platform/audio/Cone.h63
-rw-r--r--Source/WebCore/platform/audio/Distance.cpp93
-rw-r--r--Source/WebCore/platform/audio/Distance.h80
-rw-r--r--Source/WebCore/platform/audio/EqualPowerPanner.cpp112
-rw-r--r--Source/WebCore/platform/audio/EqualPowerPanner.h53
-rw-r--r--Source/WebCore/platform/audio/FFTConvolver.cpp110
-rw-r--r--Source/WebCore/platform/audio/FFTConvolver.h71
-rw-r--r--Source/WebCore/platform/audio/FFTFrame.cpp269
-rw-r--r--Source/WebCore/platform/audio/FFTFrame.h123
-rw-r--r--Source/WebCore/platform/audio/HRTFDatabase.cpp124
-rw-r--r--Source/WebCore/platform/audio/HRTFDatabase.h87
-rw-r--r--Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp133
-rw-r--r--Source/WebCore/platform/audio/HRTFDatabaseLoader.h85
-rw-r--r--Source/WebCore/platform/audio/HRTFElevation.cpp266
-rw-r--r--Source/WebCore/platform/audio/HRTFElevation.h110
-rw-r--r--Source/WebCore/platform/audio/HRTFKernel.cpp141
-rw-r--r--Source/WebCore/platform/audio/HRTFKernel.h98
-rw-r--r--Source/WebCore/platform/audio/HRTFPanner.cpp229
-rw-r--r--Source/WebCore/platform/audio/HRTFPanner.h68
-rw-r--r--Source/WebCore/platform/audio/Panner.cpp66
-rw-r--r--Source/WebCore/platform/audio/Panner.h68
-rw-r--r--Source/WebCore/platform/audio/Reverb.cpp227
-rw-r--r--Source/WebCore/platform/audio/Reverb.h66
-rw-r--r--Source/WebCore/platform/audio/ReverbAccumulationBuffer.cpp119
-rw-r--r--Source/WebCore/platform/audio/ReverbAccumulationBuffer.h67
-rw-r--r--Source/WebCore/platform/audio/ReverbConvolver.cpp230
-rw-r--r--Source/WebCore/platform/audio/ReverbConvolver.h97
-rw-r--r--Source/WebCore/platform/audio/ReverbConvolverStage.cpp165
-rw-r--r--Source/WebCore/platform/audio/ReverbConvolverStage.h83
-rw-r--r--Source/WebCore/platform/audio/ReverbInputBuffer.cpp89
-rw-r--r--Source/WebCore/platform/audio/ReverbInputBuffer.h64
-rw-r--r--Source/WebCore/platform/audio/VectorMath.cpp94
-rw-r--r--Source/WebCore/platform/audio/VectorMath.h41
-rw-r--r--Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp61
-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
-rw-r--r--Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp260
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P345.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P000.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P015.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P030.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P045.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P060.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P075.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P090.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P315.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P330.wavbin0 -> 1068 bytes
-rw-r--r--Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P345.wavbin0 -> 1068 bytes
302 files changed, 7219 insertions, 0 deletions
diff --git a/Source/WebCore/platform/audio/AudioArray.h b/Source/WebCore/platform/audio/AudioArray.h
new file mode 100644
index 0000000..9c25b0f
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioArray.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 AudioArray_h
+#define AudioArray_h
+
+#include <string.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+template<typename T>
+class AudioArray : public Vector<T> {
+public:
+ AudioArray() : Vector<T>(0) { }
+ explicit AudioArray(size_t n) : Vector<T>(n, 0) { }
+
+ void zero() { memset(this->data(), 0, sizeof(T) * this->size()); }
+
+ void zeroRange(unsigned start, unsigned end)
+ {
+ bool isSafe = (start <= end) && (end <= this->size());
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ memset(this->data() + start, 0, sizeof(T) * (end - start));
+ }
+
+ void copyToRange(T* sourceData, unsigned start, unsigned end)
+ {
+ bool isSafe = (start <= end) && (end <= this->size());
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ memcpy(this->data() + start, sourceData, sizeof(T) * (end - start));
+ }
+};
+
+typedef AudioArray<float> AudioFloatArray;
+typedef AudioArray<double> AudioDoubleArray;
+
+} // WebCore
+
+#endif // AudioArray_h
diff --git a/Source/WebCore/platform/audio/AudioBus.cpp b/Source/WebCore/platform/audio/AudioBus.cpp
new file mode 100644
index 0000000..dd4746d
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioBus.cpp
@@ -0,0 +1,365 @@
+/*
+ * 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 "AudioBus.h"
+
+#include "VectorMath.h"
+#include <algorithm>
+#include <assert.h>
+#include <math.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace VectorMath;
+
+AudioBus::AudioBus(unsigned numberOfChannels, size_t length, bool allocate)
+ : m_length(length)
+ , m_busGain(1.0)
+ , m_isFirstTime(true)
+ , m_sampleRate(0.0)
+{
+ m_channels.reserveInitialCapacity(numberOfChannels);
+
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ PassOwnPtr<AudioChannel> channel = allocate ? adoptPtr(new AudioChannel(length)) : adoptPtr(new AudioChannel(0, length));
+ m_channels.append(channel);
+ }
+
+ m_layout = LayoutCanonical; // for now this is the only layout we define
+}
+
+void AudioBus::setChannelMemory(unsigned channelIndex, float* storage, size_t length)
+{
+ if (channelIndex < m_channels.size()) {
+ channel(channelIndex)->set(storage, length);
+ m_length = length; // FIXME: verify that this length matches all the other channel lengths
+ }
+}
+
+void AudioBus::zero()
+{
+ for (unsigned i = 0; i < m_channels.size(); ++i)
+ m_channels[i]->zero();
+}
+
+AudioChannel* AudioBus::channelByType(unsigned channelType)
+{
+ // For now we only support canonical channel layouts...
+ if (m_layout != LayoutCanonical)
+ return 0;
+
+ switch (numberOfChannels()) {
+ case 1: // mono
+ if (channelType == ChannelMono || channelType == ChannelLeft)
+ return channel(0);
+ return 0;
+
+ case 2: // stereo
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ default: return 0;
+ }
+
+ case 4: // quad
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ case ChannelSurroundLeft: return channel(2);
+ case ChannelSurroundRight: return channel(3);
+ default: return 0;
+ }
+
+ case 5: // 5.0
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ case ChannelCenter: return channel(2);
+ case ChannelSurroundLeft: return channel(3);
+ case ChannelSurroundRight: return channel(4);
+ default: return 0;
+ }
+
+ case 6: // 5.1
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ case ChannelCenter: return channel(2);
+ case ChannelLFE: return channel(3);
+ case ChannelSurroundLeft: return channel(4);
+ case ChannelSurroundRight: return channel(5);
+ default: return 0;
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+// Returns true if the channel count and frame-size match.
+bool AudioBus::topologyMatches(const AudioBus& bus) const
+{
+ if (numberOfChannels() != bus.numberOfChannels())
+ return false; // channel mismatch
+
+ // Make sure source bus has enough frames.
+ if (length() > bus.length())
+ return false; // frame-size mismatch
+
+ return true;
+}
+
+PassOwnPtr<AudioBus> AudioBus::createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame)
+{
+ size_t numberOfSourceFrames = sourceBuffer->length();
+ unsigned numberOfChannels = sourceBuffer->numberOfChannels();
+
+ // Sanity checking
+ bool isRangeSafe = startFrame < endFrame && endFrame <= numberOfSourceFrames;
+ ASSERT(isRangeSafe);
+ if (!isRangeSafe)
+ return 0;
+
+ size_t rangeLength = endFrame - startFrame;
+
+ OwnPtr<AudioBus> audioBus = adoptPtr(new AudioBus(numberOfChannels, rangeLength));
+ audioBus->setSampleRate(sourceBuffer->sampleRate());
+
+ for (unsigned i = 0; i < numberOfChannels; ++i)
+ audioBus->channel(i)->copyFromRange(sourceBuffer->channel(i), startFrame, endFrame);
+
+ return audioBus.release();
+}
+
+float AudioBus::maxAbsValue() const
+{
+ float max = 0.0f;
+ for (unsigned i = 0; i < numberOfChannels(); ++i) {
+ const AudioChannel* channel = this->channel(i);
+ max = std::max(max, channel->maxAbsValue());
+ }
+
+ return max;
+}
+
+void AudioBus::normalize()
+{
+ float max = maxAbsValue();
+ if (max)
+ scale(1.0f / max);
+}
+
+void AudioBus::scale(double scale)
+{
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ channel(i)->scale(scale);
+}
+
+// Just copies the samples from the source bus to this one.
+// This is just a simple copy if the number of channels match, otherwise a mixup or mixdown is done.
+// For now, we just support a mixup from mono -> stereo.
+void AudioBus::copyFrom(const AudioBus& sourceBus)
+{
+ if (&sourceBus == this)
+ return;
+
+ if (numberOfChannels() == sourceBus.numberOfChannels()) {
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ channel(i)->copyFrom(sourceBus.channel(i));
+ } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
+ // Handle mono -> stereo case (for now simply copy mono channel into both left and right)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ const AudioChannel* sourceChannel = sourceBus.channel(0);
+ channel(0)->copyFrom(sourceChannel);
+ channel(1)->copyFrom(sourceChannel);
+ } else {
+ // Case not handled
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void AudioBus::sumFrom(const AudioBus &sourceBus)
+{
+ if (numberOfChannels() == sourceBus.numberOfChannels()) {
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ channel(i)->sumFrom(sourceBus.channel(i));
+ } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
+ // Handle mono -> stereo case (for now simply sum mono channel into both left and right)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ const AudioChannel* sourceChannel = sourceBus.channel(0);
+ channel(0)->sumFrom(sourceChannel);
+ channel(1)->sumFrom(sourceChannel);
+ } else {
+ // Case not handled
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
+{
+ // We don't want to suddenly change the gain from mixing one time slice to the next,
+ // so we "de-zipper" by slowly changing the gain each sample-frame until we've achieved the target gain.
+
+ // FIXME: optimize this method (SSE, etc.)
+ // FIXME: Need fast path here when gain has converged on targetGain. In this case, de-zippering is no longer needed.
+ // FIXME: Need fast path when this==sourceBus && lastMixGain==targetGain==1.0 && sumToBus==false (this is a NOP)
+
+ // Take master bus gain into account as well as the targetGain.
+ double totalDesiredGain = m_busGain * targetGain;
+
+ // First time, snap directly to totalDesiredGain.
+ double gain = m_isFirstTime ? totalDesiredGain : *lastMixGain;
+ m_isFirstTime = false;
+
+ int numberOfSourceChannels = sourceBus.numberOfChannels();
+ int numberOfDestinationChannels = numberOfChannels();
+
+ AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
+ const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
+ const float* sourceR = numberOfSourceChannels > 1 ? sourceBusSafe.channelByType(ChannelRight)->data() : 0;
+
+ float* destinationL = channelByType(ChannelLeft)->data();
+ float* destinationR = numberOfDestinationChannels > 1 ? channelByType(ChannelRight)->data() : 0;
+
+ const double DezipperRate = 0.005;
+ int framesToProcess = length();
+
+ if (sumToBus) {
+ // Sum to our bus
+ if (sourceR && destinationR) {
+ // Stereo
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ float sampleR = *sourceR++;
+ *destinationL++ += static_cast<float>(gain * sampleL);
+ *destinationR++ += static_cast<float>(gain * sampleR);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else if (destinationR) {
+ // Mono -> stereo (mix equally into L and R)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ while (framesToProcess--) {
+ float sample = *sourceL++;
+ *destinationL++ += static_cast<float>(gain * sample);
+ *destinationR++ += static_cast<float>(gain * sample);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else {
+ // Mono
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ *destinationL++ += static_cast<float>(gain * sampleL);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ }
+ } else {
+ // Process directly (without summing) to our bus
+ if (sourceR && destinationR) {
+ // Stereo
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ float sampleR = *sourceR++;
+ *destinationL++ = static_cast<float>(gain * sampleL);
+ *destinationR++ = static_cast<float>(gain * sampleR);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else if (destinationR) {
+ // Mono -> stereo (mix equally into L and R)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ while (framesToProcess--) {
+ float sample = *sourceL++;
+ *destinationL++ = static_cast<float>(gain * sample);
+ *destinationR++ = static_cast<float>(gain * sample);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else {
+ // Mono
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ *destinationL++ = static_cast<float>(gain * sampleL);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ }
+ }
+
+ // Save the target gain as the starting point for next time around.
+ *lastMixGain = gain;
+}
+
+void AudioBus::processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
+{
+ // Make sure we're summing from same type of bus.
+ // We *are* able to sum from mono -> stereo
+ if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus))
+ return;
+
+ // Dispatch for different channel layouts
+ switch (numberOfChannels()) {
+ case 1: // mono
+ case 2: // stereo
+ processWithGainFromMonoStereo(sourceBus, lastMixGain, targetGain, sumToBus);
+ break;
+ case 4: // FIXME: implement quad
+ case 5: // FIXME: implement 5.0
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
+{
+ processWithGainFrom(sourceBus, lastMixGain, targetGain, false);
+}
+
+void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
+{
+ processWithGainFrom(sourceBus, lastMixGain, targetGain, true);
+}
+
+} // WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/AudioBus.h b/Source/WebCore/platform/audio/AudioBus.h
new file mode 100644
index 0000000..4318b81
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioBus.h
@@ -0,0 +1,141 @@
+/*
+ * 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 AudioBus_h
+#define AudioBus_h
+
+#include "AudioChannel.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// An AudioBus represents a collection of one or more AudioChannels.
+// The data layout is "planar" as opposed to "interleaved".
+// An AudioBus with one channel is mono, an AudioBus with two channels is stereo, etc.
+class AudioBus : public Noncopyable {
+public:
+ enum {
+ ChannelLeft = 0,
+ ChannelRight = 1,
+ ChannelCenter = 2, // center and mono are the same
+ ChannelMono = 2,
+ ChannelLFE = 3,
+ ChannelSurroundLeft = 4,
+ ChannelSurroundRight = 5,
+ };
+
+ enum {
+ LayoutCanonical = 0
+ // Can define non-standard layouts here
+ };
+
+ // allocate indicates whether or not to initially have the AudioChannels created with managed storage.
+ // Normal usage is to pass true here, in which case the AudioChannels will memory-manage their own storage.
+ // If allocate is false then setChannelMemory() has to be called later on for each channel before the AudioBus is useable...
+ AudioBus(unsigned numberOfChannels, size_t length, bool allocate = true);
+
+ // Tells the given channel to use an externally allocated buffer.
+ void setChannelMemory(unsigned channelIndex, float* storage, size_t length);
+
+ // Channels
+ unsigned numberOfChannels() const { return m_channels.size(); }
+
+ AudioChannel* channel(unsigned channel) { return m_channels[channel].get(); }
+ const AudioChannel* channel(unsigned channel) const { return const_cast<AudioBus*>(this)->m_channels[channel].get(); }
+ AudioChannel* channelByType(unsigned type);
+
+ // Number of sample-frames
+ size_t length() const { return m_length; }
+
+ // Sample-rate : 0.0 if unknown or "don't care"
+ double sampleRate() const { return m_sampleRate; }
+ void setSampleRate(double sampleRate) { m_sampleRate = sampleRate; }
+
+ // Zeroes all channels.
+ void zero();
+
+ // Returns true if the channel count and frame-size match.
+ bool topologyMatches(const AudioBus &sourceBus) const;
+
+ // Creates a new buffer from a range in the source buffer.
+ // 0 may be returned if the range does not fit in the sourceBuffer
+ static PassOwnPtr<AudioBus> createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame);
+
+ // Scales all samples by the same amount.
+ void scale(double scale);
+
+ // Master gain for this bus - used with sumWithGainFrom() below
+ void setGain(double gain) { m_busGain = gain; }
+ double gain() { return m_busGain; }
+
+ void reset() { m_isFirstTime = true; } // for de-zippering
+
+ // Assuming sourceBus has the same topology, copies sample data from each channel of sourceBus to our corresponding channel.
+ void copyFrom(const AudioBus &sourceBus);
+
+ // Sums the sourceBus into our bus with unity gain.
+ // Our own internal gain m_busGain is ignored.
+ void sumFrom(const AudioBus &sourceBus);
+
+ // Copy or sum each channel from sourceBus into our corresponding channel.
+ // We scale by targetGain (and our own internal gain m_busGain), performing "de-zippering" to smoothly change from *lastMixGain to (targetGain*m_busGain).
+ // The caller is responsible for setting up lastMixGain to point to storage which is unique for every "stream" which will be summed to this bus.
+ // This represents the dezippering memory.
+ void copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain);
+ void sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain);
+
+ // Returns maximum absolute value across all channels (useful for normalization).
+ float maxAbsValue() const;
+
+ // Makes maximum absolute value == 1.0 (if possible).
+ void normalize();
+
+ static PassOwnPtr<AudioBus> loadPlatformResource(const char* name, double sampleRate);
+
+protected:
+ AudioBus() { };
+
+ void processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus);
+ void processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus);
+
+ size_t m_length;
+
+ Vector<OwnPtr<AudioChannel> > m_channels;
+
+ int m_layout;
+
+ double m_busGain;
+ bool m_isFirstTime;
+ double m_sampleRate; // 0.0 if unknown or N/A
+};
+
+} // WebCore
+
+#endif // AudioBus_h
diff --git a/Source/WebCore/platform/audio/AudioChannel.cpp b/Source/WebCore/platform/audio/AudioChannel.cpp
new file mode 100644
index 0000000..a962deb
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioChannel.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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 "AudioChannel.h"
+
+#include "VectorMath.h"
+#include <algorithm>
+#include <math.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+using namespace VectorMath;
+
+void AudioChannel::scale(double scale)
+{
+ float s = static_cast<float>(scale);
+ vsmul(data(), 1, &s, data(), 1, length());
+}
+
+void AudioChannel::copyFrom(const AudioChannel* sourceChannel)
+{
+ bool isSafe = (sourceChannel && sourceChannel->length() >= length());
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ memcpy(data(), sourceChannel->data(), sizeof(float) * length());
+}
+
+void AudioChannel::copyFromRange(const AudioChannel* sourceChannel, unsigned startFrame, unsigned endFrame)
+{
+ // Check that range is safe for reading from sourceChannel.
+ bool isRangeSafe = sourceChannel && startFrame < endFrame && endFrame <= sourceChannel->length();
+ ASSERT(isRangeSafe);
+ if (!isRangeSafe)
+ return;
+
+ // Check that this channel has enough space.
+ size_t rangeLength = endFrame - startFrame;
+ bool isRangeLengthSafe = rangeLength <= length();
+ ASSERT(isRangeLengthSafe);
+ if (!isRangeLengthSafe)
+ return;
+
+ const float* source = sourceChannel->data();
+ float* destination = data();
+ memcpy(destination, source + startFrame, sizeof(float) * rangeLength);
+}
+
+void AudioChannel::sumFrom(const AudioChannel* sourceChannel)
+{
+ bool isSafe = sourceChannel && sourceChannel->length() >= length();
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ vadd(data(), 1, sourceChannel->data(), 1, data(), 1, length());
+}
+
+float AudioChannel::maxAbsValue() const
+{
+ const float* p = data();
+ int n = length();
+
+ float max = 0.0f;
+ while (n--)
+ max = std::max(max, fabsf(*p++));
+
+ return max;
+}
+
+} // WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/AudioChannel.h b/Source/WebCore/platform/audio/AudioChannel.h
new file mode 100644
index 0000000..6816830
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioChannel.h
@@ -0,0 +1,112 @@
+/*
+ * 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 AudioChannel_h
+#define AudioChannel_h
+
+#include "AudioArray.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+// An AudioChannel represents a buffer of non-interleaved floating-point audio samples.
+// The PCM samples are normally assumed to be in a nominal range -1.0 -> +1.0
+class AudioChannel : public Noncopyable {
+public:
+ // Memory can be externally referenced, or can be internally allocated with an AudioFloatArray.
+
+ // Reference an external buffer.
+ AudioChannel(float* storage, size_t length)
+ : m_length(length), m_rawPointer(storage) { }
+
+ // Manage storage for us.
+ explicit AudioChannel(size_t length)
+ : m_length(length)
+ , m_rawPointer(0)
+ {
+ m_memBuffer = adoptPtr(new AudioFloatArray(length));
+ }
+
+ // A "blank" audio channel -- must call set() before it's useful...
+ AudioChannel()
+ : m_length(0)
+ , m_rawPointer(0)
+ {
+ }
+
+ // Redefine the memory for this channel.
+ // storage represents external memory not managed by this object.
+ void set(float* storage, size_t length)
+ {
+ m_memBuffer.clear(); // cleanup managed storage
+ m_rawPointer = storage;
+ m_length = length;
+ }
+
+ // How many sample-frames do we contain?
+ size_t length() const { return m_length; }
+
+ // Direct access to PCM sample data
+ float* data() { return m_rawPointer ? m_rawPointer : m_memBuffer->data(); }
+ const float* data() const { return m_rawPointer ? m_rawPointer : m_memBuffer->data(); }
+
+ // Zeroes out all sample values in buffer.
+ void zero()
+ {
+ if (m_memBuffer.get())
+ m_memBuffer->zero();
+ else
+ memset(m_rawPointer, 0, sizeof(float) * m_length);
+ }
+
+ // Scales all samples by the same amount.
+ void scale(double scale);
+
+ // A simple memcpy() from the source channel
+ void copyFrom(const AudioChannel* sourceChannel);
+
+ // Copies the given range from the source channel.
+ void copyFromRange(const AudioChannel* sourceChannel, unsigned startFrame, unsigned endFrame);
+
+ // Sums (with unity gain) from the source channel.
+ void sumFrom(const AudioChannel* sourceChannel);
+
+ // Returns maximum absolute value (useful for normalization).
+ float maxAbsValue() const;
+
+private:
+ size_t m_length;
+
+ float* m_rawPointer;
+ OwnPtr<AudioFloatArray> m_memBuffer;
+};
+
+} // WebCore
+
+#endif // AudioChannel_h
diff --git a/Source/WebCore/platform/audio/AudioDSPKernel.h b/Source/WebCore/platform/audio/AudioDSPKernel.h
new file mode 100644
index 0000000..d0719c5
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioDSPKernel.h
@@ -0,0 +1,73 @@
+/*
+ * 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:
+ *
+ * * 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.
+ * * Neither the name of Google Inc. 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 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
+ * OWNER 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 AudioDSPKernel_h
+#define AudioDSPKernel_h
+
+#include "AudioDSPKernelProcessor.h"
+
+namespace WebCore {
+
+// AudioDSPKernel does the processing for one channel of an AudioDSPKernelProcessor.
+
+class AudioDSPKernel {
+public:
+ AudioDSPKernel(AudioDSPKernelProcessor* kernelProcessor)
+ : m_kernelProcessor(kernelProcessor)
+ , m_sampleRate(kernelProcessor->sampleRate())
+ {
+ }
+
+ AudioDSPKernel(double sampleRate)
+ : m_kernelProcessor(0)
+ , m_sampleRate(sampleRate)
+ {
+ }
+
+ virtual ~AudioDSPKernel() { };
+
+ // Subclasses must override process() to do the processing and reset() to reset DSP state.
+ virtual void process(const float* source, float* destination, size_t framesToProcess) = 0;
+ virtual void reset() = 0;
+
+ double sampleRate() const { return m_sampleRate; }
+ double nyquist() const { return 0.5 * sampleRate(); }
+
+ AudioDSPKernelProcessor* processor() { return m_kernelProcessor; }
+ const AudioDSPKernelProcessor* processor() const { return m_kernelProcessor; }
+
+protected:
+ AudioDSPKernelProcessor* m_kernelProcessor;
+ double m_sampleRate;
+};
+
+} // namespace WebCore
+
+#endif // AudioDSPKernel_h
diff --git a/Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp
new file mode 100644
index 0000000..d79afd5
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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:
+ *
+ * * 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.
+ * * Neither the name of Google Inc. 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 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
+ * OWNER 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 "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioDSPKernelProcessor.h"
+
+#include "AudioDSPKernel.h"
+
+namespace WebCore {
+
+// setNumberOfChannels() may later be called if the object is not yet in an "initialized" state.
+AudioDSPKernelProcessor::AudioDSPKernelProcessor(double sampleRate, unsigned numberOfChannels)
+ : AudioProcessor(sampleRate)
+ , m_numberOfChannels(numberOfChannels)
+ , m_hasJustReset(true)
+{
+}
+
+void AudioDSPKernelProcessor::initialize()
+{
+ if (isInitialized())
+ return;
+
+ ASSERT(!m_kernels.size());
+
+ // Create processing kernels, one per channel.
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ m_kernels.append(createKernel());
+
+ m_initialized = true;
+}
+
+void AudioDSPKernelProcessor::uninitialize()
+{
+ if (!isInitialized())
+ return;
+
+ m_kernels.clear();
+
+ m_initialized = false;
+}
+
+void AudioDSPKernelProcessor::process(AudioBus* source, AudioBus* destination, size_t framesToProcess)
+{
+ ASSERT(source && destination);
+ if (!source || !destination)
+ return;
+
+ if (!isInitialized()) {
+ destination->zero();
+ return;
+ }
+
+ bool channelCountMatches = source->numberOfChannels() == destination->numberOfChannels() && source->numberOfChannels() == m_kernels.size();
+ ASSERT(channelCountMatches);
+ if (!channelCountMatches)
+ return;
+
+ for (unsigned i = 0; i < m_kernels.size(); ++i)
+ m_kernels[i]->process(source->channel(i)->data(), destination->channel(i)->data(), framesToProcess);
+}
+
+// Resets filter state
+void AudioDSPKernelProcessor::reset()
+{
+ if (!isInitialized())
+ return;
+
+ // Forces snap to parameter values - first time.
+ // Any processing depending on this value must set it to false at the appropriate time.
+ m_hasJustReset = true;
+
+ for (unsigned i = 0; i < m_kernels.size(); ++i)
+ m_kernels[i]->reset();
+}
+
+void AudioDSPKernelProcessor::setNumberOfChannels(unsigned numberOfChannels)
+{
+ ASSERT(!isInitialized());
+ if (!isInitialized())
+ m_numberOfChannels = numberOfChannels;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/AudioDSPKernelProcessor.h b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.h
new file mode 100644
index 0000000..e87a810
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioDSPKernelProcessor.h
@@ -0,0 +1,76 @@
+/*
+ * 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:
+ *
+ * * 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.
+ * * Neither the name of Google Inc. 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 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
+ * OWNER 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 AudioDSPKernelProcessor_h
+#define AudioDSPKernelProcessor_h
+
+#include "AudioBus.h"
+#include "AudioProcessor.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AudioBus;
+class AudioDSPKernel;
+class AudioProcessor;
+
+// AudioDSPKernelProcessor processes one input -> one output (N channels each)
+// It uses one AudioDSPKernel object per channel to do the processing, thus there is no cross-channel processing.
+// Despite this limitation it turns out to be a very common and useful type of processor.
+
+class AudioDSPKernelProcessor : public AudioProcessor {
+public:
+ // numberOfChannels may be later changed if object is not yet in an "initialized" state
+ AudioDSPKernelProcessor(double sampleRate, unsigned numberOfChannels);
+
+ // Subclasses create the appropriate type of processing kernel here.
+ // We'll call this to create a kernel for each channel.
+ virtual PassOwnPtr<AudioDSPKernel> createKernel() = 0;
+
+ // AudioProcessor methods
+ virtual void initialize();
+ virtual void uninitialize();
+ virtual void process(AudioBus* source, AudioBus* destination, size_t framesToProcess);
+ virtual void reset();
+ virtual void setNumberOfChannels(unsigned numberOfChannels);
+
+ unsigned numberOfChannels() const { return m_numberOfChannels; }
+
+protected:
+ unsigned m_numberOfChannels;
+ Vector<OwnPtr<AudioDSPKernel> > m_kernels;
+ bool m_hasJustReset;
+};
+
+} // namespace WebCore
+
+#endif // AudioDSPKernelProcessor_h
diff --git a/Source/WebCore/platform/audio/AudioDestination.h b/Source/WebCore/platform/audio/AudioDestination.h
new file mode 100644
index 0000000..9498110
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioDestination.h
@@ -0,0 +1,59 @@
+/*
+ * 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 AudioDestination_h
+#define AudioDestination_h
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class AudioSourceProvider;
+
+// Abstraction for an audio output to the audio hardware
+// An AudioSourceProvider is called back periodically to provide the rendered audio stream.
+
+class AudioDestination {
+public:
+ static PassOwnPtr<AudioDestination> create(AudioSourceProvider&, double sampleRate);
+
+ virtual ~AudioDestination() { }
+
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual bool isPlaying() = 0;
+
+ // Sample-rate conversion may happen in AudioDestination to the hardware sample-rate
+ virtual double sampleRate() const = 0;
+ static double hardwareSampleRate();
+};
+
+} // namespace WebCore
+
+#endif // AudioDestination_h
diff --git a/Source/WebCore/platform/audio/AudioFileReader.h b/Source/WebCore/platform/audio/AudioFileReader.h
new file mode 100644
index 0000000..3c02490
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioFileReader.h
@@ -0,0 +1,54 @@
+/*
+ * 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 AudioFileReader_h
+#define AudioFileReader_h
+
+#include <stdlib.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class AudioBus;
+
+// For both create functions:
+// Pass in 0.0 for sampleRate to use the file's sample-rate, otherwise a sample-rate conversion to the requested
+// sampleRate will be made (if it doesn't already match the file's sample-rate).
+// The created buffer will have its sample-rate set correctly to the result.
+
+PassOwnPtr<AudioBus> createBusFromInMemoryAudioFile(const void* data, size_t dataSize, bool mixToMono, double sampleRate);
+
+PassOwnPtr<AudioBus> createBusFromAudioFile(const char* filePath, bool mixToMono, double sampleRate);
+
+// May pass in 0.0 for sampleRate in which case it will use the AudioBus's sampleRate
+void writeBusToAudioFile(AudioBus* bus, const char* filePath, double fileSampleRate);
+
+} // namespace WebCore
+
+#endif // AudioFileReader_h
diff --git a/Source/WebCore/platform/audio/AudioProcessor.h b/Source/WebCore/platform/audio/AudioProcessor.h
new file mode 100644
index 0000000..69ba40f
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioProcessor.h
@@ -0,0 +1,75 @@
+/*
+ * 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:
+ *
+ * * 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.
+ * * Neither the name of Google Inc. 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 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
+ * OWNER 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 AudioProcessor_h
+#define AudioProcessor_h
+
+namespace WebCore {
+
+class AudioBus;
+
+// AudioProcessor is an abstract base class representing an audio signal processing object with a single input and a single output,
+// where the number of input channels equals the number of output channels. It can be used as one part of a complex DSP algorithm,
+// or as the processor for a basic (one input - one output) AudioNode.
+
+class AudioProcessor {
+public:
+ AudioProcessor(double sampleRate)
+ : m_initialized(false)
+ , m_sampleRate(sampleRate)
+ {
+ }
+
+ virtual ~AudioProcessor() { }
+
+ // Full initialization can be done here instead of in the constructor.
+ virtual void initialize() = 0;
+ virtual void uninitialize() = 0;
+
+ // Processes the source to destination bus. The number of channels must match in source and destination.
+ virtual void process(AudioBus* source, AudioBus* destination, size_t framesToProcess) = 0;
+
+ // Resets filter state
+ virtual void reset() = 0;
+
+ virtual void setNumberOfChannels(unsigned) = 0;
+
+ bool isInitialized() const { return m_initialized; }
+
+ double sampleRate() const { return m_sampleRate; }
+
+protected:
+ bool m_initialized;
+ double m_sampleRate;
+};
+
+} // namespace WebCore
+
+#endif // AudioProcessor_h
diff --git a/Source/WebCore/platform/audio/AudioResampler.cpp b/Source/WebCore/platform/audio/AudioResampler.cpp
new file mode 100644
index 0000000..ba5b58e
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioResampler.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioResampler.h"
+
+#include "AudioBus.h"
+#include <algorithm>
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+const double AudioResampler::MaxRate = 8.0;
+
+AudioResampler::AudioResampler()
+ : m_rate(1.0)
+{
+ m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
+ m_sourceBus = adoptPtr(new AudioBus(1, 0, false));
+}
+
+AudioResampler::AudioResampler(unsigned numberOfChannels)
+ : m_rate(1.0)
+{
+ for (unsigned i = 0; i < numberOfChannels; ++i)
+ m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
+
+ m_sourceBus = adoptPtr(new AudioBus(numberOfChannels, 0, false));
+}
+
+void AudioResampler::configureChannels(unsigned numberOfChannels)
+{
+ unsigned currentSize = m_kernels.size();
+ if (numberOfChannels == currentSize)
+ return; // already setup
+
+ // First deal with adding or removing kernels.
+ if (numberOfChannels > currentSize) {
+ for (unsigned i = currentSize; i < numberOfChannels; ++i)
+ m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
+ } else
+ m_kernels.resize(numberOfChannels);
+
+ // Reconfigure our source bus to the new channel size.
+ m_sourceBus = adoptPtr(new AudioBus(numberOfChannels, 0, false));
+}
+
+void AudioResampler::process(AudioSourceProvider* provider, AudioBus* destinationBus, size_t framesToProcess)
+{
+ ASSERT(provider);
+ if (!provider)
+ return;
+
+ unsigned numberOfChannels = m_kernels.size();
+
+ // Make sure our configuration matches the bus we're rendering to.
+ bool channelsMatch = (destinationBus && destinationBus->numberOfChannels() == numberOfChannels);
+ ASSERT(channelsMatch);
+ if (!channelsMatch)
+ return;
+
+ // Setup the source bus.
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ // Figure out how many frames we need to get from the provider, and a pointer to the buffer.
+ size_t framesNeeded;
+ float* fillPointer = m_kernels[i]->getSourcePointer(framesToProcess, &framesNeeded);
+ ASSERT(fillPointer);
+ if (!fillPointer)
+ return;
+
+ m_sourceBus->setChannelMemory(i, fillPointer, framesNeeded);
+ }
+
+ // Ask the provider to supply the desired number of source frames.
+ provider->provideInput(m_sourceBus.get(), m_sourceBus->length());
+
+ // Now that we have the source data, resample each channel into the destination bus.
+ // FIXME: optimize for the common stereo case where it's faster to process both left/right channels in the same inner loop.
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ float* destination = destinationBus->channel(i)->data();
+ m_kernels[i]->process(destination, framesToProcess);
+ }
+}
+
+void AudioResampler::setRate(double rate)
+{
+ if (isnan(rate) || isinf(rate) || rate <= 0.0)
+ return;
+
+ m_rate = min(AudioResampler::MaxRate, rate);
+}
+
+void AudioResampler::reset()
+{
+ unsigned numberOfChannels = m_kernels.size();
+ for (unsigned i = 0; i < numberOfChannels; ++i)
+ m_kernels[i]->reset();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/AudioResampler.h b/Source/WebCore/platform/audio/AudioResampler.h
new file mode 100644
index 0000000..ed352b8
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioResampler.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef AudioResampler_h
+#define AudioResampler_h
+
+#include "AudioBus.h"
+#include "AudioResamplerKernel.h"
+#include "AudioSourceProvider.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// AudioResampler resamples the audio stream from an AudioSourceProvider.
+// The audio stream may be single or multi-channel.
+// The default constructor defaults to single-channel (mono).
+
+class AudioResampler {
+public:
+ AudioResampler();
+ AudioResampler(unsigned numberOfChannels);
+ ~AudioResampler() { }
+
+ // Given an AudioSourceProvider, process() resamples the source stream into destinationBus.
+ void process(AudioSourceProvider*, AudioBus* destinationBus, size_t framesToProcess);
+
+ // Resets the processing state.
+ void reset();
+
+ void configureChannels(unsigned numberOfChannels);
+
+ // 0 < rate <= MaxRate
+ void setRate(double rate);
+ double rate() const { return m_rate; }
+
+ static const double MaxRate;
+
+private:
+ double m_rate;
+ Vector<OwnPtr<AudioResamplerKernel> > m_kernels;
+ OwnPtr<AudioBus> m_sourceBus;
+};
+
+} // namespace WebCore
+
+#endif // AudioResampler_h
diff --git a/Source/WebCore/platform/audio/AudioResamplerKernel.cpp b/Source/WebCore/platform/audio/AudioResamplerKernel.cpp
new file mode 100644
index 0000000..7b99997
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioResamplerKernel.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioResamplerKernel.h"
+
+#include "AudioResampler.h"
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+const size_t AudioResamplerKernel::MaxFramesToProcess = 128;
+
+AudioResamplerKernel::AudioResamplerKernel(AudioResampler* resampler)
+ : m_resampler(resampler)
+ // The buffer size must be large enough to hold up to two extra sample frames for the linear interpolation.
+ , m_sourceBuffer(2 + static_cast<int>(MaxFramesToProcess * AudioResampler::MaxRate))
+ , m_virtualReadIndex(0.0)
+ , m_fillIndex(0)
+{
+ m_lastValues[0] = 0.0f;
+ m_lastValues[1] = 0.0f;
+}
+
+float* AudioResamplerKernel::getSourcePointer(size_t framesToProcess, size_t* numberOfSourceFramesNeededP)
+{
+ ASSERT(framesToProcess <= MaxFramesToProcess);
+
+ // Calculate the next "virtual" index. After process() is called, m_virtualReadIndex will equal this value.
+ double nextFractionalIndex = m_virtualReadIndex + framesToProcess * rate();
+
+ // Because we're linearly interpolating between the previous and next sample we need to round up so we include the next sample.
+ int endIndex = static_cast<int>(nextFractionalIndex + 1.0); // round up to next integer index
+
+ // Determine how many input frames we'll need.
+ // We need to fill the buffer up to and including endIndex (so add 1) but we've already buffered m_fillIndex frames from last time.
+ size_t framesNeeded = 1 + endIndex - m_fillIndex;
+ if (numberOfSourceFramesNeededP)
+ *numberOfSourceFramesNeededP = framesNeeded;
+
+ // Do bounds checking for the source buffer.
+ bool isGood = m_fillIndex < m_sourceBuffer.size() && m_fillIndex + framesNeeded <= m_sourceBuffer.size();
+ ASSERT(isGood);
+ if (!isGood)
+ return 0;
+
+ return m_sourceBuffer.data() + m_fillIndex;
+}
+
+void AudioResamplerKernel::process(float* destination, size_t framesToProcess)
+{
+ ASSERT(framesToProcess <= MaxFramesToProcess);
+
+ float* source = m_sourceBuffer.data();
+
+ double rate = this->rate();
+ rate = max(0.0, rate);
+ rate = min(AudioResampler::MaxRate, rate);
+
+ // Start out with the previous saved values (if any).
+ if (m_fillIndex > 0) {
+ source[0] = m_lastValues[0];
+ source[1] = m_lastValues[1];
+ }
+
+ // Make a local copy.
+ double virtualReadIndex = m_virtualReadIndex;
+
+ // Sanity check source buffer access.
+ ASSERT(framesToProcess > 0);
+ ASSERT(virtualReadIndex >= 0 && 1 + static_cast<unsigned>(virtualReadIndex + (framesToProcess - 1) * rate) < m_sourceBuffer.size());
+
+ // Do the linear interpolation.
+ int n = framesToProcess;
+ while (n--) {
+ unsigned readIndex = static_cast<unsigned>(virtualReadIndex);
+ double interpolationFactor = virtualReadIndex - readIndex;
+
+ double sample1 = source[readIndex];
+ double sample2 = source[readIndex + 1];
+
+ double sample = (1.0 - interpolationFactor) * sample1 + interpolationFactor * sample2;
+
+ *destination++ = static_cast<float>(sample);
+
+ virtualReadIndex += rate;
+ }
+
+ // Save the last two sample-frames which will later be used at the beginning of the source buffer the next time around.
+ int readIndex = static_cast<int>(virtualReadIndex);
+ m_lastValues[0] = source[readIndex];
+ m_lastValues[1] = source[readIndex + 1];
+ m_fillIndex = 2;
+
+ // Wrap the virtual read index back to the start of the buffer.
+ virtualReadIndex -= readIndex;
+
+ // Put local copy back into member variable.
+ m_virtualReadIndex = virtualReadIndex;
+}
+
+void AudioResamplerKernel::reset()
+{
+ m_virtualReadIndex = 0.0;
+ m_fillIndex = 0;
+ m_lastValues[0] = 0.0f;
+ m_lastValues[1] = 0.0f;
+}
+
+double AudioResamplerKernel::rate() const
+{
+ return m_resampler->rate();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/AudioResamplerKernel.h b/Source/WebCore/platform/audio/AudioResamplerKernel.h
new file mode 100644
index 0000000..99d877b
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioResamplerKernel.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef AudioResamplerKernel_h
+#define AudioResamplerKernel_h
+
+#include "AudioArray.h"
+
+namespace WebCore {
+
+class AudioResampler;
+
+// AudioResamplerKernel does resampling on a single mono channel.
+// It uses a simple linear interpolation for good performance.
+
+class AudioResamplerKernel {
+public:
+ AudioResamplerKernel(AudioResampler*);
+
+ // getSourcePointer() should be called each time before process() is called.
+ // Given a number of frames to process (for subsequent call to process()), it returns a pointer and numberOfSourceFramesNeeded
+ // where sample data should be copied. This sample data provides the input to the resampler when process() is called.
+ // framesToProcess must be less than or equal to MaxFramesToProcess.
+ float* getSourcePointer(size_t framesToProcess, size_t* numberOfSourceFramesNeeded);
+
+ // process() resamples framesToProcess frames from the source into destination.
+ // Each call to process() must be preceded by a call to getSourcePointer() so that source input may be supplied.
+ // framesToProcess must be less than or equal to MaxFramesToProcess.
+ void process(float* destination, size_t framesToProcess);
+
+ // Resets the processing state.
+ void reset();
+
+ static const size_t MaxFramesToProcess;
+
+private:
+ double rate() const;
+
+ AudioResampler* m_resampler;
+ AudioFloatArray m_sourceBuffer;
+
+ // This is a (floating point) read index on the input stream.
+ double m_virtualReadIndex;
+
+ // We need to have continuity from one call of process() to the next.
+ // m_lastValues stores the last two sample values from the last call to process().
+ // m_fillIndex represents how many buffered samples we have which can be as many as 2.
+ // For the first call to process() (or after reset()) there will be no buffered samples.
+ float m_lastValues[2];
+ unsigned m_fillIndex;
+};
+
+} // namespace WebCore
+
+#endif // AudioResamplerKernel_h
diff --git a/Source/WebCore/platform/audio/AudioSourceProvider.h b/Source/WebCore/platform/audio/AudioSourceProvider.h
new file mode 100644
index 0000000..773546a
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioSourceProvider.h
@@ -0,0 +1,46 @@
+/*
+ * 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 AudioSourceProvider_h
+#define AudioSourceProvider_h
+
+namespace WebCore {
+
+class AudioBus;
+
+// Abstract base-class for a pull-model client.
+// provideInput() gets called repeatedly to render time-slices of a continuous audio stream.
+class AudioSourceProvider {
+public:
+ virtual void provideInput(AudioBus* bus, size_t framesToProcess) = 0;
+ virtual ~AudioSourceProvider() { }
+};
+
+} // WebCore
+
+#endif // AudioSourceProvider_h
diff --git a/Source/WebCore/platform/audio/AudioUtilities.cpp b/Source/WebCore/platform/audio/AudioUtilities.cpp
new file mode 100644
index 0000000..7a4b32e
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioUtilities.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioUtilities.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+namespace AudioUtilities {
+
+double decibelsToLinear(double decibels)
+{
+ return pow(10.0, 0.05 * decibels);
+}
+
+double linearToDecibels(double linear)
+{
+ // It's not possible to calculate decibels for a zero linear value since it would be -Inf.
+ // -1000.0 dB represents a very tiny linear value in case we ever reach this case.
+ ASSERT(linear);
+ if (!linear)
+ return -1000.0;
+
+ return 20.0 * log10(linear);
+}
+
+double discreteTimeConstantForSampleRate(double timeConstant, double sampleRate)
+{
+ // hardcoded value is temporary build fix for Windows.
+ // FIXME: replace hardcode 2.718282 with M_E until the correct MathExtras.h solution is determined.
+ return 1.0 - pow(1.0 / 2.718282, 1.0 / (sampleRate * timeConstant));
+}
+
+} // AudioUtilites
+
+} // WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/AudioUtilities.h b/Source/WebCore/platform/audio/AudioUtilities.h
new file mode 100644
index 0000000..7cf44ce
--- /dev/null
+++ b/Source/WebCore/platform/audio/AudioUtilities.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef AudioUtilities_h
+#define AudioUtilities_h
+
+namespace WebCore {
+
+namespace AudioUtilities {
+
+// Standard functions for converting to and from decibel values from linear.
+double linearToDecibels(double);
+double decibelsToLinear(double);
+
+// timeConstant is the time it takes a first-order linear time-invariant system
+// to reach the value 1 - 1/e (around 63.2%) given a step input response.
+// discreteTimeConstantForSampleRate() will return the discrete time-constant for the specific sampleRate.
+double discreteTimeConstantForSampleRate(double timeConstant, double sampleRate);
+
+} // AudioUtilites
+
+} // WebCore
+
+#endif // AudioUtilities_h
diff --git a/Source/WebCore/platform/audio/Biquad.cpp b/Source/WebCore/platform/audio/Biquad.cpp
new file mode 100644
index 0000000..20143e3
--- /dev/null
+++ b/Source/WebCore/platform/audio/Biquad.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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 "Biquad.h"
+
+#include <algorithm>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if OS(DARWIN)
+#include <Accelerate/Accelerate.h>
+#endif
+
+namespace WebCore {
+
+const int kBufferSize = 1024;
+
+Biquad::Biquad()
+{
+#if OS(DARWIN)
+ // Allocate two samples more for filter history
+ m_inputBuffer.resize(kBufferSize + 2);
+ m_outputBuffer.resize(kBufferSize + 2);
+#endif
+
+ // Initialize as pass-thru (straight-wire, no filter effect)
+ m_a0 = 1.0;
+ m_a1 = 0.0;
+ m_a2 = 0.0;
+ m_b1 = 0.0;
+ m_b2 = 0.0;
+
+ m_g = 1.0;
+
+ reset(); // clear filter memory
+}
+
+void Biquad::process(const float* sourceP, float* destP, size_t framesToProcess)
+{
+#if OS(DARWIN)
+ // Use vecLib if available
+ processFast(sourceP, destP, framesToProcess);
+#else
+ int n = framesToProcess;
+
+ // Create local copies of member variables
+ double x1 = m_x1;
+ double x2 = m_x2;
+ double y1 = m_y1;
+ double y2 = m_y2;
+
+ double a0 = m_a0;
+ double a1 = m_a1;
+ double a2 = m_a2;
+ double b1 = m_b1;
+ double b2 = m_b2;
+
+ while (n--) {
+ // FIXME: this can be optimized by pipelining the multiply adds...
+ float x = *sourceP++;
+ float y = a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2;
+
+ y *= m_g;
+
+ *destP++ = y;
+
+ // Update state variables
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ }
+
+ // Local variables back to member
+ m_x1 = x1;
+ m_x2 = x2;
+ m_y1 = y1;
+ m_y2 = y2;
+
+ m_a0 = a0;
+ m_a1 = a1;
+ m_a2 = a2;
+ m_b1 = b1;
+ m_b2 = b2;
+#endif
+}
+
+#if OS(DARWIN)
+
+// Here we have optimized version using Accelerate.framework
+
+void Biquad::processFast(const float* sourceP, float* destP, size_t framesToProcess)
+{
+ // Filter coefficients
+ double B[5];
+ B[0] = m_a0;
+ B[1] = m_a1;
+ B[2] = m_a2;
+ B[3] = m_b1;
+ B[4] = m_b2;
+
+ double* inputP = m_inputBuffer.data();
+ double* outputP = m_outputBuffer.data();
+
+ double* input2P = inputP + 2;
+ double* output2P = outputP + 2;
+
+ // Break up processing into smaller slices (kBufferSize) if necessary.
+
+ int n = framesToProcess;
+
+ while (n > 0) {
+ int framesThisTime = n < kBufferSize ? n : kBufferSize;
+
+ // Copy input to input buffer
+ for (int i = 0; i < framesThisTime; ++i)
+ input2P[i] = *sourceP++;
+
+ processSliceFast(inputP, outputP, B, framesThisTime);
+
+ // Copy output buffer to output (converts float -> double).
+ for (int i = 0; i < framesThisTime; ++i)
+ *destP++ = static_cast<float>(output2P[i]);
+
+ n -= framesThisTime;
+ }
+}
+
+void Biquad::processSliceFast(double* sourceP, double* destP, double* coefficientsP, size_t framesToProcess)
+{
+ // Use double-precision for filter stability
+ vDSP_deq22D(sourceP, 1, coefficientsP, destP, 1, framesToProcess);
+
+ // Save history. Note that sourceP and destP reference m_inputBuffer and m_outputBuffer respectively.
+ // These buffers are allocated (in the constructor) with space for two extra samples so it's OK to access
+ // array values two beyond framesToProcess.
+ sourceP[0] = sourceP[framesToProcess - 2 + 2];
+ sourceP[1] = sourceP[framesToProcess - 1 + 2];
+ destP[0] = destP[framesToProcess - 2 + 2];
+ destP[1] = destP[framesToProcess - 1 + 2];
+}
+
+#endif // OS(DARWIN)
+
+
+void Biquad::reset()
+{
+ m_x1 = m_x2 = m_y1 = m_y2 = 0.0;
+
+#if OS(DARWIN)
+ // Two extra samples for filter history
+ double* inputP = m_inputBuffer.data();
+ inputP[0] = 0.0;
+ inputP[1] = 0.0;
+
+ double* outputP = m_outputBuffer.data();
+ outputP[0] = 0.0;
+ outputP[1] = 0.0;
+#endif
+}
+
+void Biquad::setLowpassParams(double cutoff, double resonance)
+{
+ resonance = std::max(0.0, resonance); // can't go negative
+
+ double g = pow(10.0, 0.05 * resonance);
+ double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0);
+
+ // Compute biquad coefficients for lopass filter
+ double theta = piDouble * cutoff;
+ double sn = 0.5 * d * sin(theta);
+ double beta = 0.5 * (1.0 - sn) / (1.0 + sn);
+ double gamma = (0.5 + beta) * cos(theta);
+ double alpha = 0.25 * (0.5 + beta - gamma);
+
+ m_a0 = 2.0 * alpha;
+ m_a1 = 2.0 * 2.0*alpha;
+ m_a2 = 2.0 * alpha;
+ m_b1 = 2.0 * -gamma;
+ m_b2 = 2.0 * beta;
+}
+
+void Biquad::setHighpassParams(double cutoff, double resonance)
+{
+ resonance = std::max(0.0, resonance); // can't go negative
+
+ double g = pow(10.0, 0.05 * resonance);
+ double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0);
+
+ // Compute biquad coefficients for highpass filter
+ double theta = piDouble * cutoff;
+ double sn = 0.5 * d * sin(theta);
+ double beta = 0.5 * (1.0 - sn) / (1.0 + sn);
+ double gamma = (0.5 + beta) * cos(theta);
+ double alpha = 0.25 * (0.5 + beta + gamma);
+
+ m_a0 = 2.0 * alpha;
+ m_a1 = 2.0 * -2.0*alpha;
+ m_a2 = 2.0 * alpha;
+ m_b1 = 2.0 * -gamma;
+ m_b2 = 2.0 * beta;
+}
+
+void Biquad::setLowShelfParams(double cutoff, double dbGain)
+{
+ double theta = piDouble * cutoff;
+
+ double A = pow(10.0, dbGain / 40.0);
+ double S = 1.0; // filter slope (1.0 is max value)
+ double alpha = 0.5 * sin(theta) * sqrt((A + 1.0 / A) * (1.0 / S - 1.0) + 2.0);
+
+ double k = cos(theta);
+ double k2 = 2.0 * sqrt(A) * alpha;
+
+ double b0 = A * ((A + 1.0) - (A - 1.0) * k + k2);
+ double b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * k);
+ double b2 = A * ((A + 1.0) - (A - 1.0) * k - k2);
+ double a0 = (A + 1.0) + (A - 1.0) * k + k2;
+ double a1 = -2.0 * ((A - 1.0) + (A + 1.0) * k);
+ double a2 = (A + 1.0) + (A - 1.0) * k - k2;
+
+ double a0Inverse = 1.0 / a0;
+
+ m_a0 = b0 * a0Inverse;
+ m_a1 = b1 * a0Inverse;
+ m_a2 = b2 * a0Inverse;
+ m_b1 = a1 * a0Inverse;
+ m_b2 = a2 * a0Inverse;
+}
+
+void Biquad::setZeroPolePairs(const Complex &zero, const Complex &pole)
+{
+ m_a0 = 1.0;
+ m_a1 = -2.0 * zero.real();
+
+ double zeroMag = abs(zero);
+ m_a2 = zeroMag * zeroMag;
+
+ m_b1 = -2.0 * pole.real();
+
+ double poleMag = abs(pole);
+ m_b2 = poleMag * poleMag;
+}
+
+void Biquad::setAllpassPole(const Complex &pole)
+{
+ Complex zero = Complex(1.0, 0.0) / pole;
+ setZeroPolePairs(zero, pole);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/Biquad.h b/Source/WebCore/platform/audio/Biquad.h
new file mode 100644
index 0000000..d68bf4e
--- /dev/null
+++ b/Source/WebCore/platform/audio/Biquad.h
@@ -0,0 +1,99 @@
+/*
+ * 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 Biquad_h
+#define Biquad_h
+
+#include "AudioArray.h"
+#include <sys/types.h>
+#include <wtf/Complex.h>
+#include <wtf/Platform.h>
+
+namespace WebCore {
+
+// A basic biquad (two-zero / two-pole digital filter)
+//
+// It can be configured to a number of common and very useful filters:
+// lowpass, highpass, shelving, parameteric, notch, allpass, ...
+
+class Biquad {
+public:
+ Biquad();
+ virtual ~Biquad() { }
+
+ void process(const float* sourceP, float* destP, size_t framesToProcess);
+
+ // cutoff is 0-1 normalized, resonance is in dB >= 0.0
+ void setLowpassParams(double cutoff, double resonance);
+ void setHighpassParams(double cutoff, double resonance);
+
+ void setLowShelfParams(double cutoff, double dbGain);
+
+ // FIXME: need to implement a few more common filters
+ // void setHighShelfParams(double cutoff, double dbGain);
+ // void setParametricEQParams(double cutoff, double resonance);
+
+ // Set the biquad coefficients given a single zero (other zero will be conjugate)
+ // and a single pole (other pole will be conjugate)
+ void setZeroPolePairs(const Complex& zero, const Complex& pole);
+
+ // Set the biquad coefficients given a single pole (other pole will be conjugate)
+ // (The zeroes will be the inverse of the poles)
+ void setAllpassPole(const Complex& pole);
+
+ // Resets filter state
+ void reset();
+
+private:
+ // Filter coefficients
+ double m_a0;
+ double m_a1;
+ double m_a2;
+ double m_b1;
+ double m_b2;
+
+ double m_g;
+
+ // Filter memory
+ double m_x1; // input delayed by 1 sample
+ double m_x2; // input delayed by 2 samples
+ double m_y1; // output delayed by 1 sample
+ double m_y2; // output delayed by 2 samples
+
+#if OS(DARWIN)
+ void processFast(const float* sourceP, float* destP, size_t framesToProcess);
+ void processSliceFast(double* sourceP, double* destP, double* coefficientsP, size_t framesToProcess);
+
+ AudioDoubleArray m_inputBuffer;
+ AudioDoubleArray m_outputBuffer;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // Biquad_h
diff --git a/Source/WebCore/platform/audio/Cone.cpp b/Source/WebCore/platform/audio/Cone.cpp
new file mode 100644
index 0000000..f514cde
--- /dev/null
+++ b/Source/WebCore/platform/audio/Cone.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "Cone.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+ConeEffect::ConeEffect()
+ : m_innerAngle(360.0)
+ , m_outerAngle(360.0)
+ , m_outerGain(0.0)
+{
+}
+
+double ConeEffect::gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition)
+{
+ if (sourceOrientation.isZero() || ((m_innerAngle == 360.0) && (m_outerAngle == 360.0)))
+ return 1.0; // no cone specified - unity gain
+
+ // Normalized source-listener vector
+ FloatPoint3D sourceToListener = listenerPosition - sourcePosition;
+ sourceToListener.normalize();
+
+ FloatPoint3D normalizedSourceOrientation = sourceOrientation;
+ normalizedSourceOrientation.normalize();
+
+ // Angle between the source orientation vector and the source-listener vector
+ double dotProduct = sourceToListener.dot(normalizedSourceOrientation);
+ double angle = 180.0 * acos(dotProduct) / piDouble;
+ double absAngle = fabs(angle);
+
+ // Divide by 2.0 here since API is entire angle (not half-angle)
+ double absInnerAngle = fabs(m_innerAngle) / 2.0;
+ double absOuterAngle = fabs(m_outerAngle) / 2.0;
+ double gain = 1.0;
+
+ if (absAngle <= absInnerAngle)
+ // No attenuation
+ gain = 1.0;
+ else if (absAngle >= absOuterAngle)
+ // Max attenuation
+ gain = m_outerGain;
+ else {
+ // Between inner and outer cones
+ // inner -> outer, x goes from 0 -> 1
+ double x = (absAngle - absInnerAngle) / (absOuterAngle - absInnerAngle);
+ gain = (1.0 - x) + m_outerGain * x;
+ }
+
+ return gain;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/Cone.h b/Source/WebCore/platform/audio/Cone.h
new file mode 100644
index 0000000..f566018
--- /dev/null
+++ b/Source/WebCore/platform/audio/Cone.h
@@ -0,0 +1,63 @@
+/*
+ * 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 Cone_h
+#define Cone_h
+
+#include "FloatPoint3D.h"
+
+namespace WebCore {
+
+// Cone gain is defined according to the OpenAL specification
+
+class ConeEffect {
+public:
+ ConeEffect();
+
+ // Returns scalar gain for the given source/listener positions/orientations
+ double gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition);
+
+ // Angles in degrees
+ void setInnerAngle(double innerAngle) { m_innerAngle = innerAngle; }
+ double innerAngle() const { return m_innerAngle; }
+
+ void setOuterAngle(double outerAngle) { m_outerAngle = outerAngle; }
+ double outerAngle() const { return m_outerAngle; }
+
+ void setOuterGain(double outerGain) { m_outerGain = outerGain; }
+ double outerGain() const { return m_outerGain; }
+
+protected:
+ double m_innerAngle;
+ double m_outerAngle;
+ double m_outerGain;
+};
+
+} // namespace WebCore
+
+#endif // Cone_h
diff --git a/Source/WebCore/platform/audio/Distance.cpp b/Source/WebCore/platform/audio/Distance.cpp
new file mode 100644
index 0000000..0f1b005
--- /dev/null
+++ b/Source/WebCore/platform/audio/Distance.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "Distance.h"
+
+#include <algorithm>
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+DistanceEffect::DistanceEffect()
+ : m_model(ModelInverse)
+ , m_isClamped(true)
+ , m_refDistance(1.0)
+ , m_maxDistance(10000.0)
+ , m_rolloffFactor(1.0)
+{
+}
+
+double DistanceEffect::gain(double distance)
+{
+ // don't go beyond maximum distance
+ distance = min(distance, m_maxDistance);
+
+ // if clamped, don't get closer than reference distance
+ if (m_isClamped)
+ distance = max(distance, m_refDistance);
+
+ switch (m_model) {
+ case ModelLinear:
+ return linearGain(distance);
+ break;
+ case ModelInverse:
+ return inverseGain(distance);
+ break;
+ case ModelExponential:
+ return exponentialGain(distance);
+ break;
+
+ default:
+ return 0.0;
+ }
+}
+
+double DistanceEffect::linearGain(double distance)
+{
+ return (1.0 - m_rolloffFactor * (distance - m_refDistance)) / (m_maxDistance - m_refDistance);
+}
+
+double DistanceEffect::inverseGain(double distance)
+{
+ return m_refDistance / (m_refDistance + m_rolloffFactor * (distance - m_refDistance));
+}
+
+double DistanceEffect::exponentialGain(double distance)
+{
+ return pow(distance / m_refDistance, -m_rolloffFactor);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/Distance.h b/Source/WebCore/platform/audio/Distance.h
new file mode 100644
index 0000000..c7edded
--- /dev/null
+++ b/Source/WebCore/platform/audio/Distance.h
@@ -0,0 +1,80 @@
+/*
+ * 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 Distance_h
+#define Distance_h
+
+namespace WebCore {
+
+// Distance models are defined according to the OpenAL specification
+
+class DistanceEffect {
+public:
+ enum ModelType {
+ ModelLinear = 0,
+ ModelInverse = 1,
+ ModelExponential = 2
+ };
+
+ DistanceEffect();
+
+ // Returns scalar gain for the given distance the current distance model is used
+ double gain(double distance);
+
+ ModelType model() { return m_model; }
+
+ void setModel(ModelType model, bool clamped)
+ {
+ m_model = model;
+ m_isClamped = clamped;
+ }
+
+ // Distance params
+ void setRefDistance(double refDistance) { m_refDistance = refDistance; }
+ void setMaxDistance(double maxDistance) { m_maxDistance = maxDistance; }
+ void setRolloffFactor(double rolloffFactor) { m_rolloffFactor = rolloffFactor; }
+
+ double refDistance() const { return m_refDistance; }
+ double maxDistance() const { return m_maxDistance; }
+ double rolloffFactor() const { return m_rolloffFactor; }
+
+protected:
+ double linearGain(double distance);
+ double inverseGain(double distance);
+ double exponentialGain(double distance);
+
+ ModelType m_model;
+ bool m_isClamped;
+ double m_refDistance;
+ double m_maxDistance;
+ double m_rolloffFactor;
+};
+
+} // namespace WebCore
+
+#endif // Distance_h
diff --git a/Source/WebCore/platform/audio/EqualPowerPanner.cpp b/Source/WebCore/platform/audio/EqualPowerPanner.cpp
new file mode 100644
index 0000000..002b7c6
--- /dev/null
+++ b/Source/WebCore/platform/audio/EqualPowerPanner.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "EqualPowerPanner.h"
+
+#include "AudioBus.h"
+#include "AudioUtilities.h"
+#include <wtf/MathExtras.h>
+
+// Use a 50ms smoothing / de-zippering time-constant.
+const double SmoothingTimeConstant = 0.050;
+
+namespace WebCore {
+
+EqualPowerPanner::EqualPowerPanner(double sampleRate)
+ : Panner(PanningModelEqualPower)
+ , m_isFirstRender(true)
+ , m_gainL(0.0)
+ , m_gainR(0.0)
+{
+ m_smoothingConstant = AudioUtilities::discreteTimeConstantForSampleRate(SmoothingTimeConstant, sampleRate);
+}
+
+void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess)
+{
+ // FIXME: implement stereo sources
+ bool isInputSafe = inputBus && inputBus->numberOfChannels() == 1 && framesToProcess <= inputBus->length();
+ ASSERT(isInputSafe);
+ if (!isInputSafe)
+ return;
+
+ bool isOutputSafe = outputBus && outputBus->numberOfChannels() == 2 && framesToProcess <= outputBus->length();
+ ASSERT(isOutputSafe);
+ if (!isOutputSafe)
+ return;
+
+ AudioChannel* channel = inputBus->channel(0);
+ float* sourceP = channel->data();
+ float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->data();
+ float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->data();
+
+ if (!sourceP || !destinationL || !destinationR)
+ return;
+
+ // Pan smoothly from left to right with azimuth going from -30 -> +30 degrees.
+ double desiredPanPosition;
+ if (azimuth > 30.0)
+ desiredPanPosition = 1.0;
+ else if (azimuth < -30.0)
+ desiredPanPosition = 0.0;
+ else
+ desiredPanPosition = (azimuth + 30.0) / 60.0;
+
+ double desiredGainL = 0.5 * cos(piDouble * desiredPanPosition) + 0.5;
+ double desiredGainR = sqrt(1.0 - desiredGainL*desiredGainL);
+
+ // Don't de-zipper on first render call.
+ if (m_isFirstRender) {
+ m_isFirstRender = false;
+ m_gainL = desiredGainL;
+ m_gainR = desiredGainR;
+ }
+
+ // Cache in local variables.
+ double gainL = m_gainL;
+ double gainR = m_gainR;
+
+ // Get local copy of smoothing constant.
+ const double SmoothingConstant = m_smoothingConstant;
+
+ int n = framesToProcess;
+
+ while (n--) {
+ float input = *sourceP++;
+ gainL += (desiredGainL - gainL) * SmoothingConstant;
+ gainR += (desiredGainR - gainR) * SmoothingConstant;
+ *destinationL++ = static_cast<float>(input * gainL);
+ *destinationR++ = static_cast<float>(input * gainR);
+ }
+
+ m_gainL = gainL;
+ m_gainR = gainR;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/EqualPowerPanner.h b/Source/WebCore/platform/audio/EqualPowerPanner.h
new file mode 100644
index 0000000..f20617e
--- /dev/null
+++ b/Source/WebCore/platform/audio/EqualPowerPanner.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef EqualPowerPanner_h
+#define EqualPowerPanner_h
+
+#include "Panner.h"
+
+namespace WebCore {
+
+// Common type of stereo panner as found in normal audio mixing equipment.
+
+class EqualPowerPanner : public Panner {
+public:
+ EqualPowerPanner(double sampleRate);
+
+ virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBuf, size_t framesToProcess);
+
+ virtual void reset() { m_isFirstRender = true; }
+
+private:
+ // For smoothing / de-zippering
+ bool m_isFirstRender;
+ double m_smoothingConstant;
+
+ double m_gainL;
+ double m_gainR;
+};
+
+} // namespace WebCore
+
+#endif // EqualPowerPanner_h
diff --git a/Source/WebCore/platform/audio/FFTConvolver.cpp b/Source/WebCore/platform/audio/FFTConvolver.cpp
new file mode 100644
index 0000000..9093433
--- /dev/null
+++ b/Source/WebCore/platform/audio/FFTConvolver.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "FFTConvolver.h"
+
+#include "VectorMath.h"
+
+namespace WebCore {
+
+using namespace VectorMath;
+
+FFTConvolver::FFTConvolver(size_t fftSize)
+ : m_frame(fftSize)
+ , m_readWriteIndex(0)
+ , m_inputBuffer(fftSize) // 2nd half of buffer is always zeroed
+ , m_outputBuffer(fftSize)
+ , m_lastOverlapBuffer(fftSize / 2)
+{
+}
+
+void FFTConvolver::process(FFTFrame* fftKernel, float* sourceP, float* destP, size_t framesToProcess)
+{
+ // FIXME: make so framesToProcess is not required to fit evenly into fftSize/2
+
+ // Copy samples to input buffer (note contraint above!)
+ float* inputP = m_inputBuffer.data();
+
+ // Sanity check
+ bool isCopyGood1 = sourceP && inputP && m_readWriteIndex + framesToProcess <= m_inputBuffer.size();
+ ASSERT(isCopyGood1);
+ if (!isCopyGood1)
+ return;
+
+ memcpy(inputP + m_readWriteIndex, sourceP, sizeof(float) * framesToProcess);
+
+ // Copy samples from output buffer
+ float* outputP = m_outputBuffer.data();
+
+ // Sanity check
+ bool isCopyGood2 = destP && outputP && m_readWriteIndex + framesToProcess <= m_outputBuffer.size();
+ ASSERT(isCopyGood2);
+ if (!isCopyGood2)
+ return;
+
+ memcpy(destP, outputP + m_readWriteIndex, sizeof(float) * framesToProcess);
+ m_readWriteIndex += framesToProcess;
+
+
+ // Check if it's time to perform the next FFT
+ size_t halfSize = fftSize() / 2;
+ if (m_readWriteIndex == halfSize) {
+ // The input buffer is now filled (get frequency-domain version)
+ m_frame.doFFT(m_inputBuffer.data());
+ m_frame.multiply(*fftKernel);
+ m_frame.doInverseFFT(m_outputBuffer.data());
+
+ // Overlap-add 1st half from previous time
+ vadd(m_outputBuffer.data(), 1, m_lastOverlapBuffer.data(), 1, m_outputBuffer.data(), 1, halfSize);
+
+ // Finally, save 2nd half of result
+ bool isCopyGood3 = m_outputBuffer.size() == 2 * halfSize && m_lastOverlapBuffer.size() == halfSize;
+ ASSERT(isCopyGood3);
+ if (!isCopyGood3)
+ return;
+
+ memcpy(m_lastOverlapBuffer.data(), m_outputBuffer.data() + halfSize, sizeof(float) * halfSize);
+
+ // Reset index back to start for next time
+ m_readWriteIndex = 0;
+ }
+}
+
+void FFTConvolver::reset()
+{
+ m_lastOverlapBuffer.zero();
+ m_readWriteIndex = 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/FFTConvolver.h b/Source/WebCore/platform/audio/FFTConvolver.h
new file mode 100644
index 0000000..c1b5002
--- /dev/null
+++ b/Source/WebCore/platform/audio/FFTConvolver.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 FFTConvolver_h
+#define FFTConvolver_h
+
+#include "AudioArray.h"
+#include "FFTFrame.h"
+
+namespace WebCore {
+
+class FFTConvolver {
+public:
+ // fftSize must be a power of two
+ FFTConvolver(size_t fftSize);
+
+ // For now, with multiple calls to Process(), framesToProcess MUST add up EXACTLY to fftSize / 2
+ //
+ // FIXME: Later, we can do more sophisticated buffering to relax this requirement...
+ //
+ // The input to output latency is equal to fftSize / 2
+ //
+ // Processing in-place is allowed...
+ void process(FFTFrame* fftKernel, float* sourceP, float* destP, size_t framesToProcess);
+
+ void reset();
+
+ size_t fftSize() const { return m_frame.fftSize(); }
+
+private:
+ FFTFrame m_frame;
+
+ // Buffer input until we get fftSize / 2 samples then do an FFT
+ size_t m_readWriteIndex;
+ AudioFloatArray m_inputBuffer;
+
+ // Stores output which we read a little at a time
+ AudioFloatArray m_outputBuffer;
+
+ // Saves the 2nd half of the FFT buffer, so we can do an overlap-add with the 1st half of the next one
+ AudioFloatArray m_lastOverlapBuffer;
+};
+
+} // namespace WebCore
+
+#endif // FFTConvolver_h
diff --git a/Source/WebCore/platform/audio/FFTFrame.cpp b/Source/WebCore/platform/audio/FFTFrame.cpp
new file mode 100644
index 0000000..d9979d9
--- /dev/null
+++ b/Source/WebCore/platform/audio/FFTFrame.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 "FFTFrame.h"
+
+#include <wtf/Complex.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+void FFTFrame::doPaddedFFT(float* data, size_t dataSize)
+{
+ // Zero-pad the impulse response
+ AudioFloatArray paddedResponse(fftSize()); // zero-initialized
+ paddedResponse.copyToRange(data, 0, dataSize);
+
+ // Get the frequency-domain version of padded response
+ doFFT(paddedResponse.data());
+}
+
+PassOwnPtr<FFTFrame> FFTFrame::createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x)
+{
+ OwnPtr<FFTFrame> newFrame = adoptPtr(new FFTFrame(frame1.fftSize()));
+
+ newFrame->interpolateFrequencyComponents(frame1, frame2, x);
+
+ // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
+ int fftSize = newFrame->fftSize();
+ AudioFloatArray buffer(fftSize);
+ newFrame->doInverseFFT(buffer.data());
+ buffer.zeroRange(fftSize / 2, fftSize);
+
+ // Put back into frequency domain.
+ newFrame->doFFT(buffer.data());
+
+ return newFrame.release();
+}
+
+void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double interp)
+{
+ // FIXME : with some work, this method could be optimized
+
+ float* realP = realData();
+ float* imagP = imagData();
+
+ const float* realP1 = frame1.realData();
+ const float* imagP1 = frame1.imagData();
+ const float* realP2 = frame2.realData();
+ const float* imagP2 = frame2.imagData();
+
+ m_FFTSize = frame1.fftSize();
+ m_log2FFTSize = frame1.log2FFTSize();
+
+ double s1base = (1.0 - interp);
+ double s2base = interp;
+
+ double phaseAccum = 0.0;
+ double lastPhase1 = 0.0;
+ double lastPhase2 = 0.0;
+
+ realP[0] = static_cast<float>(s1base * realP1[0] + s2base * realP2[0]);
+ imagP[0] = static_cast<float>(s1base * imagP1[0] + s2base * imagP2[0]);
+
+ int n = m_FFTSize / 2;
+
+ for (int i = 1; i < n; ++i) {
+ Complex c1(realP1[i], imagP1[i]);
+ Complex c2(realP2[i], imagP2[i]);
+
+ double mag1 = abs(c1);
+ double mag2 = abs(c2);
+
+ // Interpolate magnitudes in decibels
+ double mag1db = 20.0 * log10(mag1);
+ double mag2db = 20.0 * log10(mag2);
+
+ double s1 = s1base;
+ double s2 = s2base;
+
+ double magdbdiff = mag1db - mag2db;
+
+ // Empirical tweak to retain higher-frequency zeroes
+ double threshold = (i > 16) ? 5.0 : 2.0;
+
+ if (magdbdiff < -threshold && mag1db < 0.0) {
+ s1 = pow(s1, 0.75);
+ s2 = 1.0 - s1;
+ } else if (magdbdiff > threshold && mag2db < 0.0) {
+ s2 = pow(s2, 0.75);
+ s1 = 1.0 - s2;
+ }
+
+ // Average magnitude by decibels instead of linearly
+ double magdb = s1 * mag1db + s2 * mag2db;
+ double mag = pow(10.0, 0.05 * magdb);
+
+ // Now, deal with phase
+ double phase1 = arg(c1);
+ double phase2 = arg(c2);
+
+ double deltaPhase1 = phase1 - lastPhase1;
+ double deltaPhase2 = phase2 - lastPhase2;
+ lastPhase1 = phase1;
+ lastPhase2 = phase2;
+
+ // Unwrap phase deltas
+ if (deltaPhase1 > piDouble)
+ deltaPhase1 -= 2.0 * piDouble;
+ if (deltaPhase1 < -piDouble)
+ deltaPhase1 += 2.0 * piDouble;
+ if (deltaPhase2 > piDouble)
+ deltaPhase2 -= 2.0 * piDouble;
+ if (deltaPhase2 < -piDouble)
+ deltaPhase2 += 2.0 * piDouble;
+
+ // Blend group-delays
+ double deltaPhaseBlend;
+
+ if (deltaPhase1 - deltaPhase2 > piDouble)
+ deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * piDouble + deltaPhase2);
+ else if (deltaPhase2 - deltaPhase1 > piDouble)
+ deltaPhaseBlend = s1 * (2.0 * piDouble + deltaPhase1) + s2 * deltaPhase2;
+ else
+ deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
+
+ phaseAccum += deltaPhaseBlend;
+
+ // Unwrap
+ if (phaseAccum > piDouble)
+ phaseAccum -= 2.0 * piDouble;
+ if (phaseAccum < -piDouble)
+ phaseAccum += 2.0 * piDouble;
+
+ Complex c = complexFromMagnitudePhase(mag, phaseAccum);
+
+ realP[i] = static_cast<float>(c.real());
+ imagP[i] = static_cast<float>(c.imag());
+ }
+}
+
+double FFTFrame::extractAverageGroupDelay()
+{
+ float* realP = realData();
+ float* imagP = imagData();
+
+ double aveSum = 0.0;
+ double weightSum = 0.0;
+ double lastPhase = 0.0;
+
+ int halfSize = fftSize() / 2;
+
+ const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
+
+ // Calculate weighted average group delay
+ for (int i = 0; i < halfSize; i++) {
+ Complex c(realP[i], imagP[i]);
+ double mag = abs(c);
+ double phase = arg(c);
+
+ double deltaPhase = phase - lastPhase;
+ lastPhase = phase;
+
+ // Unwrap
+ if (deltaPhase < -piDouble)
+ deltaPhase += 2.0 * piDouble;
+ if (deltaPhase > piDouble)
+ deltaPhase -= 2.0 * piDouble;
+
+ aveSum += mag * deltaPhase;
+ weightSum += mag;
+ }
+
+ // Note how we invert the phase delta wrt frequency since this is how group delay is defined
+ double ave = aveSum / weightSum;
+ double aveSampleDelay = -ave / kSamplePhaseDelay;
+
+ // Leave 20 sample headroom (for leading edge of impulse)
+ if (aveSampleDelay > 20.0)
+ aveSampleDelay -= 20.0;
+
+ // Remove average group delay (minus 20 samples for headroom)
+ addConstantGroupDelay(-aveSampleDelay);
+
+ // Remove DC offset
+ realP[0] = 0.0f;
+
+ return aveSampleDelay;
+}
+
+void FFTFrame::addConstantGroupDelay(double sampleFrameDelay)
+{
+ int halfSize = fftSize() / 2;
+
+ float* realP = realData();
+ float* imagP = imagData();
+
+ const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
+
+ double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
+
+ // Add constant group delay
+ for (int i = 1; i < halfSize; i++) {
+ Complex c(realP[i], imagP[i]);
+ double mag = abs(c);
+ double phase = arg(c);
+
+ phase += i * phaseAdj;
+
+ Complex c2 = complexFromMagnitudePhase(mag, phase);
+
+ realP[i] = static_cast<float>(c2.real());
+ imagP[i] = static_cast<float>(c2.imag());
+ }
+}
+
+#ifndef NDEBUG
+void FFTFrame::print()
+{
+ FFTFrame& frame = *this;
+ float* realP = frame.realData();
+ float* imagP = frame.imagData();
+ printf("**** \n");
+ printf("DC = %f : nyquist = %f\n", realP[0], imagP[0]);
+
+ int n = m_FFTSize / 2;
+
+ for (int i = 1; i < n; i++) {
+ double mag = sqrt(realP[i] * realP[i] + imagP[i] * imagP[i]);
+ double phase = atan2(realP[i], imagP[i]);
+
+ printf("[%d] (%f %f)\n", i, mag, phase);
+ }
+ printf("****\n");
+}
+#endif // NDEBUG
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/FFTFrame.h b/Source/WebCore/platform/audio/FFTFrame.h
new file mode 100644
index 0000000..1a82ef0
--- /dev/null
+++ b/Source/WebCore/platform/audio/FFTFrame.h
@@ -0,0 +1,123 @@
+/*
+ * 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 FFTFrame_h
+#define FFTFrame_h
+
+#include "AudioArray.h"
+
+#if OS(DARWIN)
+#include <Accelerate/Accelerate.h>
+#endif
+
+#if !OS(DARWIN) && USE(WEBAUDIO_MKL)
+#include "mkl_dfti.h"
+#endif
+
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Platform.h>
+
+namespace WebCore {
+
+// Defines the interface for an "FFT frame", an object which is able to perform a forward
+// and reverse FFT, internally storing the resultant frequency-domain data.
+
+class FFTFrame {
+public:
+ // The constructors, destructor, and methods up to the CROSS-PLATFORM section have platform-dependent implementations.
+
+ FFTFrame(unsigned fftSize);
+ FFTFrame(); // creates a blank/empty frame for later use with createInterpolatedFrame()
+ FFTFrame(const FFTFrame& frame);
+ ~FFTFrame();
+
+ static void cleanup();
+ void doFFT(float* data);
+ void doInverseFFT(float* data);
+ void multiply(const FFTFrame& frame); // multiplies ourself with frame : effectively operator*=()
+
+ float* realData() const;
+ float* imagData() const;
+
+ void print(); // for debugging
+
+ // CROSS-PLATFORM
+ // The remaining public methods have cross-platform implementations:
+
+ // Interpolates from frame1 -> frame2 as x goes from 0.0 -> 1.0
+ static PassOwnPtr<FFTFrame> createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x);
+
+ void doPaddedFFT(float* data, size_t dataSize); // zero-padding with dataSize <= fftSize
+ double extractAverageGroupDelay();
+ void addConstantGroupDelay(double sampleFrameDelay);
+
+ unsigned fftSize() const { return m_FFTSize; }
+ unsigned log2FFTSize() const { return m_log2FFTSize; }
+
+private:
+ unsigned m_FFTSize;
+ unsigned m_log2FFTSize;
+
+ void interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double x);
+
+#if OS(DARWIN)
+ DSPSplitComplex& dspSplitComplex() { return m_frame; }
+ DSPSplitComplex dspSplitComplex() const { return m_frame; }
+
+ static FFTSetup fftSetupForSize(unsigned fftSize);
+
+ static FFTSetup* fftSetups;
+
+ FFTSetup m_FFTSetup;
+
+ DSPSplitComplex m_frame;
+ AudioFloatArray m_realData;
+ AudioFloatArray m_imagData;
+#endif // OS(DARWIN)
+#if !OS(DARWIN) && USE(WEBAUDIO_MKL)
+ // Interleaves the planar real and imaginary data and returns a
+ // pointer to the resulting storage which can be used for in-place
+ // or out-of-place operations. FIXME: ideally all of the MKL
+ // routines would operate on planar data and this method would be
+ // removed.
+ float* getUpToDateComplexData();
+
+ static DFTI_DESCRIPTOR_HANDLE descriptorHandleForSize(unsigned fftSize);
+
+ static DFTI_DESCRIPTOR_HANDLE* descriptorHandles;
+
+ DFTI_DESCRIPTOR_HANDLE m_handle;
+ AudioFloatArray m_complexData;
+ AudioFloatArray m_realData;
+ AudioFloatArray m_imagData;
+#endif // !OS(DARWIN) && USE(WEBAUDIO_MKL)
+};
+
+} // namespace WebCore
+
+#endif // FFTFrame_h
diff --git a/Source/WebCore/platform/audio/HRTFDatabase.cpp b/Source/WebCore/platform/audio/HRTFDatabase.cpp
new file mode 100644
index 0000000..ef1229f
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFDatabase.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 "HRTFDatabase.h"
+
+#include "HRTFElevation.h"
+
+using namespace std;
+
+namespace WebCore {
+
+const int HRTFDatabase::MinElevation = -45;
+const int HRTFDatabase::MaxElevation = 90;
+const unsigned HRTFDatabase::RawElevationAngleSpacing = 15;
+const unsigned HRTFDatabase::NumberOfRawElevations = 10; // -45 -> +90 (each 15 degrees)
+const unsigned HRTFDatabase::InterpolationFactor = 1;
+const unsigned HRTFDatabase::NumberOfTotalElevations = NumberOfRawElevations * InterpolationFactor;
+
+PassOwnPtr<HRTFDatabase> HRTFDatabase::create(double sampleRate)
+{
+ OwnPtr<HRTFDatabase> hrtfDatabase = adoptPtr(new HRTFDatabase(sampleRate));
+ return hrtfDatabase.release();
+}
+
+HRTFDatabase::HRTFDatabase(double sampleRate)
+ : m_elevations(NumberOfTotalElevations)
+ , m_sampleRate(sampleRate)
+{
+ unsigned elevationIndex = 0;
+ for (int elevation = MinElevation; elevation <= MaxElevation; elevation += RawElevationAngleSpacing) {
+ OwnPtr<HRTFElevation> hrtfElevation = HRTFElevation::createForSubject("Composite", elevation, sampleRate);
+ ASSERT(hrtfElevation.get());
+ if (!hrtfElevation.get())
+ return;
+
+ m_elevations[elevationIndex] = hrtfElevation.release();
+ elevationIndex += InterpolationFactor;
+ }
+
+ // Now, go back and interpolate elevations.
+ if (InterpolationFactor > 1) {
+ for (unsigned i = 0; i < NumberOfTotalElevations; i += InterpolationFactor) {
+ unsigned j = (i + InterpolationFactor);
+ if (j >= NumberOfTotalElevations)
+ j = i; // for last elevation interpolate with itself
+
+ // Create the interpolated convolution kernels and delays.
+ for (unsigned jj = 1; jj < InterpolationFactor; ++jj) {
+ double x = static_cast<double>(jj) / static_cast<double>(InterpolationFactor);
+ m_elevations[i + jj] = HRTFElevation::createByInterpolatingSlices(m_elevations[i].get(), m_elevations[j].get(), x, sampleRate);
+ ASSERT(m_elevations[i + jj].get());
+ }
+ }
+ }
+}
+
+void HRTFDatabase::getKernelsFromAzimuthElevation(double azimuthBlend, unsigned azimuthIndex, double elevationAngle, HRTFKernel* &kernelL, HRTFKernel* &kernelR,
+ double& frameDelayL, double& frameDelayR)
+{
+ unsigned elevationIndex = indexFromElevationAngle(elevationAngle);
+ ASSERT(elevationIndex < m_elevations.size() && m_elevations.size() > 0);
+
+ if (!m_elevations.size()) {
+ kernelL = 0;
+ kernelR = 0;
+ return;
+ }
+
+ if (elevationIndex > m_elevations.size() - 1)
+ elevationIndex = m_elevations.size() - 1;
+
+ HRTFElevation* hrtfElevation = m_elevations[elevationIndex].get();
+ ASSERT(hrtfElevation);
+ if (!hrtfElevation) {
+ kernelL = 0;
+ kernelR = 0;
+ return;
+ }
+
+ hrtfElevation->getKernelsFromAzimuth(azimuthBlend, azimuthIndex, kernelL, kernelR, frameDelayL, frameDelayR);
+}
+
+unsigned HRTFDatabase::indexFromElevationAngle(double elevationAngle)
+{
+ // Clamp to allowed range.
+ elevationAngle = max(static_cast<double>(MinElevation), elevationAngle);
+ elevationAngle = min(static_cast<double>(MaxElevation), elevationAngle);
+
+ unsigned elevationIndex = static_cast<int>(InterpolationFactor * (elevationAngle - MinElevation) / RawElevationAngleSpacing);
+ return elevationIndex;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/HRTFDatabase.h b/Source/WebCore/platform/audio/HRTFDatabase.h
new file mode 100644
index 0000000..c33b38f
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFDatabase.h
@@ -0,0 +1,87 @@
+/*
+ * 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 HRTFDatabase_h
+#define HRTFDatabase_h
+
+#include "HRTFElevation.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class HRTFKernel;
+
+class HRTFDatabase : public Noncopyable {
+public:
+ static PassOwnPtr<HRTFDatabase> create(double sampleRate);
+
+ // getKernelsFromAzimuthElevation() returns a left and right ear kernel, and an interpolated left and right frame delay for the given azimuth and elevation.
+ // azimuthBlend must be in the range 0 -> 1.
+ // Valid values for azimuthIndex are 0 -> HRTFElevation::NumberOfTotalAzimuths - 1 (corresponding to angles of 0 -> 360).
+ // Valid values for elevationAngle are MinElevation -> MaxElevation.
+ void getKernelsFromAzimuthElevation(double azimuthBlend, unsigned azimuthIndex, double elevationAngle, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR);
+
+ // Returns the number of different azimuth angles.
+ static unsigned numberOfAzimuths() { return HRTFElevation::NumberOfTotalAzimuths; }
+
+ double sampleRate() const { return m_sampleRate; }
+
+private:
+ explicit HRTFDatabase(double sampleRate);
+
+ // Minimum and maximum elevation angles (inclusive) for a HRTFDatabase.
+ static const int MinElevation;
+ static const int MaxElevation;
+ static const unsigned RawElevationAngleSpacing;
+
+ // Number of elevations loaded from resource.
+ static const unsigned NumberOfRawElevations;
+
+ // Interpolates by this factor to get the total number of elevations from every elevation loaded from resource.
+ static const unsigned InterpolationFactor;
+
+ // Total number of elevations after interpolation.
+ static const unsigned NumberOfTotalElevations;
+
+ // Returns the index for the correct HRTFElevation given the elevation angle.
+ static unsigned indexFromElevationAngle(double);
+
+ Vector<OwnPtr<HRTFElevation> > m_elevations;
+ double m_sampleRate;
+};
+
+} // namespace WebCore
+
+#endif // HRTFDatabase_h
diff --git a/Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp b/Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp
new file mode 100644
index 0000000..4368d22
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFDatabaseLoader.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 "HRTFDatabaseLoader.h"
+
+#include "HRTFDatabase.h"
+
+namespace WebCore {
+
+// Singleton
+HRTFDatabaseLoader* HRTFDatabaseLoader::s_loader = 0;
+
+PassRefPtr<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(double sampleRate)
+{
+ ASSERT(isMainThread());
+
+ RefPtr<HRTFDatabaseLoader> loader;
+
+ if (!s_loader) {
+ // Lazily create and load.
+ loader = adoptRef(new HRTFDatabaseLoader(sampleRate));
+ s_loader = loader.get();
+ loader->loadAsynchronously();
+ } else {
+ loader = s_loader;
+ ASSERT(sampleRate == loader->databaseSampleRate());
+ }
+
+ return loader;
+}
+
+HRTFDatabaseLoader::HRTFDatabaseLoader(double sampleRate)
+ : m_hrtfDatabase(0)
+ , m_databaseLoaderThread(0)
+ , m_startedLoadingDatabase(false)
+ , m_databaseSampleRate(sampleRate)
+{
+ ASSERT(isMainThread());
+}
+
+HRTFDatabaseLoader::~HRTFDatabaseLoader()
+{
+ ASSERT(isMainThread());
+
+ if (m_startedLoadingDatabase)
+ waitForThreadCompletion(m_databaseLoaderThread, 0);
+
+ m_startedLoadingDatabase = false;
+ m_databaseLoaderThread = 0;
+
+ m_hrtfDatabase.clear();
+
+ // Clear out singleton.
+ ASSERT(this == s_loader);
+ s_loader = 0;
+}
+
+
+// Asynchronously load the database in this thread.
+static void* databaseLoaderEntry(void* threadData)
+{
+ HRTFDatabaseLoader* loader = reinterpret_cast<HRTFDatabaseLoader*>(threadData);
+ ASSERT(loader);
+ loader->load();
+
+ return 0;
+}
+
+void HRTFDatabaseLoader::load()
+{
+ ASSERT(!isMainThread());
+ if (!m_hrtfDatabase.get()) {
+ // Load the default HRTF database.
+ m_hrtfDatabase = HRTFDatabase::create(m_databaseSampleRate);
+ }
+}
+
+void HRTFDatabaseLoader::loadAsynchronously()
+{
+ ASSERT(isMainThread());
+
+ if (!m_hrtfDatabase.get() && !m_startedLoadingDatabase) {
+ // Start the asynchronous database loading process.
+ m_startedLoadingDatabase = true;
+ m_databaseLoaderThread = createThread(databaseLoaderEntry, this, "HRTF database loader");
+ }
+}
+
+bool HRTFDatabaseLoader::isLoaded() const
+{
+ return m_hrtfDatabase.get();
+}
+
+HRTFDatabase* HRTFDatabaseLoader::defaultHRTFDatabase()
+{
+ if (!s_loader)
+ return 0;
+
+ return s_loader->database();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/HRTFDatabaseLoader.h b/Source/WebCore/platform/audio/HRTFDatabaseLoader.h
new file mode 100644
index 0000000..72002c5
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFDatabaseLoader.h
@@ -0,0 +1,85 @@
+/*
+ * 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 HRTFDatabaseLoader_h
+#define HRTFDatabaseLoader_h
+
+#include "HRTFDatabase.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+// HRTFDatabaseLoader will asynchronously load the default HRTFDatabase in a new thread.
+
+class HRTFDatabaseLoader : public RefCounted<HRTFDatabaseLoader> {
+public:
+ // Lazily creates the singleton HRTFDatabaseLoader (if not already created) and starts loading asynchronously (when created the first time).
+ // Returns the singleton HRTFDatabaseLoader.
+ // Must be called from the main thread.
+ static PassRefPtr<HRTFDatabaseLoader> createAndLoadAsynchronouslyIfNecessary(double sampleRate);
+
+ // Both constructor and destructor must be called from the main thread.
+ ~HRTFDatabaseLoader();
+
+ // Returns true once the default database has been completely loaded.
+ bool isLoaded() const;
+
+ HRTFDatabase* database() { return m_hrtfDatabase.get(); }
+
+ // Called in asynchronous loading thread.
+ void load();
+
+ // defaultHRTFDatabase() gives access to the loaded database.
+ // This can be called from any thread, but it is the callers responsibilty to call this while the context (and thus HRTFDatabaseLoader)
+ // is still alive. Otherwise this will return 0.
+ static HRTFDatabase* defaultHRTFDatabase();
+
+private:
+ // Both constructor and destructor must be called from the main thread.
+ explicit HRTFDatabaseLoader(double sampleRate);
+
+ // If it hasn't already been loaded, creates a new thread and initiates asynchronous loading of the default database.
+ // This must be called from the main thread.
+ void loadAsynchronously();
+
+ double databaseSampleRate() const { return m_databaseSampleRate; }
+
+ static HRTFDatabaseLoader* s_loader; // singleton
+ OwnPtr<HRTFDatabase> m_hrtfDatabase;
+ ThreadIdentifier m_databaseLoaderThread;
+ bool m_startedLoadingDatabase;
+ double m_databaseSampleRate;
+};
+
+
+} // namespace WebCore
+
+#endif // HRTFDatabaseLoader_h
diff --git a/Source/WebCore/platform/audio/HRTFElevation.cpp b/Source/WebCore/platform/audio/HRTFElevation.cpp
new file mode 100644
index 0000000..06d03ea
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFElevation.cpp
@@ -0,0 +1,266 @@
+/*
+ * 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 "HRTFElevation.h"
+
+#include "AudioBus.h"
+#include "AudioFileReader.h"
+#include "Biquad.h"
+#include "FFTFrame.h"
+#include "HRTFPanner.h"
+#include <algorithm>
+#include <math.h>
+#include <wtf/OwnPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+const unsigned HRTFElevation::AzimuthSpacing = 15;
+const unsigned HRTFElevation::NumberOfRawAzimuths = 360 / AzimuthSpacing;
+const unsigned HRTFElevation::InterpolationFactor = 8;
+const unsigned HRTFElevation::NumberOfTotalAzimuths = NumberOfRawAzimuths * InterpolationFactor;
+
+// Takes advantage of the symmetry and creates a composite version of the two measured versions. For example, we have both azimuth 30 and -30 degrees
+// where the roles of left and right ears are reversed with respect to each other.
+bool HRTFElevation::calculateSymmetricKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName,
+ RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR)
+{
+ RefPtr<HRTFKernel> kernelL1;
+ RefPtr<HRTFKernel> kernelR1;
+ bool success = calculateKernelsForAzimuthElevation(azimuth, elevation, sampleRate, subjectName, kernelL1, kernelR1);
+ if (!success)
+ return false;
+
+ // And symmetric version
+ int symmetricAzimuth = !azimuth ? 0 : 360 - azimuth;
+
+ RefPtr<HRTFKernel> kernelL2;
+ RefPtr<HRTFKernel> kernelR2;
+ success = calculateKernelsForAzimuthElevation(symmetricAzimuth, elevation, sampleRate, subjectName, kernelL2, kernelR2);
+ if (!success)
+ return false;
+
+ // Notice L/R reversal in symmetric version.
+ kernelL = HRTFKernel::createInterpolatedKernel(kernelL1.get(), kernelR2.get(), 0.5);
+ kernelR = HRTFKernel::createInterpolatedKernel(kernelR1.get(), kernelL2.get(), 0.5);
+
+ return true;
+}
+
+bool HRTFElevation::calculateKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName,
+ RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR)
+{
+ // Valid values for azimuth are 0 -> 345 in 15 degree increments.
+ // Valid values for elevation are -45 -> +90 in 15 degree increments.
+
+ bool isAzimuthGood = azimuth >= 0 && azimuth <= 345 && (azimuth / 15) * 15 == azimuth;
+ ASSERT(isAzimuthGood);
+ if (!isAzimuthGood)
+ return false;
+
+ bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 15) * 15 == elevation;
+ ASSERT(isElevationGood);
+ if (!isElevationGood)
+ return false;
+
+ // Construct the resource name from the subject name, azimuth, and elevation, for example:
+ // "IRC_Composite_C_R0195_T015_P000"
+ // Note: the passed in subjectName is not a string passed in via JavaScript or the web.
+ // It's passed in as an internal ASCII identifier and is an implementation detail.
+ int positiveElevation = elevation < 0 ? elevation + 360 : elevation;
+ String resourceName = String::format("IRC_%s_C_R0195_T%03d_P%03d", subjectName.utf8().data(), azimuth, positiveElevation);
+
+ OwnPtr<AudioBus> impulseResponse(AudioBus::loadPlatformResource(resourceName.utf8().data(), sampleRate));
+
+ ASSERT(impulseResponse.get());
+ if (!impulseResponse.get())
+ return false;
+
+ size_t responseLength = impulseResponse->length();
+ size_t expectedLength = static_cast<size_t>(256 * (sampleRate / 44100.0));
+
+ // Check number of channels and length. For now these are fixed and known.
+ bool isBusGood = responseLength == expectedLength && impulseResponse->numberOfChannels() == 2;
+ ASSERT(isBusGood);
+ if (!isBusGood)
+ return false;
+
+ AudioChannel* leftEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelLeft);
+ AudioChannel* rightEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelRight);
+
+ // Note that depending on the fftSize returned by the panner, we may be truncating the impulse response we just loaded in.
+ const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate);
+ kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate, true);
+ kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate, true);
+
+ return true;
+}
+
+// The range of elevations for the IRCAM impulse responses varies depending on azimuth, but the minimum elevation appears to always be -45.
+//
+// Here's how it goes:
+static int maxElevations[] = {
+ // Azimuth
+ //
+ 90, // 0
+ 45, // 15
+ 60, // 30
+ 45, // 45
+ 75, // 60
+ 45, // 75
+ 60, // 90
+ 45, // 105
+ 75, // 120
+ 45, // 135
+ 60, // 150
+ 45, // 165
+ 75, // 180
+ 45, // 195
+ 60, // 210
+ 45, // 225
+ 75, // 240
+ 45, // 255
+ 60, // 270
+ 45, // 285
+ 75, // 300
+ 45, // 315
+ 60, // 330
+ 45 // 345
+};
+
+PassOwnPtr<HRTFElevation> HRTFElevation::createForSubject(const String& subjectName, int elevation, double sampleRate)
+{
+ bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 15) * 15 == elevation;
+ ASSERT(isElevationGood);
+ if (!isElevationGood)
+ return 0;
+
+ OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
+ OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
+
+ // Load convolution kernels from HRTF files.
+ int interpolatedIndex = 0;
+ for (unsigned rawIndex = 0; rawIndex < NumberOfRawAzimuths; ++rawIndex) {
+ // Don't let elevation exceed maximum for this azimuth.
+ int maxElevation = maxElevations[rawIndex];
+ int actualElevation = min(elevation, maxElevation);
+
+ bool success = calculateKernelsForAzimuthElevation(rawIndex * AzimuthSpacing, actualElevation, sampleRate, subjectName, kernelListL->at(interpolatedIndex), kernelListR->at(interpolatedIndex));
+ if (!success)
+ return 0;
+
+ interpolatedIndex += InterpolationFactor;
+ }
+
+ // Now go back and interpolate intermediate azimuth values.
+ for (unsigned i = 0; i < NumberOfTotalAzimuths; i += InterpolationFactor) {
+ int j = (i + InterpolationFactor) % NumberOfTotalAzimuths;
+
+ // Create the interpolated convolution kernels and delays.
+ for (unsigned jj = 1; jj < InterpolationFactor; ++jj) {
+ double x = double(jj) / double(InterpolationFactor); // interpolate from 0 -> 1
+
+ (*kernelListL)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListL->at(i).get(), kernelListL->at(j).get(), x);
+ (*kernelListR)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListR->at(i).get(), kernelListR->at(j).get(), x);
+ }
+ }
+
+ OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), elevation, sampleRate));
+ return hrtfElevation.release();
+}
+
+PassOwnPtr<HRTFElevation> HRTFElevation::createByInterpolatingSlices(HRTFElevation* hrtfElevation1, HRTFElevation* hrtfElevation2, double x, double sampleRate)
+{
+ ASSERT(hrtfElevation1 && hrtfElevation2);
+ if (!hrtfElevation1 || !hrtfElevation2)
+ return 0;
+
+ ASSERT(x >= 0.0 && x < 1.0);
+
+ OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
+ OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
+
+ HRTFKernelList* kernelListL1 = hrtfElevation1->kernelListL();
+ HRTFKernelList* kernelListR1 = hrtfElevation1->kernelListR();
+ HRTFKernelList* kernelListL2 = hrtfElevation2->kernelListL();
+ HRTFKernelList* kernelListR2 = hrtfElevation2->kernelListR();
+
+ // Interpolate kernels of corresponding azimuths of the two elevations.
+ for (unsigned i = 0; i < NumberOfTotalAzimuths; ++i) {
+ (*kernelListL)[i] = HRTFKernel::createInterpolatedKernel(kernelListL1->at(i).get(), kernelListL2->at(i).get(), x);
+ (*kernelListR)[i] = HRTFKernel::createInterpolatedKernel(kernelListR1->at(i).get(), kernelListR2->at(i).get(), x);
+ }
+
+ // Interpolate elevation angle.
+ double angle = (1.0 - x) * hrtfElevation1->elevationAngle() + x * hrtfElevation2->elevationAngle();
+
+ OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), static_cast<int>(angle), sampleRate));
+ return hrtfElevation.release();
+}
+
+void HRTFElevation::getKernelsFromAzimuth(double azimuthBlend, unsigned azimuthIndex, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR)
+{
+ bool checkAzimuthBlend = azimuthBlend >= 0.0 && azimuthBlend < 1.0;
+ ASSERT(checkAzimuthBlend);
+ if (!checkAzimuthBlend)
+ azimuthBlend = 0.0;
+
+ unsigned numKernels = m_kernelListL->size();
+
+ bool isIndexGood = azimuthIndex < numKernels;
+ ASSERT(isIndexGood);
+ if (!isIndexGood) {
+ kernelL = 0;
+ kernelR = 0;
+ return;
+ }
+
+ // Return the left and right kernels.
+ kernelL = m_kernelListL->at(azimuthIndex).get();
+ kernelR = m_kernelListR->at(azimuthIndex).get();
+
+ frameDelayL = m_kernelListL->at(azimuthIndex)->frameDelay();
+ frameDelayR = m_kernelListR->at(azimuthIndex)->frameDelay();
+
+ int azimuthIndex2 = (azimuthIndex + 1) % numKernels;
+ double frameDelay2L = m_kernelListL->at(azimuthIndex2)->frameDelay();
+ double frameDelay2R = m_kernelListR->at(azimuthIndex2)->frameDelay();
+
+ // Linearly interpolate delays.
+ frameDelayL = (1.0 - azimuthBlend) * frameDelayL + azimuthBlend * frameDelay2L;
+ frameDelayR = (1.0 - azimuthBlend) * frameDelayR + azimuthBlend * frameDelay2R;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/HRTFElevation.h b/Source/WebCore/platform/audio/HRTFElevation.h
new file mode 100644
index 0000000..b388b34
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFElevation.h
@@ -0,0 +1,110 @@
+/*
+ * 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 HRTFElevation_h
+#define HRTFElevation_h
+
+#include "HRTFKernel.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+// HRTFElevation contains all of the HRTFKernels (one left ear and one right ear per azimuth angle) for a particular elevation.
+
+class HRTFElevation : public Noncopyable {
+public:
+ // Loads and returns an HRTFElevation with the given HRTF database subject name and elevation from browser (or WebKit.framework) resources.
+ // Normally, there will only be a single HRTF database set, but this API supports the possibility of multiple ones with different names.
+ // Interpolated azimuths will be generated based on InterpolationFactor.
+ // Valid values for elevation are -45 -> +90 in 15 degree increments.
+ static PassOwnPtr<HRTFElevation> createForSubject(const String& subjectName, int elevation, double sampleRate);
+
+ // Given two HRTFElevations, and an interpolation factor x: 0 -> 1, returns an interpolated HRTFElevation.
+ static PassOwnPtr<HRTFElevation> createByInterpolatingSlices(HRTFElevation* hrtfElevation1, HRTFElevation* hrtfElevation2, double x, double sampleRate);
+
+ // Returns the list of left or right ear HRTFKernels for all the azimuths going from 0 to 360 degrees.
+ HRTFKernelList* kernelListL() { return m_kernelListL.get(); }
+ HRTFKernelList* kernelListR() { return m_kernelListR.get(); }
+
+ double elevationAngle() const { return m_elevationAngle; }
+ unsigned numberOfAzimuths() { return NumberOfTotalAzimuths; }
+ double sampleRate() const { return m_sampleRate; }
+
+ // Returns the left and right kernels for the given azimuth index.
+ // The interpolated delays based on azimuthBlend: 0 -> 1 are returned in frameDelayL and frameDelayR.
+ void getKernelsFromAzimuth(double azimuthBlend, unsigned azimuthIndex, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR);
+
+ // Spacing, in degrees, between every azimuth loaded from resource.
+ static const unsigned AzimuthSpacing;
+
+ // Number of azimuths loaded from resource.
+ static const unsigned NumberOfRawAzimuths;
+
+ // Interpolates by this factor to get the total number of azimuths from every azimuth loaded from resource.
+ static const unsigned InterpolationFactor;
+
+ // Total number of azimuths after interpolation.
+ static const unsigned NumberOfTotalAzimuths;
+
+ // Given a specific azimuth and elevation angle, returns the left and right HRTFKernel.
+ // Valid values for azimuth are 0 -> 345 in 15 degree increments.
+ // Valid values for elevation are -45 -> +90 in 15 degree increments.
+ // Returns true on success.
+ static bool calculateKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName,
+ RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR);
+
+ // Given a specific azimuth and elevation angle, returns the left and right HRTFKernel in kernelL and kernelR.
+ // This method averages the measured response using symmetry of azimuth (for example by averaging the -30.0 and +30.0 azimuth responses).
+ // Returns true on success.
+ static bool calculateSymmetricKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName,
+ RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR);
+private:
+ HRTFElevation(PassOwnPtr<HRTFKernelList> kernelListL, PassOwnPtr<HRTFKernelList> kernelListR, int elevation, double sampleRate)
+ : m_kernelListL(kernelListL)
+ , m_kernelListR(kernelListR)
+ , m_elevationAngle(elevation)
+ , m_sampleRate(sampleRate)
+ {
+ }
+
+ OwnPtr<HRTFKernelList> m_kernelListL;
+ OwnPtr<HRTFKernelList> m_kernelListR;
+ double m_elevationAngle;
+ double m_sampleRate;
+};
+
+} // namespace WebCore
+
+#endif // HRTFElevation_h
diff --git a/Source/WebCore/platform/audio/HRTFKernel.cpp b/Source/WebCore/platform/audio/HRTFKernel.cpp
new file mode 100644
index 0000000..22d4b12
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFKernel.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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 "HRTFKernel.h"
+
+#include "AudioChannel.h"
+#include "Biquad.h"
+#include "FFTFrame.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// Takes the input AudioChannel as an input impulse response and calculates the average group delay.
+// This represents the initial delay before the most energetic part of the impulse response.
+// The sample-frame delay is removed from the impulseP impulse response, and this value is returned.
+// the length of the passed in AudioChannel must be a power of 2.
+static double extractAverageGroupDelay(AudioChannel* channel)
+{
+ ASSERT(channel);
+
+ float* impulseP = channel->data();
+ size_t length = channel->length();
+
+ // Check that length is power-of-2;
+ ASSERT(1UL << static_cast<unsigned>(log2(length)) == length);
+
+ FFTFrame estimationFrame(length);
+ estimationFrame.doFFT(impulseP);
+
+ double frameDelay = estimationFrame.extractAverageGroupDelay();
+ estimationFrame.doInverseFFT(impulseP);
+
+ return frameDelay;
+}
+
+HRTFKernel::HRTFKernel(AudioChannel* channel, size_t fftSize, double sampleRate, bool bassBoost)
+ : m_frameDelay(0.0)
+ , m_sampleRate(sampleRate)
+{
+ ASSERT(channel);
+
+ // Determine the leading delay (average group delay) for the response.
+ m_frameDelay = extractAverageGroupDelay(channel);
+
+ float* impulseResponse = channel->data();
+ size_t responseLength = channel->length();
+
+ if (bassBoost) {
+ // Run through some post-processing to boost the bass a little -- the HRTF's seem to be a little bass-deficient.
+ // FIXME: this post-processing should have already been applied to the HRTF file resources. Once the files are put into this form,
+ // then this code path can be removed along with the bassBoost parameter.
+ Biquad filter;
+ filter.setLowShelfParams(700.0 / nyquist(), 6.0); // boost 6dB at 700Hz
+ filter.process(impulseResponse, impulseResponse, responseLength);
+ }
+
+ // We need to truncate to fit into 1/2 the FFT size (with zero padding) in order to do proper convolution.
+ size_t truncatedResponseLength = min(responseLength, fftSize / 2); // truncate if necessary to max impulse response length allowed by FFT
+
+ // Quick fade-out (apply window) at truncation point
+ unsigned numberOfFadeOutFrames = static_cast<unsigned>(sampleRate / 4410); // 10 sample-frames @44.1KHz sample-rate
+ ASSERT(numberOfFadeOutFrames < truncatedResponseLength);
+ if (numberOfFadeOutFrames < truncatedResponseLength) {
+ for (unsigned i = truncatedResponseLength - numberOfFadeOutFrames; i < truncatedResponseLength; ++i) {
+ float x = 1.0f - static_cast<float>(i - (truncatedResponseLength - numberOfFadeOutFrames)) / numberOfFadeOutFrames;
+ impulseResponse[i] *= x;
+ }
+ }
+
+ m_fftFrame = adoptPtr(new FFTFrame(fftSize));
+ m_fftFrame->doPaddedFFT(impulseResponse, truncatedResponseLength);
+}
+
+PassOwnPtr<AudioChannel> HRTFKernel::createImpulseResponse()
+{
+ OwnPtr<AudioChannel> channel = adoptPtr(new AudioChannel(fftSize()));
+ FFTFrame fftFrame(*m_fftFrame);
+
+ // Add leading delay back in.
+ fftFrame.addConstantGroupDelay(m_frameDelay);
+ fftFrame.doInverseFFT(channel->data());
+
+ return channel.release();
+}
+
+// Interpolates two kernels with x: 0 -> 1 and returns the result.
+PassRefPtr<HRTFKernel> HRTFKernel::createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, double x)
+{
+ ASSERT(kernel1 && kernel2);
+ if (!kernel1 || !kernel2)
+ return 0;
+
+ ASSERT(x >= 0.0 && x < 1.0);
+ x = min(1.0, max(0.0, x));
+
+ double sampleRate1 = kernel1->sampleRate();
+ double sampleRate2 = kernel2->sampleRate();
+ ASSERT(sampleRate1 == sampleRate2);
+ if (sampleRate1 != sampleRate2)
+ return 0;
+
+ double frameDelay = (1.0 - x) * kernel1->frameDelay() + x * kernel2->frameDelay();
+
+ OwnPtr<FFTFrame> interpolatedFrame = FFTFrame::createInterpolatedFrame(*kernel1->fftFrame(), *kernel2->fftFrame(), x);
+ return HRTFKernel::create(interpolatedFrame.release(), frameDelay, sampleRate1);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/HRTFKernel.h b/Source/WebCore/platform/audio/HRTFKernel.h
new file mode 100644
index 0000000..572a085
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFKernel.h
@@ -0,0 +1,98 @@
+/*
+ * 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 HRTFKernel_h
+#define HRTFKernel_h
+
+#include "FFTFrame.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AudioChannel;
+
+// HRTF stands for Head-Related Transfer Function.
+// HRTFKernel is a frequency-domain representation of an impulse-response used as part of the spatialized panning system.
+// For a given azimuth / elevation angle there will be one HRTFKernel for the left ear transfer function, and one for the right ear.
+// The leading delay (average group delay) for each impulse response is extracted:
+// m_fftFrame is the frequency-domain representation of the impulse response with the delay removed
+// m_frameDelay is the leading delay of the original impulse response.
+class HRTFKernel : public RefCounted<HRTFKernel> {
+public:
+ // Note: this is destructive on the passed in AudioChannel.
+ // The length of channel must be a power of two.
+ static PassRefPtr<HRTFKernel> create(AudioChannel* channel, size_t fftSize, double sampleRate, bool bassBoost)
+ {
+ return adoptRef(new HRTFKernel(channel, fftSize, sampleRate, bassBoost));
+ }
+
+ static PassRefPtr<HRTFKernel> create(PassOwnPtr<FFTFrame> fftFrame, double frameDelay, double sampleRate)
+ {
+ return adoptRef(new HRTFKernel(fftFrame, frameDelay, sampleRate));
+ }
+
+ // Given two HRTFKernels, and an interpolation factor x: 0 -> 1, returns an interpolated HRTFKernel.
+ static PassRefPtr<HRTFKernel> createInterpolatedKernel(HRTFKernel* kernel1, HRTFKernel* kernel2, double x);
+
+ FFTFrame* fftFrame() { return m_fftFrame.get(); }
+
+ size_t fftSize() const { return m_fftFrame->fftSize(); }
+ double frameDelay() const { return m_frameDelay; }
+
+ double sampleRate() const { return m_sampleRate; }
+ double nyquist() const { return 0.5 * sampleRate(); }
+
+ // Converts back into impulse-response form.
+ PassOwnPtr<AudioChannel> createImpulseResponse();
+
+private:
+ // Note: this is destructive on the passed in AudioChannel.
+ HRTFKernel(AudioChannel* channel, size_t fftSize, double sampleRate, bool bassBoost);
+
+ HRTFKernel(PassOwnPtr<FFTFrame> fftFrame, double frameDelay, double sampleRate)
+ : m_fftFrame(fftFrame)
+ , m_frameDelay(frameDelay)
+ , m_sampleRate(sampleRate)
+ {
+ }
+
+ OwnPtr<FFTFrame> m_fftFrame;
+ double m_frameDelay;
+ double m_sampleRate;
+};
+
+typedef Vector<RefPtr<HRTFKernel> > HRTFKernelList;
+
+} // namespace WebCore
+
+#endif // HRTFKernel_h
diff --git a/Source/WebCore/platform/audio/HRTFPanner.cpp b/Source/WebCore/platform/audio/HRTFPanner.cpp
new file mode 100644
index 0000000..68bc505
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFPanner.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "HRTFPanner.h"
+
+#include "AudioBus.h"
+#include "FFTConvolver.h"
+#include "HRTFDatabase.h"
+#include "HRTFDatabaseLoader.h"
+#include <algorithm>
+#include <wtf/MathExtras.h>
+#include <wtf/RefPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// The value of 2 milliseconds is larger than the largest delay which exists in any HRTFKernel from the default HRTFDatabase (0.0136 seconds).
+// We ASSERT the delay values used in process() with this value.
+const double MaxDelayTimeSeconds = 0.002;
+
+HRTFPanner::HRTFPanner(double sampleRate)
+ : Panner(PanningModelHRTF)
+ , m_sampleRate(sampleRate)
+ , m_isFirstRender(true)
+ , m_azimuthIndex(0)
+ , m_convolverL(fftSizeForSampleRate(sampleRate))
+ , m_convolverR(fftSizeForSampleRate(sampleRate))
+ , m_delayLineL(MaxDelayTimeSeconds, sampleRate)
+ , m_delayLineR(MaxDelayTimeSeconds, sampleRate)
+{
+}
+
+HRTFPanner::~HRTFPanner()
+{
+}
+
+size_t HRTFPanner::fftSizeForSampleRate(double sampleRate)
+{
+ // The HRTF impulse responses (loaded as audio resources) are 512 sample-frames @44.1KHz.
+ // Currently, we truncate the impulse responses to half this size, but an FFT-size of twice impulse response size is needed (for convolution).
+ // So for sample rates around 44.1KHz an FFT size of 512 is good. We double that size for higher sample rates.
+ ASSERT(sampleRate >= 44100 && sampleRate <= 96000.0);
+ return (sampleRate <= 48000.0) ? 512 : 1024;
+}
+
+void HRTFPanner::reset()
+{
+ m_isFirstRender = true;
+ m_convolverL.reset();
+ m_convolverR.reset();
+ m_delayLineL.reset();
+ m_delayLineR.reset();
+}
+
+static bool wrapDistance(int i, int j, int length)
+{
+ int directDistance = abs(i - j);
+ int indirectDistance = length - directDistance;
+
+ return indirectDistance < directDistance;
+}
+
+int HRTFPanner::calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azimuthBlend)
+{
+ // Convert the azimuth angle from the range -180 -> +180 into the range 0 -> 360.
+ // The azimuth index may then be calculated from this positive value.
+ if (azimuth < 0)
+ azimuth += 360.0;
+
+ HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase();
+ ASSERT(database);
+
+ int numberOfAzimuths = database->numberOfAzimuths();
+ const double angleBetweenAzimuths = 360.0 / numberOfAzimuths;
+
+ // Calculate the azimuth index and the blend (0 -> 1) for interpolation.
+ double desiredAzimuthIndexFloat = azimuth / angleBetweenAzimuths;
+ int desiredAzimuthIndex = static_cast<int>(desiredAzimuthIndexFloat);
+ azimuthBlend = desiredAzimuthIndexFloat - static_cast<double>(desiredAzimuthIndex);
+
+ // We don't immediately start using this azimuth index, but instead approach this index from the last index we rendered at.
+ // This minimizes the clicks and graininess for moving sources which occur otherwise.
+ desiredAzimuthIndex = max(0, desiredAzimuthIndex);
+ desiredAzimuthIndex = min(numberOfAzimuths - 1, desiredAzimuthIndex);
+ return desiredAzimuthIndex;
+}
+
+void HRTFPanner::pan(double desiredAzimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess)
+{
+ unsigned numInputChannels = inputBus ? inputBus->numberOfChannels() : 0;
+
+ bool isInputGood = inputBus && numInputChannels >= 1 && numInputChannels <= 2;
+ ASSERT(isInputGood);
+
+ bool isOutputGood = outputBus && outputBus->numberOfChannels() == 2 && framesToProcess <= outputBus->length();
+ ASSERT(isOutputGood);
+
+ if (!isInputGood || !isOutputGood) {
+ if (outputBus)
+ outputBus->zero();
+ return;
+ }
+
+ // This code only runs as long as the context is alive and after database has been loaded.
+ HRTFDatabase* database = HRTFDatabaseLoader::defaultHRTFDatabase();
+ ASSERT(database);
+ if (!database) {
+ outputBus->zero();
+ return;
+ }
+
+ // IRCAM HRTF azimuths values from the loaded database is reversed from the panner's notion of azimuth.
+ double azimuth = -desiredAzimuth;
+
+ bool isAzimuthGood = azimuth >= -180.0 && azimuth <= 180.0;
+ ASSERT(isAzimuthGood);
+ if (!isAzimuthGood) {
+ outputBus->zero();
+ return;
+ }
+
+ // Normally, we'll just be dealing with mono sources.
+ // If we have a stereo input, implement stereo panning with left source processed by left HRTF, and right source by right HRTF.
+ AudioChannel* inputChannelL = inputBus->channelByType(AudioBus::ChannelLeft);
+ AudioChannel* inputChannelR = numInputChannels > 1 ? inputBus->channelByType(AudioBus::ChannelRight) : 0;
+
+ // Get source and destination pointers.
+ float* sourceL = inputChannelL->data();
+ float* sourceR = numInputChannels > 1 ? inputChannelR->data() : sourceL;
+ float* destinationL = outputBus->channelByType(AudioBus::ChannelLeft)->data();
+ float* destinationR = outputBus->channelByType(AudioBus::ChannelRight)->data();
+
+ double azimuthBlend;
+ int desiredAzimuthIndex = calculateDesiredAzimuthIndexAndBlend(azimuth, azimuthBlend);
+
+ // This algorithm currently requires that we process in power-of-two size chunks at least 128.
+ ASSERT(1UL << static_cast<int>(log2(framesToProcess)) == framesToProcess);
+ ASSERT(framesToProcess >= 128);
+
+ const unsigned framesPerSegment = 128;
+ const unsigned numberOfSegments = framesToProcess / framesPerSegment;
+
+ for (unsigned segment = 0; segment < numberOfSegments; ++segment) {
+ if (m_isFirstRender) {
+ // Snap exactly to desired position (first time and after reset()).
+ m_azimuthIndex = desiredAzimuthIndex;
+ m_isFirstRender = false;
+ } else {
+ // Each segment renders with an azimuth index closer by one to the desired azimuth index.
+ // Because inter-aural time delay is mostly a factor of azimuth and the delay is where the clicks and graininess come from,
+ // we don't bother smoothing the elevations.
+ int numberOfAzimuths = database->numberOfAzimuths();
+ bool wrap = wrapDistance(m_azimuthIndex, desiredAzimuthIndex, numberOfAzimuths);
+ if (wrap) {
+ if (m_azimuthIndex < desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex - 1 + numberOfAzimuths) % numberOfAzimuths;
+ else if (m_azimuthIndex > desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex + 1) % numberOfAzimuths;
+ } else {
+ if (m_azimuthIndex < desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex + 1) % numberOfAzimuths;
+ else if (m_azimuthIndex > desiredAzimuthIndex)
+ m_azimuthIndex = (m_azimuthIndex - 1 + numberOfAzimuths) % numberOfAzimuths;
+ }
+ }
+
+ // Get the HRTFKernels and interpolated delays.
+ HRTFKernel* kernelL;
+ HRTFKernel* kernelR;
+ double frameDelayL;
+ double frameDelayR;
+ database->getKernelsFromAzimuthElevation(azimuthBlend, m_azimuthIndex, elevation, kernelL, kernelR, frameDelayL, frameDelayR);
+
+ ASSERT(kernelL && kernelR);
+ if (!kernelL || !kernelR) {
+ outputBus->zero();
+ return;
+ }
+
+ ASSERT(frameDelayL / sampleRate() < MaxDelayTimeSeconds && frameDelayR / sampleRate() < MaxDelayTimeSeconds);
+
+ // Calculate the source and destination pointers for the current segment.
+ unsigned offset = segment * framesPerSegment;
+ float* segmentSourceL = sourceL + offset;
+ float* segmentSourceR = sourceR + offset;
+ float* segmentDestinationL = destinationL + offset;
+ float* segmentDestinationR = destinationR + offset;
+
+ // First run through delay lines for inter-aural time difference.
+ m_delayLineL.setDelayFrames(frameDelayL);
+ m_delayLineR.setDelayFrames(frameDelayR);
+ m_delayLineL.process(segmentSourceL, segmentDestinationL, framesPerSegment);
+ m_delayLineR.process(segmentSourceR, segmentDestinationR, framesPerSegment);
+
+ // Now do the convolutions in-place.
+ m_convolverL.process(kernelL->fftFrame(), segmentDestinationL, segmentDestinationL, framesPerSegment);
+ m_convolverR.process(kernelR->fftFrame(), segmentDestinationR, segmentDestinationR, framesPerSegment);
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/HRTFPanner.h b/Source/WebCore/platform/audio/HRTFPanner.h
new file mode 100644
index 0000000..6c13d48
--- /dev/null
+++ b/Source/WebCore/platform/audio/HRTFPanner.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef HRTFPanner_h
+#define HRTFPanner_h
+
+#include "DelayDSPKernel.h"
+#include "FFTConvolver.h"
+#include "Panner.h"
+
+namespace WebCore {
+
+class HRTFPanner : public Panner {
+public:
+ explicit HRTFPanner(double sampleRate);
+ virtual ~HRTFPanner();
+
+ // Panner
+ virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess);
+ virtual void reset();
+
+ size_t fftSize() { return fftSizeForSampleRate(m_sampleRate); }
+ static size_t fftSizeForSampleRate(double sampleRate);
+
+ double sampleRate() const { return m_sampleRate; }
+
+private:
+ // Given an azimuth angle in the range -180 -> +180, returns the corresponding azimuth index for the database,
+ // and azimuthBlend which is an interpolation value from 0 -> 1.
+ int calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azimuthBlend);
+
+ double m_sampleRate;
+
+ // m_isFirstRender and m_azimuthIndex are used to avoid harshly changing from rendering at one azimuth angle to another angle very far away.
+ // Changing the azimuth gradually produces a smoother sound.
+ bool m_isFirstRender;
+ int m_azimuthIndex;
+
+ FFTConvolver m_convolverL;
+ FFTConvolver m_convolverR;
+ DelayDSPKernel m_delayLineL;
+ DelayDSPKernel m_delayLineR;
+};
+
+} // namespace WebCore
+
+#endif // HRTFPanner_h
diff --git a/Source/WebCore/platform/audio/Panner.cpp b/Source/WebCore/platform/audio/Panner.cpp
new file mode 100644
index 0000000..5e8efca
--- /dev/null
+++ b/Source/WebCore/platform/audio/Panner.cpp
@@ -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.
+ * 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 "Panner.h"
+
+#include "EqualPowerPanner.h"
+#include "HRTFPanner.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<Panner> Panner::create(PanningModel model, double sampleRate)
+{
+ OwnPtr<Panner> panner;
+
+ switch (model) {
+ case PanningModelEqualPower:
+ panner = adoptPtr(new EqualPowerPanner(sampleRate));
+ break;
+
+ case PanningModelHRTF:
+ panner = adoptPtr(new HRTFPanner(sampleRate));
+ break;
+
+ // FIXME: sound field panning is not yet implemented...
+ case PanningModelSoundField:
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+
+ return panner.release();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/Panner.h b/Source/WebCore/platform/audio/Panner.h
new file mode 100644
index 0000000..b57ceda
--- /dev/null
+++ b/Source/WebCore/platform/audio/Panner.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 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 Panner_h
+#define Panner_h
+
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class AudioBus;
+
+// Abstract base class for panning a mono or stereo source.
+
+class Panner {
+public:
+ enum {
+ PanningModelEqualPower = 0,
+ PanningModelHRTF = 1,
+ PanningModelSoundField = 2
+ };
+
+ typedef unsigned PanningModel;
+
+ static PassOwnPtr<Panner> create(PanningModel model, double sampleRate);
+
+ virtual ~Panner() { };
+
+ PanningModel panningModel() const { return m_panningModel; }
+
+ virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) = 0;
+
+ virtual void reset() = 0;
+
+protected:
+ Panner(PanningModel model) : m_panningModel(model) { }
+
+ PanningModel m_panningModel;
+};
+
+} // namespace WebCore
+
+#endif // Panner_h
diff --git a/Source/WebCore/platform/audio/Reverb.cpp b/Source/WebCore/platform/audio/Reverb.cpp
new file mode 100644
index 0000000..e59ff46
--- /dev/null
+++ b/Source/WebCore/platform/audio/Reverb.cpp
@@ -0,0 +1,227 @@
+/*
+ * 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 "Reverb.h"
+
+#include "AudioBus.h"
+#include "AudioFileReader.h"
+#include "ReverbConvolver.h"
+#include <math.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+#if OS(DARWIN)
+using namespace std;
+#endif
+
+namespace WebCore {
+
+// Empirical gain calibration tested across many impulse responses to ensure perceived volume is same as dry (unprocessed) signal
+const double GainCalibration = -58.0;
+
+// A minimum power value to when normalizing a silent (or very quiet) impulse response
+const double MinPower = 0.000125;
+
+static double calculateNormalizationScale(AudioBus* response)
+{
+ // Normalize by RMS power
+ size_t numberOfChannels = response->numberOfChannels();
+ size_t length = response->length();
+
+ double power = 0.0;
+
+ for (size_t i = 0; i < numberOfChannels; ++i) {
+ int n = length;
+ float* p = response->channel(i)->data();
+
+ while (n--) {
+ float sample = *p++;
+ power += sample * sample;
+ }
+ }
+
+ power = sqrt(power / (numberOfChannels * length));
+
+ // Protect against accidental overload
+ if (isinf(power) || isnan(power) || power < MinPower)
+ power = MinPower;
+
+ double scale = 1.0 / power;
+
+ scale *= pow(10.0, GainCalibration * 0.05); // calibrate to make perceived volume same as unprocessed
+
+ // True-stereo compensation
+ if (response->numberOfChannels() == 4)
+ scale *= 0.5;
+
+ return scale;
+}
+
+Reverb::Reverb(AudioBus* impulseResponse, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads)
+{
+ double scale = calculateNormalizationScale(impulseResponse);
+ if (scale)
+ impulseResponse->scale(scale);
+
+ initialize(impulseResponse, renderSliceSize, maxFFTSize, numberOfChannels, useBackgroundThreads);
+
+ // Undo scaling since this shouldn't be a destructive operation on impulseResponse
+ if (scale)
+ impulseResponse->scale(1.0 / scale);
+}
+
+void Reverb::initialize(AudioBus* impulseResponseBuffer, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads)
+{
+ m_impulseResponseLength = impulseResponseBuffer->length();
+
+ // The reverb can handle a mono impulse response and still do stereo processing
+ size_t numResponseChannels = impulseResponseBuffer->numberOfChannels();
+ m_convolvers.reserveCapacity(numberOfChannels);
+
+ int convolverRenderPhase = 0;
+ for (size_t i = 0; i < numResponseChannels; ++i) {
+ AudioChannel* channel = impulseResponseBuffer->channel(i);
+
+ OwnPtr<ReverbConvolver> convolver = adoptPtr(new ReverbConvolver(channel, renderSliceSize, maxFFTSize, convolverRenderPhase, useBackgroundThreads));
+ m_convolvers.append(convolver.release());
+
+ convolverRenderPhase += renderSliceSize;
+ }
+
+ // For "True" stereo processing we allocate a temporary buffer to avoid repeatedly allocating it in the process() method.
+ // It can be bad to allocate memory in a real-time thread.
+ if (numResponseChannels == 4)
+ m_tempBuffer = new AudioBus(2, MaxFrameSize);
+}
+
+void Reverb::process(AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess)
+{
+ // Do a fairly comprehensive sanity check.
+ // If these conditions are satisfied, all of the source and destination pointers will be valid for the various matrixing cases.
+ bool isSafeToProcess = sourceBus && destinationBus && sourceBus->numberOfChannels() > 0 && destinationBus->numberOfChannels() > 0
+ && framesToProcess <= MaxFrameSize && framesToProcess <= sourceBus->length() && framesToProcess <= destinationBus->length();
+
+ ASSERT(isSafeToProcess);
+ if (!isSafeToProcess)
+ return;
+
+ // For now only handle mono or stereo output
+ if (destinationBus->numberOfChannels() > 2) {
+ destinationBus->zero();
+ return;
+ }
+
+ AudioChannel* destinationChannelL = destinationBus->channel(0);
+ AudioChannel* sourceChannelL = sourceBus->channel(0);
+
+ // Handle input -> output matrixing...
+ size_t numInputChannels = sourceBus->numberOfChannels();
+ size_t numOutputChannels = destinationBus->numberOfChannels();
+ size_t numReverbChannels = m_convolvers.size();
+
+ if (numInputChannels == 2 && numReverbChannels == 2 && numOutputChannels == 2) {
+ // 2 -> 2 -> 2
+ AudioChannel* sourceChannelR = sourceBus->channel(1);
+ AudioChannel* destinationChannelR = destinationBus->channel(1);
+ m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
+ m_convolvers[1]->process(sourceChannelR, destinationChannelR, framesToProcess);
+ } else if (numInputChannels == 1 && numOutputChannels == 2 && numReverbChannels == 2) {
+ // 1 -> 2 -> 2
+ for (int i = 0; i < 2; ++i) {
+ AudioChannel* destinationChannel = destinationBus->channel(i);
+ m_convolvers[i]->process(sourceChannelL, destinationChannel, framesToProcess);
+ }
+ } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 2) {
+ // 1 -> 1 -> 2
+ m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
+
+ // simply copy L -> R
+ AudioChannel* destinationChannelR = destinationBus->channel(1);
+ bool isCopySafe = destinationChannelL->data() && destinationChannelR->data() && destinationChannelL->length() >= framesToProcess && destinationChannelR->length() >= framesToProcess;
+ ASSERT(isCopySafe);
+ if (!isCopySafe)
+ return;
+ memcpy(destinationChannelR->data(), destinationChannelL->data(), sizeof(float) * framesToProcess);
+ } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) {
+ // 1 -> 1 -> 1
+ m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
+ } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) {
+ // 2 -> 4 -> 2 ("True" stereo)
+ AudioChannel* sourceChannelR = sourceBus->channel(1);
+ AudioChannel* destinationChannelR = destinationBus->channel(1);
+
+ AudioChannel* tempChannelL = m_tempBuffer->channel(0);
+ AudioChannel* tempChannelR = m_tempBuffer->channel(1);
+
+ // Process left virtual source
+ m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
+ m_convolvers[1]->process(sourceChannelL, destinationChannelR, framesToProcess);
+
+ // Process right virtual source
+ m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess);
+ m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess);
+
+ destinationBus->sumFrom(*m_tempBuffer);
+ } else if (numInputChannels == 1 && numReverbChannels == 4 && numOutputChannels == 2) {
+ // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response)
+ // This is an inefficient use of a four-channel impulse response, but we should handle the case.
+ AudioChannel* destinationChannelR = destinationBus->channel(1);
+
+ AudioChannel* tempChannelL = m_tempBuffer->channel(0);
+ AudioChannel* tempChannelR = m_tempBuffer->channel(1);
+
+ // Process left virtual source
+ m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess);
+ m_convolvers[1]->process(sourceChannelL, destinationChannelR, framesToProcess);
+
+ // Process right virtual source
+ m_convolvers[2]->process(sourceChannelL, tempChannelL, framesToProcess);
+ m_convolvers[3]->process(sourceChannelL, tempChannelR, framesToProcess);
+
+ destinationBus->sumFrom(*m_tempBuffer);
+ } else {
+ // Handle gracefully any unexpected / unsupported matrixing
+ // FIXME: add code for 5.1 support...
+ destinationBus->zero();
+ }
+}
+
+void Reverb::reset()
+{
+ for (size_t i = 0; i < m_convolvers.size(); ++i)
+ m_convolvers[i]->reset();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/Reverb.h b/Source/WebCore/platform/audio/Reverb.h
new file mode 100644
index 0000000..26f5f8e
--- /dev/null
+++ b/Source/WebCore/platform/audio/Reverb.h
@@ -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.
+ * 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 Reverb_h
+#define Reverb_h
+
+#include "ReverbConvolver.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AudioBus;
+
+// Multi-channel convolution reverb with channel matrixing - one or more ReverbConvolver objects are used internally.
+
+class Reverb {
+public:
+ enum { MaxFrameSize = 256 };
+
+ // renderSliceSize is a rendering hint, so the FFTs can be optimized to not all occur at the same time (very bad when rendering on a real-time thread).
+ Reverb(AudioBus* impulseResponseBuffer, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads);
+
+ void process(AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess);
+ void reset();
+
+ unsigned impulseResponseLength() const { return m_impulseResponseLength; }
+
+private:
+ void initialize(AudioBus* impulseResponseBuffer, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads);
+
+ size_t m_impulseResponseLength;
+
+ Vector<OwnPtr<ReverbConvolver> > m_convolvers;
+
+ // For "True" stereo processing
+ OwnPtr<AudioBus> m_tempBuffer;
+};
+
+} // namespace WebCore
+
+#endif // Reverb_h
diff --git a/Source/WebCore/platform/audio/ReverbAccumulationBuffer.cpp b/Source/WebCore/platform/audio/ReverbAccumulationBuffer.cpp
new file mode 100644
index 0000000..3d694d1
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbAccumulationBuffer.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 "ReverbAccumulationBuffer.h"
+
+#include "VectorMath.h"
+
+namespace WebCore {
+
+using namespace VectorMath;
+
+ReverbAccumulationBuffer::ReverbAccumulationBuffer(size_t length)
+ : m_buffer(length)
+ , m_readIndex(0)
+ , m_readTimeFrame(0)
+{
+}
+
+void ReverbAccumulationBuffer::readAndClear(float* destination, size_t numberOfFrames)
+{
+ size_t bufferLength = m_buffer.size();
+ bool isCopySafe = m_readIndex <= bufferLength && numberOfFrames <= bufferLength;
+
+ ASSERT(isCopySafe);
+ if (!isCopySafe)
+ return;
+
+ size_t framesAvailable = bufferLength - m_readIndex;
+ size_t numberOfFrames1 = std::min(numberOfFrames, framesAvailable);
+ size_t numberOfFrames2 = numberOfFrames - numberOfFrames1;
+
+ float* source = m_buffer.data();
+ memcpy(destination, source + m_readIndex, sizeof(float) * numberOfFrames1);
+ memset(source + m_readIndex, 0, sizeof(float) * numberOfFrames1);
+
+ // Handle wrap-around if necessary
+ if (numberOfFrames2 > 0) {
+ memcpy(destination + numberOfFrames1, source, sizeof(float) * numberOfFrames2);
+ memset(source, 0, sizeof(float) * numberOfFrames2);
+ }
+
+ m_readIndex = (m_readIndex + numberOfFrames) % bufferLength;
+ m_readTimeFrame += numberOfFrames;
+}
+
+void ReverbAccumulationBuffer::updateReadIndex(int* readIndex, size_t numberOfFrames) const
+{
+ // Update caller's readIndex
+ *readIndex = (*readIndex + numberOfFrames) % m_buffer.size();
+}
+
+int ReverbAccumulationBuffer::accumulate(float* source, size_t numberOfFrames, int* readIndex, size_t delayFrames)
+{
+ size_t bufferLength = m_buffer.size();
+
+ size_t writeIndex = (*readIndex + delayFrames) % bufferLength;
+
+ // Update caller's readIndex
+ *readIndex = (*readIndex + numberOfFrames) % bufferLength;
+
+ size_t framesAvailable = bufferLength - writeIndex;
+ size_t numberOfFrames1 = std::min(numberOfFrames, framesAvailable);
+ size_t numberOfFrames2 = numberOfFrames - numberOfFrames1;
+
+ float* destination = m_buffer.data();
+
+ bool isSafe = writeIndex <= bufferLength && numberOfFrames1 + writeIndex <= bufferLength && numberOfFrames2 <= bufferLength;
+ ASSERT(isSafe);
+ if (!isSafe)
+ return 0;
+
+ vadd(source, 1, destination + writeIndex, 1, destination + writeIndex, 1, numberOfFrames1);
+
+ // Handle wrap-around if necessary
+ if (numberOfFrames2 > 0)
+ vadd(source + numberOfFrames1, 1, destination, 1, destination, 1, numberOfFrames2);
+
+ return writeIndex;
+}
+
+void ReverbAccumulationBuffer::reset()
+{
+ m_buffer.zero();
+ m_readIndex = 0;
+ m_readTimeFrame = 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/ReverbAccumulationBuffer.h b/Source/WebCore/platform/audio/ReverbAccumulationBuffer.h
new file mode 100644
index 0000000..f5ead2a
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbAccumulationBuffer.h
@@ -0,0 +1,67 @@
+/*
+ * 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 ReverbAccumulationBuffer_h
+#define ReverbAccumulationBuffer_h
+
+#include "AudioArray.h"
+
+namespace WebCore {
+
+// ReverbAccumulationBuffer is a circular delay buffer with one client reading from it and multiple clients
+// writing/accumulating to it at different delay offsets from the read position. The read operation will zero the memory
+// just read from the buffer, so it will be ready for accumulation the next time around.
+class ReverbAccumulationBuffer {
+public:
+ ReverbAccumulationBuffer(size_t length);
+
+ // This will read from, then clear-out numberOfFrames
+ void readAndClear(float* destination, size_t numberOfFrames);
+
+ // Each ReverbConvolverStage will accumulate its output at the appropriate delay from the read position.
+ // We need to pass in and update readIndex here, since each ReverbConvolverStage may be running in
+ // a different thread than the realtime thread calling ReadAndClear() and maintaining m_readIndex
+ // Returns the writeIndex where the accumulation took place
+ int accumulate(float* source, size_t numberOfFrames, int* readIndex, size_t delayFrames);
+
+ size_t readIndex() const { return m_readIndex; }
+ void updateReadIndex(int* readIndex, size_t numberOfFrames) const;
+
+ size_t readTimeFrame() const { return m_readTimeFrame; }
+
+ void reset();
+
+private:
+ AudioFloatArray m_buffer;
+ size_t m_readIndex;
+ size_t m_readTimeFrame; // for debugging (frame on continuous timeline)
+};
+
+} // namespace WebCore
+
+#endif // ReverbAccumulationBuffer_h
diff --git a/Source/WebCore/platform/audio/ReverbConvolver.cpp b/Source/WebCore/platform/audio/ReverbConvolver.cpp
new file mode 100644
index 0000000..120c9f2
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbConvolver.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 "ReverbConvolver.h"
+
+#include "VectorMath.h"
+#include "AudioBus.h"
+
+namespace WebCore {
+
+using namespace VectorMath;
+
+const int InputBufferSize = 8 * 16384;
+
+// We only process the leading portion of the impulse response in the real-time thread. We don't exceed this length.
+// It turns out then, that the background thread has about 278msec of scheduling slop.
+// Empirically, this has been found to be a good compromise between giving enough time for scheduling slop,
+// while still minimizing the amount of processing done in the primary (high-priority) thread.
+// This was found to be a good value on Mac OS X, and may work well on other platforms as well, assuming
+// the very rough scheduling latencies are similar on these time-scales. Of course, this code may need to be
+// tuned for individual platforms if this assumption is found to be incorrect.
+const size_t RealtimeFrameLimit = 8192 + 4096; // ~278msec @ 44.1KHz
+
+const size_t MinFFTSize = 256;
+const size_t MaxRealtimeFFTSize = 2048;
+
+static void* backgroundThreadEntry(void* threadData)
+{
+ ReverbConvolver* reverbConvolver = static_cast<ReverbConvolver*>(threadData);
+ reverbConvolver->backgroundThreadEntry();
+ return 0;
+}
+
+ReverbConvolver::ReverbConvolver(AudioChannel* impulseResponse, size_t renderSliceSize, size_t maxFFTSize, size_t convolverRenderPhase, bool useBackgroundThreads)
+ : m_impulseResponseLength(impulseResponse->length())
+ , m_accumulationBuffer(impulseResponse->length() + renderSliceSize)
+ , m_inputBuffer(InputBufferSize)
+ , m_renderSliceSize(renderSliceSize)
+ , m_minFFTSize(MinFFTSize) // First stage will have this size - successive stages will double in size each time
+ , m_maxFFTSize(maxFFTSize) // until we hit m_maxFFTSize
+ , m_useBackgroundThreads(useBackgroundThreads)
+ , m_backgroundThread(0)
+ , m_wantsToExit(false)
+ , m_moreInputBuffered(false)
+{
+ // If we are using background threads then don't exceed this FFT size for the
+ // stages which run in the real-time thread. This avoids having only one or two
+ // large stages (size 16384 or so) at the end which take a lot of time every several
+ // processing slices. This way we amortize the cost over more processing slices.
+ m_maxRealtimeFFTSize = MaxRealtimeFFTSize;
+
+ // For the moment, a good way to know if we have real-time constraint is to check if we're using background threads.
+ // Otherwise, assume we're being run from a command-line tool.
+ bool hasRealtimeConstraint = useBackgroundThreads;
+
+ float* response = impulseResponse->data();
+ size_t totalResponseLength = impulseResponse->length();
+
+ // Because we're not using direct-convolution in the leading portion, the reverb has an overall latency of half the first-stage FFT size
+ size_t reverbTotalLatency = m_minFFTSize / 2;
+
+ size_t stageOffset = 0;
+ int i = 0;
+ size_t fftSize = m_minFFTSize;
+ while (stageOffset < totalResponseLength) {
+ size_t stageSize = fftSize / 2;
+
+ // For the last stage, it's possible that stageOffset is such that we're straddling the end
+ // of the impulse response buffer (if we use stageSize), so reduce the last stage's length...
+ if (stageSize + stageOffset > totalResponseLength)
+ stageSize = totalResponseLength - stageOffset;
+
+ // This "staggers" the time when each FFT happens so they don't all happen at the same time
+ int renderPhase = convolverRenderPhase + i * renderSliceSize;
+
+ OwnPtr<ReverbConvolverStage> stage(new ReverbConvolverStage(response, totalResponseLength, reverbTotalLatency, stageOffset, stageSize, fftSize, renderPhase, renderSliceSize, &m_accumulationBuffer));
+
+ bool isBackgroundStage = false;
+
+ if (this->useBackgroundThreads() && stageOffset > RealtimeFrameLimit) {
+ m_backgroundStages.append(stage.release());
+ isBackgroundStage = true;
+ } else
+ m_stages.append(stage.release());
+
+ stageOffset += stageSize;
+ ++i;
+
+ // Figure out next FFT size
+ fftSize *= 2;
+ if (hasRealtimeConstraint && !isBackgroundStage && fftSize > m_maxRealtimeFFTSize)
+ fftSize = m_maxRealtimeFFTSize;
+ if (fftSize > m_maxFFTSize)
+ fftSize = m_maxFFTSize;
+ }
+
+ // Start up background thread
+ // FIXME: would be better to up the thread priority here. It doesn't need to be real-time, but higher than the default...
+ if (this->useBackgroundThreads() && m_backgroundStages.size() > 0)
+ m_backgroundThread = createThread(WebCore::backgroundThreadEntry, this, "convolution background thread");
+}
+
+ReverbConvolver::~ReverbConvolver()
+{
+ // Wait for background thread to stop
+ if (useBackgroundThreads() && m_backgroundThread) {
+ m_wantsToExit = true;
+
+ // Wake up thread so it can return
+ {
+ MutexLocker locker(m_backgroundThreadLock);
+ m_moreInputBuffered = true;
+ m_backgroundThreadCondition.signal();
+ }
+
+ waitForThreadCompletion(m_backgroundThread, 0);
+ }
+}
+
+void ReverbConvolver::backgroundThreadEntry()
+{
+ while (!m_wantsToExit) {
+ // Wait for realtime thread to give us more input
+ m_moreInputBuffered = false;
+ {
+ MutexLocker locker(m_backgroundThreadLock);
+ while (!m_moreInputBuffered && !m_wantsToExit)
+ m_backgroundThreadCondition.wait(m_backgroundThreadLock);
+ }
+
+ // Process all of the stages until their read indices reach the input buffer's write index
+ int writeIndex = m_inputBuffer.writeIndex();
+
+ // Even though it doesn't seem like every stage needs to maintain its own version of readIndex
+ // we do this in case we want to run in more than one background thread.
+ int readIndex;
+
+ while ((readIndex = m_backgroundStages[0]->inputReadIndex()) != writeIndex) { // FIXME: do better to detect buffer overrun...
+ // The ReverbConvolverStages need to process in amounts which evenly divide half the FFT size
+ const int SliceSize = MinFFTSize / 2;
+
+ // Accumulate contributions from each stage
+ for (size_t i = 0; i < m_backgroundStages.size(); ++i)
+ m_backgroundStages[i]->processInBackground(this, SliceSize);
+ }
+ }
+}
+
+void ReverbConvolver::process(AudioChannel* sourceChannel, AudioChannel* destinationChannel, size_t framesToProcess)
+{
+ bool isSafe = sourceChannel && destinationChannel && sourceChannel->length() >= framesToProcess && destinationChannel->length() >= framesToProcess;
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ float* source = sourceChannel->data();
+ float* destination = destinationChannel->data();
+ bool isDataSafe = source && destination;
+ ASSERT(isDataSafe);
+ if (!isDataSafe)
+ return;
+
+ // Feed input buffer (read by all threads)
+ m_inputBuffer.write(source, framesToProcess);
+
+ // Accumulate contributions from each stage
+ for (size_t i = 0; i < m_stages.size(); ++i)
+ m_stages[i]->process(source, framesToProcess);
+
+ // Finally read from accumulation buffer
+ m_accumulationBuffer.readAndClear(destination, framesToProcess);
+
+ // Now that we've buffered more input, wake up our background thread.
+
+ // Not using a MutexLocker looks strange, but we use a tryLock() instead because this is run on the real-time
+ // thread where it is a disaster for the lock to be contended (causes audio glitching). It's OK if we fail to
+ // signal from time to time, since we'll get to it the next time we're called. We're called repeatedly
+ // and frequently (around every 3ms). The background thread is processing well into the future and has a considerable amount of
+ // leeway here...
+ if (m_backgroundThreadLock.tryLock()) {
+ m_moreInputBuffered = true;
+ m_backgroundThreadCondition.signal();
+ m_backgroundThreadLock.unlock();
+ }
+}
+
+void ReverbConvolver::reset()
+{
+ for (size_t i = 0; i < m_stages.size(); ++i)
+ m_stages[i]->reset();
+
+ for (size_t i = 0; i < m_backgroundStages.size(); ++i)
+ m_backgroundStages[i]->reset();
+
+ m_accumulationBuffer.reset();
+ m_inputBuffer.reset();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/ReverbConvolver.h b/Source/WebCore/platform/audio/ReverbConvolver.h
new file mode 100644
index 0000000..013b684
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbConvolver.h
@@ -0,0 +1,97 @@
+/*
+ * 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 ReverbConvolver_h
+#define ReverbConvolver_h
+
+#include "AudioArray.h"
+#include "FFTConvolver.h"
+#include "ReverbAccumulationBuffer.h"
+#include "ReverbConvolverStage.h"
+#include "ReverbInputBuffer.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AudioChannel;
+
+class ReverbConvolver {
+public:
+ // maxFFTSize can be adjusted (from say 2048 to 32768) depending on how much precision is necessary.
+ // For certain tweaky de-convolving applications the phase errors add up quickly and lead to non-sensical results with
+ // larger FFT sizes and single-precision floats. In these cases 2048 is a good size.
+ // If not doing multi-threaded convolution, then should not go > 8192.
+ ReverbConvolver(AudioChannel* impulseResponse, size_t renderSliceSize, size_t maxFFTSize, size_t convolverRenderPhase, bool useBackgroundThreads);
+ ~ReverbConvolver();
+
+ void process(AudioChannel* sourceChannel, AudioChannel* destinationChannel, size_t framesToProcess);
+ void reset();
+
+ size_t impulseResponseLength() const { return m_impulseResponseLength; }
+
+ ReverbInputBuffer* inputBuffer() { return &m_inputBuffer; }
+
+ bool useBackgroundThreads() const { return m_useBackgroundThreads; }
+ void backgroundThreadEntry();
+
+private:
+ Vector<OwnPtr<ReverbConvolverStage> > m_stages;
+ Vector<OwnPtr<ReverbConvolverStage> > m_backgroundStages;
+ size_t m_impulseResponseLength;
+
+ ReverbAccumulationBuffer m_accumulationBuffer;
+
+ // One or more background threads read from this input buffer which is fed from the realtime thread.
+ ReverbInputBuffer m_inputBuffer;
+
+ // We're given a rendering hint, so the FFTs can be optimized to not all occur at the same time
+ // (very bad when rendering on a real-time thread).
+ size_t m_renderSliceSize;
+
+ // First stage will be of size m_minFFTSize. Each next stage will be twice as big until we hit m_maxFFTSize.
+ size_t m_minFFTSize;
+ size_t m_maxFFTSize;
+
+ // But don't exceed this size in the real-time thread (if we're doing background processing).
+ size_t m_maxRealtimeFFTSize;
+
+ // Background thread and synchronization
+ bool m_useBackgroundThreads;
+ ThreadIdentifier m_backgroundThread;
+ bool m_wantsToExit;
+ bool m_moreInputBuffered;
+ mutable Mutex m_backgroundThreadLock;
+ mutable ThreadCondition m_backgroundThreadCondition;
+};
+
+} // namespace WebCore
+
+#endif // ReverbConvolver_h
diff --git a/Source/WebCore/platform/audio/ReverbConvolverStage.cpp b/Source/WebCore/platform/audio/ReverbConvolverStage.cpp
new file mode 100644
index 0000000..e722813
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbConvolverStage.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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 "ReverbConvolverStage.h"
+
+#include "VectorMath.h"
+#include "ReverbAccumulationBuffer.h"
+#include "ReverbConvolver.h"
+#include "ReverbInputBuffer.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+using namespace VectorMath;
+
+ReverbConvolverStage::ReverbConvolverStage(float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength,
+ size_t fftSize, size_t renderPhase, size_t renderSliceSize, ReverbAccumulationBuffer* accumulationBuffer)
+ : m_fftKernel(fftSize)
+ , m_accumulationBuffer(accumulationBuffer)
+ , m_accumulationReadIndex(0)
+ , m_inputReadIndex(0)
+ , m_impulseResponseLength(responseLength)
+{
+ ASSERT(impulseResponse);
+ ASSERT(accumulationBuffer);
+
+ m_fftKernel.doPaddedFFT(impulseResponse + stageOffset, stageLength);
+ m_convolver = adoptPtr(new FFTConvolver(fftSize));
+ m_temporaryBuffer.resize(renderSliceSize);
+
+ // The convolution stage at offset stageOffset needs to have a corresponding delay to cancel out the offset.
+ size_t totalDelay = stageOffset + reverbTotalLatency;
+
+ // But, the FFT convolution itself incurs fftSize / 2 latency, so subtract this out...
+ size_t halfSize = fftSize / 2;
+ ASSERT(totalDelay >= halfSize);
+ if (totalDelay >= halfSize)
+ totalDelay -= halfSize;
+
+ // We divide up the total delay, into pre and post delay sections so that we can schedule at exactly the moment when the FFT will happen.
+ // This is coordinated with the other stages, so they don't all do their FFTs at the same time...
+ int maxPreDelayLength = std::min(halfSize, totalDelay);
+ m_preDelayLength = totalDelay > 0 ? renderPhase % maxPreDelayLength : 0;
+ if (m_preDelayLength > totalDelay)
+ m_preDelayLength = 0;
+
+ m_postDelayLength = totalDelay - m_preDelayLength;
+ m_preReadWriteIndex = 0;
+ m_framesProcessed = 0; // total frames processed so far
+
+ m_preDelayBuffer.resize(m_preDelayLength < fftSize ? fftSize : m_preDelayLength);
+}
+
+void ReverbConvolverStage::processInBackground(ReverbConvolver* convolver, size_t framesToProcess)
+{
+ ReverbInputBuffer* inputBuffer = convolver->inputBuffer();
+ float* source = inputBuffer->directReadFrom(&m_inputReadIndex, framesToProcess);
+ process(source, framesToProcess);
+}
+
+void ReverbConvolverStage::process(float* source, size_t framesToProcess)
+{
+ ASSERT(source);
+ if (!source)
+ return;
+
+ // Deal with pre-delay stream : note special handling of zero delay.
+
+ float* preDelayedSource;
+ float* temporaryBuffer;
+ bool isTemporaryBufferSafe = false;
+ if (m_preDelayLength > 0) {
+ // Handles both the read case (call to process() ) and the write case (memcpy() )
+ bool isPreDelaySafe = m_preReadWriteIndex + framesToProcess <= m_preDelayBuffer.size();
+ ASSERT(isPreDelaySafe);
+ if (!isPreDelaySafe)
+ return;
+
+ isTemporaryBufferSafe = framesToProcess <= m_temporaryBuffer.size();
+
+ preDelayedSource = m_preDelayBuffer.data() + m_preReadWriteIndex;
+ temporaryBuffer = m_temporaryBuffer.data();
+ } else {
+ // Zero delay
+ preDelayedSource = source;
+ temporaryBuffer = m_preDelayBuffer.data();
+
+ isTemporaryBufferSafe = framesToProcess <= m_preDelayBuffer.size();
+ }
+
+ ASSERT(isTemporaryBufferSafe);
+ if (!isTemporaryBufferSafe)
+ return;
+
+ int writeIndex = 0;
+
+ if (m_framesProcessed < m_preDelayLength) {
+ // For the first m_preDelayLength frames don't process the convolver, instead simply buffer in the pre-delay.
+ // But while buffering the pre-delay, we still need to update our index.
+ m_accumulationBuffer->updateReadIndex(&m_accumulationReadIndex, framesToProcess);
+ } else {
+ // Now, run the convolution (into the delay buffer).
+ // An expensive FFT will happen every fftSize / 2 frames.
+ // We process in-place here...
+ m_convolver->process(&m_fftKernel, preDelayedSource, temporaryBuffer, framesToProcess);
+
+ // Now accumulate into reverb's accumulation buffer.
+ writeIndex = m_accumulationBuffer->accumulate(temporaryBuffer, framesToProcess, &m_accumulationReadIndex, m_postDelayLength);
+ }
+
+ // Finally copy input to pre-delay.
+ if (m_preDelayLength > 0) {
+ memcpy(preDelayedSource, source, sizeof(float) * framesToProcess);
+ m_preReadWriteIndex += framesToProcess;
+
+ ASSERT(m_preReadWriteIndex <= m_preDelayLength);
+ if (m_preReadWriteIndex >= m_preDelayLength)
+ m_preReadWriteIndex = 0;
+ }
+
+ m_framesProcessed += framesToProcess;
+}
+
+void ReverbConvolverStage::reset()
+{
+ m_convolver->reset();
+ m_preDelayBuffer.zero();
+ m_accumulationReadIndex = 0;
+ m_inputReadIndex = 0;
+ m_framesProcessed = 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/ReverbConvolverStage.h b/Source/WebCore/platform/audio/ReverbConvolverStage.h
new file mode 100644
index 0000000..fc05a0e
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbConvolverStage.h
@@ -0,0 +1,83 @@
+/*
+ * 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 ReverbConvolverStage_h
+#define ReverbConvolverStage_h
+
+#include "AudioArray.h"
+#include "FFTFrame.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class ReverbAccumulationBuffer;
+class ReverbConvolver;
+class FFTConvolver;
+
+// A ReverbConvolverStage represents the convolution associated with a sub-section of a large impulse response.
+// It incorporates a delay line to account for the offset of the sub-section within the larger impulse response.
+class ReverbConvolverStage {
+public:
+ // renderPhase is useful to know so that we can manipulate the pre versus post delay so that stages will perform
+ // their heavy work (FFT processing) on different slices to balance the load in a real-time thread.
+ ReverbConvolverStage(float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength,
+ size_t fftSize, size_t renderPhase, size_t renderSliceSize, ReverbAccumulationBuffer* accumulationBuffer);
+
+ // WARNING: framesToProcess must be such that it evenly divides the delay buffer size (stage_offset).
+ void process(float* source, size_t framesToProcess);
+
+ void processInBackground(ReverbConvolver* convolver, size_t framesToProcess);
+
+ void reset();
+
+ // Useful for background processing
+ int inputReadIndex() const { return m_inputReadIndex; }
+
+private:
+ FFTFrame m_fftKernel;
+ OwnPtr<FFTConvolver> m_convolver;
+
+ AudioFloatArray m_preDelayBuffer;
+
+ ReverbAccumulationBuffer* m_accumulationBuffer;
+ int m_accumulationReadIndex;
+ int m_inputReadIndex;
+
+ size_t m_preDelayLength;
+ size_t m_postDelayLength;
+ size_t m_preReadWriteIndex;
+ size_t m_framesProcessed;
+
+ AudioFloatArray m_temporaryBuffer;
+
+ size_t m_impulseResponseLength;
+};
+
+} // namespace WebCore
+
+#endif // ReverbConvolverStage_h
diff --git a/Source/WebCore/platform/audio/ReverbInputBuffer.cpp b/Source/WebCore/platform/audio/ReverbInputBuffer.cpp
new file mode 100644
index 0000000..f270f6f
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbInputBuffer.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "ReverbInputBuffer.h"
+
+namespace WebCore {
+
+ReverbInputBuffer::ReverbInputBuffer(size_t length)
+ : m_buffer(length)
+ , m_writeIndex(0)
+{
+}
+
+void ReverbInputBuffer::write(float* sourceP, size_t numberOfFrames)
+{
+ size_t bufferLength = m_buffer.size();
+ bool isCopySafe = m_writeIndex + numberOfFrames <= bufferLength;
+ ASSERT(isCopySafe);
+ if (!isCopySafe)
+ return;
+
+ memcpy(m_buffer.data() + m_writeIndex, sourceP, sizeof(float) * numberOfFrames);
+
+ m_writeIndex += numberOfFrames;
+ ASSERT(m_writeIndex <= bufferLength);
+
+ if (m_writeIndex >= bufferLength)
+ m_writeIndex = 0;
+}
+
+float* ReverbInputBuffer::directReadFrom(int* readIndex, size_t numberOfFrames)
+{
+ size_t bufferLength = m_buffer.size();
+ bool isPointerGood = readIndex && *readIndex >= 0 && *readIndex + numberOfFrames <= bufferLength;
+ ASSERT(isPointerGood);
+ if (!isPointerGood) {
+ // Should never happen in practice but return pointer to start of buffer (avoid crash)
+ if (readIndex)
+ *readIndex = 0;
+ return m_buffer.data();
+ }
+
+ float* sourceP = m_buffer.data();
+ float* p = sourceP + *readIndex;
+
+ // Update readIndex
+ *readIndex = (*readIndex + numberOfFrames) % bufferLength;
+
+ return p;
+}
+
+void ReverbInputBuffer::reset()
+{
+ m_buffer.zero();
+ m_writeIndex = 0;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/ReverbInputBuffer.h b/Source/WebCore/platform/audio/ReverbInputBuffer.h
new file mode 100644
index 0000000..15a2818
--- /dev/null
+++ b/Source/WebCore/platform/audio/ReverbInputBuffer.h
@@ -0,0 +1,64 @@
+/*
+ * 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 ReverbInputBuffer_h
+#define ReverbInputBuffer_h
+
+#include "AudioArray.h"
+
+namespace WebCore {
+
+// ReverbInputBuffer is used to buffer input samples for deferred processing by the background threads.
+class ReverbInputBuffer {
+public:
+ ReverbInputBuffer(size_t length);
+
+ // The realtime audio thread keeps writing samples here.
+ // The assumption is that the buffer's length is evenly divisible by numberOfFrames (for nearly all cases this will be fine).
+ // FIXME: remove numberOfFrames restriction...
+ void write(float* sourceP, size_t numberOfFrames);
+
+ // Background threads can call this to check if there's anything to read...
+ size_t writeIndex() const { return m_writeIndex; }
+
+ // The individual background threads read here (and hope that they can keep up with the buffer writing).
+ // readIndex is updated with the next readIndex to read from...
+ // The assumption is that the buffer's length is evenly divisible by numberOfFrames.
+ // FIXME: remove numberOfFrames restriction...
+ float* directReadFrom(int* readIndex, size_t numberOfFrames);
+
+ void reset();
+
+private:
+ AudioFloatArray m_buffer;
+ size_t m_writeIndex;
+};
+
+} // namespace WebCore
+
+#endif // ReverbInputBuffer_h
diff --git a/Source/WebCore/platform/audio/VectorMath.cpp b/Source/WebCore/platform/audio/VectorMath.cpp
new file mode 100644
index 0000000..64e192b
--- /dev/null
+++ b/Source/WebCore/platform/audio/VectorMath.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "VectorMath.h"
+
+#if OS(DARWIN)
+#include <Accelerate/Accelerate.h>
+#endif
+
+namespace WebCore {
+
+namespace VectorMath {
+
+#if OS(DARWIN)
+// On the Mac we use the highly optimized versions in Accelerate.framework
+// In 32-bit mode (__ppc__ or __i386__) <Accelerate/Accelerate.h> includes <vecLib/vDSP_translate.h> which defines macros of the same name as
+// our namespaced function names, so we must handle this case differently. Other architectures (64bit, ARM, etc.) do not include this header file.
+
+void vsmul(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess)
+{
+#if defined(__ppc__) || defined(__i386__)
+ ::vsmul(sourceP, sourceStride, scale, destP, destStride, framesToProcess);
+#else
+ vDSP_vsmul(sourceP, sourceStride, scale, destP, destStride, framesToProcess);
+#endif
+}
+
+void vadd(const float* source1P, int sourceStride1, const float* source2P, int sourceStride2, float* destP, int destStride, size_t framesToProcess)
+{
+#if defined(__ppc__) || defined(__i386__)
+ ::vadd(source1P, sourceStride1, source2P, sourceStride2, destP, destStride, framesToProcess);
+#else
+ vDSP_vadd(source1P, sourceStride1, source2P, sourceStride2, destP, destStride, framesToProcess);
+#endif
+}
+
+#else
+
+void vsmul(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess)
+{
+ // FIXME: optimize for SSE
+ int n = framesToProcess;
+ float k = *scale;
+ while (n--) {
+ *destP = k * *sourceP;
+ sourceP += sourceStride;
+ destP += destStride;
+ }
+}
+
+void vadd(const float* source1P, int sourceStride1, const float* source2P, int sourceStride2, float* destP, int destStride, size_t framesToProcess)
+{
+ // FIXME: optimize for SSE
+ int n = framesToProcess;
+ while (n--) {
+ *destP = *source1P + *source2P;
+ source1P += sourceStride1;
+ source2P += sourceStride2;
+ destP += destStride;
+ }
+}
+
+#endif // OS(DARWIN)
+
+} // namespace VectorMath
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/VectorMath.h b/Source/WebCore/platform/audio/VectorMath.h
new file mode 100644
index 0000000..0360bdb
--- /dev/null
+++ b/Source/WebCore/platform/audio/VectorMath.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef VectorMath_h
+#define VectorMath_h
+
+// Defines the interface for several vector math functions whose implementation will ideally be optimized.
+
+namespace WebCore {
+
+namespace VectorMath {
+
+void vsmul(const float* sourceP, int sourceStride, const float* scale, float* destP, int destStride, size_t framesToProcess);
+void vadd(const float* source1P, int sourceStride1, const float* source2P, int sourceStride2, float* destP, int destStride, size_t framesToProcess);
+
+} // namespace VectorMath
+
+} // namespace WebCore
+
+#endif // VectorMath_h
diff --git a/Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp b/Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp
new file mode 100644
index 0000000..a93703d
--- /dev/null
+++ b/Source/WebCore/platform/audio/chromium/AudioBusChromium.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioBus.h"
+
+#include "AudioFileReader.h"
+#include "ChromiumBridge.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+// We will use this version of loadPlatformResource() once the resources are checked into Chromium.
+
+// PassOwnPtr<AudioBus> AudioBus::loadPlatformResource(const char* name, double sampleRate)
+// {
+// return ChromiumBridge::loadPlatformAudioResource(name, sampleRate);
+// }
+
+PassOwnPtr<AudioBus> createBusFromInMemoryAudioFile(const void* data, size_t dataSize, bool mixToMono, double sampleRate)
+{
+ OwnPtr<AudioBus> audioBus = ChromiumBridge::decodeAudioFileData(static_cast<const char*>(data), dataSize, sampleRate);
+ if (audioBus->numberOfChannels() == 2 && mixToMono) {
+ OwnPtr<AudioBus> monoAudioBus = adoptPtr(new AudioBus(1, audioBus->length()));
+
+ // FIXME: AudioBus::copyFrom() should be able to do a downmix to mono.
+ // for now simply copy the left channel.
+ monoAudioBus->channel(0)->copyFrom(audioBus->channel(0));
+ return monoAudioBus.release();
+ }
+
+ return audioBus.release();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
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)
diff --git a/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp
new file mode 100644
index 0000000..f66a485
--- /dev/null
+++ b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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 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.
+ */
+
+// FFTFrame implementation using Intel's Math Kernel Library (MKL),
+// suitable for use on Windows and Linux.
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "FFTFrame.h"
+
+#include "mkl_vml.h"
+#include <wtf/MathExtras.h>
+
+namespace {
+
+DFTI_DESCRIPTOR_HANDLE createDescriptorHandle(int fftSize)
+{
+ DFTI_DESCRIPTOR_HANDLE handle = 0;
+
+ // Create DFTI descriptor for 1D single precision transform.
+ MKL_LONG status = DftiCreateDescriptor(&handle, DFTI_SINGLE, DFTI_REAL, 1, fftSize);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set placement of result to DFTI_NOT_INPLACE.
+ status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set packing format to PERM; this produces the layout which
+ // matches Accelerate.framework's on the Mac, though interleaved.
+ status = DftiSetValue(handle, DFTI_PACKED_FORMAT, DFTI_PERM_FORMAT);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set the forward scale factor to 2 to match Accelerate.framework's.
+ // FIXME: FFTFrameMac's scaling factor could be fixed to be 1.0,
+ // in which case this code would need to be changed as well.
+ status = DftiSetValue(handle, DFTI_FORWARD_SCALE, 2.0);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set the backward scale factor to 1 / 2n to match Accelerate.framework's.
+ // FIXME: if the above scaling factor is fixed then this needs to be as well.
+ double scale = 1.0 / (2.0 * fftSize);
+ status = DftiSetValue(handle, DFTI_BACKWARD_SCALE, scale);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Use the default DFTI_CONJUGATE_EVEN_STORAGE = DFTI_COMPLEX_REAL.
+
+ // Commit DFTI descriptor.
+ status = DftiCommitDescriptor(handle);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ return handle;
+}
+
+} // anonymous namespace
+
+namespace WebCore {
+
+const int kMaxFFTPow2Size = 24;
+
+DFTI_DESCRIPTOR_HANDLE* FFTFrame::descriptorHandles = 0;
+
+// Normal constructor: allocates for a given fftSize.
+FFTFrame::FFTFrame(unsigned fftSize)
+ : m_FFTSize(fftSize)
+ , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
+ , m_handle(0)
+ , m_complexData(fftSize)
+ , m_realData(fftSize / 2)
+ , m_imagData(fftSize / 2)
+{
+ // We only allow power of two.
+ ASSERT(1UL << m_log2FFTSize == m_FFTSize);
+
+ m_handle = descriptorHandleForSize(fftSize);
+}
+
+// Creates a blank/empty frame (interpolate() must later be called).
+FFTFrame::FFTFrame()
+ : m_FFTSize(0)
+ , m_log2FFTSize(0)
+ , m_handle(0)
+{
+}
+
+// Copy constructor.
+FFTFrame::FFTFrame(const FFTFrame& frame)
+ : m_FFTSize(frame.m_FFTSize)
+ , m_log2FFTSize(frame.m_log2FFTSize)
+ , m_handle(0)
+ , m_complexData(frame.m_FFTSize)
+ , m_realData(frame.m_FFTSize / 2)
+ , m_imagData(frame.m_FFTSize / 2)
+{
+ m_handle = descriptorHandleForSize(m_FFTSize);
+
+ // Copy/setup frame data.
+ unsigned nbytes = sizeof(float) * (m_FFTSize / 2);
+ memcpy(realData(), frame.realData(), nbytes);
+ memcpy(imagData(), frame.imagData(), nbytes);
+}
+
+FFTFrame::~FFTFrame()
+{
+}
+
+void FFTFrame::multiply(const FFTFrame& frame)
+{
+ FFTFrame& frame1 = *this;
+ FFTFrame& frame2 = const_cast<FFTFrame&>(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.
+ // FIXME: this scaling factor will be 1.0f if the above 2.0 -> 1.0
+ // scaling factor is fixed.
+ 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.
+ float* interleavedData1 = frame1.getUpToDateComplexData();
+ float* interleavedData2 = frame2.getUpToDateComplexData();
+
+ unsigned halfSize = m_FFTSize / 2;
+
+ // Complex multiply.
+ vcMul(halfSize - 1,
+ reinterpret_cast<MKL_Complex8*>(interleavedData1) + 1,
+ reinterpret_cast<MKL_Complex8*>(interleavedData2) + 1,
+ reinterpret_cast<MKL_Complex8*>(interleavedData1) + 1);
+
+ // De-interleave and scale the rest of the data.
+ // FIXME: find an MKL routine to do at least the scaling more efficiently.
+ for (unsigned i = 1; i < halfSize; ++i) {
+ int baseComplexIndex = 2 * i;
+ realP1[i] = scale * interleavedData1[baseComplexIndex];
+ imagP1[i] = scale * interleavedData1[baseComplexIndex + 1];
+ }
+}
+
+void FFTFrame::doFFT(float* data)
+{
+ // Compute Forward transform.
+ MKL_LONG status = DftiComputeForward(m_handle, data, m_complexData.data());
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // De-interleave to separate real and complex arrays. FIXME:
+ // figure out if it's possible to get MKL to use split-complex
+ // form for 1D real-to-complex out-of-place FFTs.
+ int len = m_FFTSize / 2;
+ for (int i = 0; i < len; ++i) {
+ int baseComplexIndex = 2 * i;
+ // m_realData[0] is the DC component and m_imagData[0] the
+ // Nyquist component since the interleaved complex data is
+ // packed.
+ m_realData[i] = m_complexData[baseComplexIndex];
+ m_imagData[i] = m_complexData[baseComplexIndex + 1];
+ }
+}
+
+void FFTFrame::doInverseFFT(float* data)
+{
+ // Prepare interleaved data. FIXME: figure out if it's possible to
+ // get MKL to use split-complex form for 1D backward
+ // (complex-to-real) out-of-place FFTs.
+ float* interleavedData = getUpToDateComplexData();
+
+ // Compute backward transform.
+ MKL_LONG status = DftiComputeBackward(m_handle, interleavedData, data);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+}
+
+void FFTFrame::cleanup()
+{
+ if (!descriptorHandles)
+ return;
+
+ for (int i = 0; i < kMaxFFTPow2Size; ++i) {
+ if (descriptorHandles[i]) {
+ MKL_LONG status = DftiFreeDescriptor(&descriptorHandles[i]);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+ }
+ }
+
+ delete[] descriptorHandles;
+ descriptorHandles = 0;
+}
+
+float* FFTFrame::realData() const
+{
+ return const_cast<float*>(m_realData.data());
+}
+
+float* FFTFrame::imagData() const
+{
+ return const_cast<float*>(m_imagData.data());
+}
+
+float* FFTFrame::getUpToDateComplexData()
+{
+ // FIXME: if we can't completely get rid of this method, SSE
+ // optimization could be considered if it shows up hot on profiles.
+ int len = m_FFTSize / 2;
+ for (int i = 0; i < len; ++i) {
+ int baseComplexIndex = 2 * i;
+ m_complexData[baseComplexIndex] = m_realData[i];
+ m_complexData[baseComplexIndex + 1] = m_imagData[i];
+ }
+ return const_cast<float*>(m_complexData.data());
+}
+
+DFTI_DESCRIPTOR_HANDLE FFTFrame::descriptorHandleForSize(unsigned fftSize)
+{
+ if (!descriptorHandles) {
+ descriptorHandles = new DFTI_DESCRIPTOR_HANDLE[kMaxFFTPow2Size];
+ for (int i = 0; i < kMaxFFTPow2Size; ++i)
+ descriptorHandles[i] = 0;
+ }
+
+ ASSERT(fftSize);
+ int pow2size = static_cast<int>(log2(fftSize));
+ ASSERT(pow2size < kMaxFFTPow2Size);
+ if (!descriptorHandles[pow2size])
+ descriptorHandles[pow2size] = createDescriptorHandle(fftSize);
+ return descriptorHandles[pow2size];
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P000.wav
new file mode 100644
index 0000000..57f2ef3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P015.wav
new file mode 100644
index 0000000..3ecea33
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P030.wav
new file mode 100644
index 0000000..7320802
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P045.wav
new file mode 100644
index 0000000..1a10d9a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P060.wav
new file mode 100644
index 0000000..9b12c22
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P075.wav
new file mode 100644
index 0000000..3153bb8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P090.wav
new file mode 100644
index 0000000..3282da9
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P315.wav
new file mode 100644
index 0000000..b999852
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P330.wav
new file mode 100644
index 0000000..53a03b6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P345.wav
new file mode 100644
index 0000000..16d5766
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T000_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P000.wav
new file mode 100644
index 0000000..3788e16
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P015.wav
new file mode 100644
index 0000000..ad2efb6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P030.wav
new file mode 100644
index 0000000..ee86702
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P045.wav
new file mode 100644
index 0000000..98ff82e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P060.wav
new file mode 100644
index 0000000..98ff82e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P075.wav
new file mode 100644
index 0000000..98ff82e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P090.wav
new file mode 100644
index 0000000..98ff82e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P315.wav
new file mode 100644
index 0000000..10bdf78
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P330.wav
new file mode 100644
index 0000000..c8398a4
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P345.wav
new file mode 100644
index 0000000..82b92a8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T015_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P000.wav
new file mode 100644
index 0000000..8b8714c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P015.wav
new file mode 100644
index 0000000..882efd4
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P030.wav
new file mode 100644
index 0000000..abd99e6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P045.wav
new file mode 100644
index 0000000..28765be
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P060.wav
new file mode 100644
index 0000000..42c1445
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P075.wav
new file mode 100644
index 0000000..42c1445
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P090.wav
new file mode 100644
index 0000000..42c1445
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P315.wav
new file mode 100644
index 0000000..99b00f7
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P330.wav
new file mode 100644
index 0000000..f81bee2
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P345.wav
new file mode 100644
index 0000000..139d0cb
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T030_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P000.wav
new file mode 100644
index 0000000..68b7b4f
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P015.wav
new file mode 100644
index 0000000..d6773ae
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P030.wav
new file mode 100644
index 0000000..9e786bb
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P045.wav
new file mode 100644
index 0000000..fbef2f3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P060.wav
new file mode 100644
index 0000000..fbef2f3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P075.wav
new file mode 100644
index 0000000..fbef2f3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P090.wav
new file mode 100644
index 0000000..fbef2f3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P315.wav
new file mode 100644
index 0000000..3c53b76
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P330.wav
new file mode 100644
index 0000000..e4524c0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P345.wav
new file mode 100644
index 0000000..ff12535
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T045_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P000.wav
new file mode 100644
index 0000000..5bb1b17
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P015.wav
new file mode 100644
index 0000000..47e0209
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P030.wav
new file mode 100644
index 0000000..536b4ac
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P045.wav
new file mode 100644
index 0000000..05152ad
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P060.wav
new file mode 100644
index 0000000..221637b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P075.wav
new file mode 100644
index 0000000..7d6d07f
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P090.wav
new file mode 100644
index 0000000..7d6d07f
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P315.wav
new file mode 100644
index 0000000..a4eca78
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P330.wav
new file mode 100644
index 0000000..37393c2
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P345.wav
new file mode 100644
index 0000000..3d56e26
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T060_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P000.wav
new file mode 100644
index 0000000..2159f3d
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P015.wav
new file mode 100644
index 0000000..8b689f6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P030.wav
new file mode 100644
index 0000000..9ee8ac5
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P045.wav
new file mode 100644
index 0000000..88124e9
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P060.wav
new file mode 100644
index 0000000..88124e9
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P075.wav
new file mode 100644
index 0000000..88124e9
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P090.wav
new file mode 100644
index 0000000..88124e9
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P315.wav
new file mode 100644
index 0000000..59441a6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P330.wav
new file mode 100644
index 0000000..7cac0f5
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P345.wav
new file mode 100644
index 0000000..dc28d64
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T075_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P000.wav
new file mode 100644
index 0000000..ae7e583
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P015.wav
new file mode 100644
index 0000000..509449e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P030.wav
new file mode 100644
index 0000000..e23b20c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P045.wav
new file mode 100644
index 0000000..cf247b9
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P060.wav
new file mode 100644
index 0000000..f49d520
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P075.wav
new file mode 100644
index 0000000..f49d520
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P090.wav
new file mode 100644
index 0000000..f49d520
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P315.wav
new file mode 100644
index 0000000..e5472f1
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P330.wav
new file mode 100644
index 0000000..8e1af83
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P345.wav
new file mode 100644
index 0000000..c477193
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T090_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P000.wav
new file mode 100644
index 0000000..4236e08
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P015.wav
new file mode 100644
index 0000000..2461fb0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P030.wav
new file mode 100644
index 0000000..11d549b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P045.wav
new file mode 100644
index 0000000..0aa100e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P060.wav
new file mode 100644
index 0000000..0aa100e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P075.wav
new file mode 100644
index 0000000..0aa100e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P090.wav
new file mode 100644
index 0000000..0aa100e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P315.wav
new file mode 100644
index 0000000..572e602
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P330.wav
new file mode 100644
index 0000000..7f41da3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P345.wav
new file mode 100644
index 0000000..d0101b8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T105_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P000.wav
new file mode 100644
index 0000000..800fbd7
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P015.wav
new file mode 100644
index 0000000..9b35e72
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P030.wav
new file mode 100644
index 0000000..bb58c4e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P045.wav
new file mode 100644
index 0000000..8963e3e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P060.wav
new file mode 100644
index 0000000..22241ee
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P075.wav
new file mode 100644
index 0000000..9e4fee0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P090.wav
new file mode 100644
index 0000000..9e4fee0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P315.wav
new file mode 100644
index 0000000..95976c6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P330.wav
new file mode 100644
index 0000000..8fc55f1
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P345.wav
new file mode 100644
index 0000000..eeeb702
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T120_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P000.wav
new file mode 100644
index 0000000..1847d8d
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P015.wav
new file mode 100644
index 0000000..52e812c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P030.wav
new file mode 100644
index 0000000..32ca344
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P045.wav
new file mode 100644
index 0000000..3de60c8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P060.wav
new file mode 100644
index 0000000..3de60c8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P075.wav
new file mode 100644
index 0000000..3de60c8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P090.wav
new file mode 100644
index 0000000..3de60c8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P315.wav
new file mode 100644
index 0000000..2668e41
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P330.wav
new file mode 100644
index 0000000..e69670b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P345.wav
new file mode 100644
index 0000000..1cc48ee
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T135_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P000.wav
new file mode 100644
index 0000000..252968b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P015.wav
new file mode 100644
index 0000000..50aff3c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P030.wav
new file mode 100644
index 0000000..3abd6e8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P045.wav
new file mode 100644
index 0000000..3f0d5ef
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P060.wav
new file mode 100644
index 0000000..616f760
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P075.wav
new file mode 100644
index 0000000..616f760
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P090.wav
new file mode 100644
index 0000000..616f760
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P315.wav
new file mode 100644
index 0000000..bfb6032
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P330.wav
new file mode 100644
index 0000000..1983cdb
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P345.wav
new file mode 100644
index 0000000..27c0762
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T150_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P000.wav
new file mode 100644
index 0000000..b04391b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P015.wav
new file mode 100644
index 0000000..5955612
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P030.wav
new file mode 100644
index 0000000..af5d83a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P045.wav
new file mode 100644
index 0000000..a592f71
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P060.wav
new file mode 100644
index 0000000..a592f71
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P075.wav
new file mode 100644
index 0000000..a592f71
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P090.wav
new file mode 100644
index 0000000..a592f71
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P315.wav
new file mode 100644
index 0000000..a985aa1
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P330.wav
new file mode 100644
index 0000000..a8b83d1
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P345.wav
new file mode 100644
index 0000000..7e649a3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T165_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P000.wav
new file mode 100644
index 0000000..b74985c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P015.wav
new file mode 100644
index 0000000..e112ee0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P030.wav
new file mode 100644
index 0000000..ac842cc
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P045.wav
new file mode 100644
index 0000000..95c3a6d
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P060.wav
new file mode 100644
index 0000000..610eedb
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P075.wav
new file mode 100644
index 0000000..d4a57bf
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P090.wav
new file mode 100644
index 0000000..d4a57bf
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P315.wav
new file mode 100644
index 0000000..bd6e4f8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P330.wav
new file mode 100644
index 0000000..7d4be6f
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P345.wav
new file mode 100644
index 0000000..b7ef81a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T180_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P000.wav
new file mode 100644
index 0000000..0c4af2a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P015.wav
new file mode 100644
index 0000000..dd7a505
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P030.wav
new file mode 100644
index 0000000..e169049
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P045.wav
new file mode 100644
index 0000000..49008a0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P060.wav
new file mode 100644
index 0000000..49008a0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P075.wav
new file mode 100644
index 0000000..49008a0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P090.wav
new file mode 100644
index 0000000..49008a0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P315.wav
new file mode 100644
index 0000000..1e7d478
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P330.wav
new file mode 100644
index 0000000..2a77d74
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P345.wav
new file mode 100644
index 0000000..843b928
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T195_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P000.wav
new file mode 100644
index 0000000..770af17
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P015.wav
new file mode 100644
index 0000000..437a1c6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P030.wav
new file mode 100644
index 0000000..f0d9d8e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P045.wav
new file mode 100644
index 0000000..cd4ae55
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P060.wav
new file mode 100644
index 0000000..7dd5a1a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P075.wav
new file mode 100644
index 0000000..7dd5a1a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P090.wav
new file mode 100644
index 0000000..7dd5a1a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P315.wav
new file mode 100644
index 0000000..bfac19d
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P330.wav
new file mode 100644
index 0000000..8b3e086
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P345.wav
new file mode 100644
index 0000000..8b4da46
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T210_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P000.wav
new file mode 100644
index 0000000..b6d4703
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P015.wav
new file mode 100644
index 0000000..0ff35e9
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P030.wav
new file mode 100644
index 0000000..e934c78
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P045.wav
new file mode 100644
index 0000000..c931e3c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P060.wav
new file mode 100644
index 0000000..c931e3c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P075.wav
new file mode 100644
index 0000000..c931e3c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P090.wav
new file mode 100644
index 0000000..c931e3c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P315.wav
new file mode 100644
index 0000000..f999966
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P330.wav
new file mode 100644
index 0000000..d958590
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P345.wav
new file mode 100644
index 0000000..ac06260
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T225_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P000.wav
new file mode 100644
index 0000000..b720ed1
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P015.wav
new file mode 100644
index 0000000..b48852a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P030.wav
new file mode 100644
index 0000000..92c7ef0
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P045.wav
new file mode 100644
index 0000000..2d5ff65
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P060.wav
new file mode 100644
index 0000000..07dcfde
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P075.wav
new file mode 100644
index 0000000..283e250
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P090.wav
new file mode 100644
index 0000000..283e250
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P315.wav
new file mode 100644
index 0000000..b99ad7d
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P330.wav
new file mode 100644
index 0000000..4886915
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P345.wav
new file mode 100644
index 0000000..c932833
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T240_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P000.wav
new file mode 100644
index 0000000..b204def
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P015.wav
new file mode 100644
index 0000000..fa48113
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P030.wav
new file mode 100644
index 0000000..2e2de70
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P045.wav
new file mode 100644
index 0000000..685f102
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P060.wav
new file mode 100644
index 0000000..685f102
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P075.wav
new file mode 100644
index 0000000..685f102
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P090.wav
new file mode 100644
index 0000000..685f102
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P315.wav
new file mode 100644
index 0000000..c7cce6e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P330.wav
new file mode 100644
index 0000000..93a6b8a
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P345.wav
new file mode 100644
index 0000000..efc72bc
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T255_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P000.wav
new file mode 100644
index 0000000..8f49078
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P015.wav
new file mode 100644
index 0000000..96510f7
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P030.wav
new file mode 100644
index 0000000..60b84f4
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P045.wav
new file mode 100644
index 0000000..ec995e6
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P060.wav
new file mode 100644
index 0000000..e287d0e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P075.wav
new file mode 100644
index 0000000..e287d0e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P090.wav
new file mode 100644
index 0000000..e287d0e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P315.wav
new file mode 100644
index 0000000..01f0921
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P330.wav
new file mode 100644
index 0000000..380e707
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P345.wav
new file mode 100644
index 0000000..124a534
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T270_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P000.wav
new file mode 100644
index 0000000..1a577f3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P015.wav
new file mode 100644
index 0000000..ce698bb
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P030.wav
new file mode 100644
index 0000000..8d5134f
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P045.wav
new file mode 100644
index 0000000..583c6ed
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P060.wav
new file mode 100644
index 0000000..583c6ed
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P075.wav
new file mode 100644
index 0000000..583c6ed
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P090.wav
new file mode 100644
index 0000000..583c6ed
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P315.wav
new file mode 100644
index 0000000..7b1b43b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P330.wav
new file mode 100644
index 0000000..e9ed7ed
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P345.wav
new file mode 100644
index 0000000..6ce83ed
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T285_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P000.wav
new file mode 100644
index 0000000..b4ea6bf
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P015.wav
new file mode 100644
index 0000000..76d5b71
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P030.wav
new file mode 100644
index 0000000..04ee003
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P045.wav
new file mode 100644
index 0000000..22d7413
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P060.wav
new file mode 100644
index 0000000..1b35018
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P075.wav
new file mode 100644
index 0000000..2f55df8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P090.wav
new file mode 100644
index 0000000..2f55df8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P315.wav
new file mode 100644
index 0000000..7bcc8a4
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P330.wav
new file mode 100644
index 0000000..a3bacf3
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P345.wav
new file mode 100644
index 0000000..bdfba2d
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T300_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P000.wav
new file mode 100644
index 0000000..719320c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P015.wav
new file mode 100644
index 0000000..5d366fc
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P030.wav
new file mode 100644
index 0000000..e10e88b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P045.wav
new file mode 100644
index 0000000..ecb4b50
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P060.wav
new file mode 100644
index 0000000..ecb4b50
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P075.wav
new file mode 100644
index 0000000..ecb4b50
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P090.wav
new file mode 100644
index 0000000..ecb4b50
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P315.wav
new file mode 100644
index 0000000..35c44d4
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P330.wav
new file mode 100644
index 0000000..8fe859b
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P345.wav
new file mode 100644
index 0000000..3e44b83
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T315_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P000.wav
new file mode 100644
index 0000000..e878220
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P015.wav
new file mode 100644
index 0000000..7628cbc
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P030.wav
new file mode 100644
index 0000000..7c4430c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P045.wav
new file mode 100644
index 0000000..55e3c5e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P060.wav
new file mode 100644
index 0000000..563313e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P075.wav
new file mode 100644
index 0000000..563313e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P090.wav
new file mode 100644
index 0000000..563313e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P315.wav
new file mode 100644
index 0000000..3eccc16
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P330.wav
new file mode 100644
index 0000000..fd3f5e1
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P345.wav
new file mode 100644
index 0000000..5937c59
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T330_P345.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P000.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P000.wav
new file mode 100644
index 0000000..99dc851
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P000.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P015.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P015.wav
new file mode 100644
index 0000000..28994d5
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P015.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P030.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P030.wav
new file mode 100644
index 0000000..beb24a2
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P030.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P045.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P045.wav
new file mode 100644
index 0000000..f840c59
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P045.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P060.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P060.wav
new file mode 100644
index 0000000..f840c59
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P060.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P075.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P075.wav
new file mode 100644
index 0000000..f840c59
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P075.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P090.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P090.wav
new file mode 100644
index 0000000..f840c59
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P090.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P315.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P315.wav
new file mode 100644
index 0000000..68baa8e
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P315.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P330.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P330.wav
new file mode 100644
index 0000000..6cb01b8
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P330.wav
Binary files differ
diff --git a/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P345.wav b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P345.wav
new file mode 100644
index 0000000..b2ae88c
--- /dev/null
+++ b/Source/WebCore/platform/audio/resources/IRC_Composite_C_R0195_T345_P345.wav
Binary files differ