1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30
31 #if ENABLE(WEB_AUDIO)
32
33 #include "modules/webaudio/AudioBuffer.h"
34
35 #include "bindings/core/v8/ExceptionMessages.h"
36 #include "bindings/core/v8/ExceptionState.h"
37 #include "bindings/core/v8/custom/V8ArrayBufferCustom.h"
38 #include "core/dom/ExceptionCode.h"
39 #include "modules/webaudio/AudioContext.h"
40 #include "platform/audio/AudioBus.h"
41 #include "platform/audio/AudioFileReader.h"
42 #include "platform/audio/AudioUtilities.h"
43
44 namespace blink {
45
create(unsigned numberOfChannels,size_t numberOfFrames,float sampleRate)46 AudioBuffer* AudioBuffer::create(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
47 {
48 if (!AudioUtilities::isValidAudioBufferSampleRate(sampleRate) || numberOfChannels > AudioContext::maxNumberOfChannels() || !numberOfChannels || !numberOfFrames)
49 return 0;
50
51 AudioBuffer* buffer = new AudioBuffer(numberOfChannels, numberOfFrames, sampleRate);
52
53 if (!buffer->createdSuccessfully(numberOfChannels))
54 return 0;
55 return buffer;
56 }
57
create(unsigned numberOfChannels,size_t numberOfFrames,float sampleRate,ExceptionState & exceptionState)58 AudioBuffer* AudioBuffer::create(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
59 {
60 if (!numberOfChannels || numberOfChannels > AudioContext::maxNumberOfChannels()) {
61 exceptionState.throwDOMException(
62 NotSupportedError,
63 ExceptionMessages::indexOutsideRange(
64 "number of channels",
65 numberOfChannels,
66 1u,
67 ExceptionMessages::InclusiveBound,
68 AudioContext::maxNumberOfChannels(),
69 ExceptionMessages::InclusiveBound));
70 return 0;
71 }
72
73 if (!AudioUtilities::isValidAudioBufferSampleRate(sampleRate)) {
74 exceptionState.throwDOMException(
75 NotSupportedError,
76 ExceptionMessages::indexOutsideRange(
77 "sample rate",
78 sampleRate,
79 AudioUtilities::minAudioBufferSampleRate(),
80 ExceptionMessages::InclusiveBound,
81 AudioUtilities::maxAudioBufferSampleRate(),
82 ExceptionMessages::InclusiveBound));
83 return 0;
84 }
85
86 if (!numberOfFrames) {
87 exceptionState.throwDOMException(
88 NotSupportedError,
89 ExceptionMessages::indexExceedsMinimumBound(
90 "number of frames",
91 numberOfFrames,
92 static_cast<size_t>(0)));
93 return 0;
94 }
95
96 AudioBuffer* audioBuffer = create(numberOfChannels, numberOfFrames, sampleRate);
97
98 if (!audioBuffer) {
99 exceptionState.throwDOMException(
100 NotSupportedError,
101 "createBuffer("
102 + String::number(numberOfChannels) + ", "
103 + String::number(numberOfFrames) + ", "
104 + String::number(sampleRate)
105 + ") failed.");
106 }
107
108 return audioBuffer;
109 }
110
createFromAudioFileData(const void * data,size_t dataSize,bool mixToMono,float sampleRate)111 AudioBuffer* AudioBuffer::createFromAudioFileData(const void* data, size_t dataSize, bool mixToMono, float sampleRate)
112 {
113 RefPtr<AudioBus> bus = createBusFromInMemoryAudioFile(data, dataSize, mixToMono, sampleRate);
114 if (bus.get()) {
115 AudioBuffer* buffer = new AudioBuffer(bus.get());
116 if (buffer->createdSuccessfully(bus->numberOfChannels()))
117 return buffer;
118 }
119
120 return 0;
121 }
122
createFromAudioBus(AudioBus * bus)123 AudioBuffer* AudioBuffer::createFromAudioBus(AudioBus* bus)
124 {
125 if (!bus)
126 return 0;
127 AudioBuffer* buffer = new AudioBuffer(bus);
128 if (buffer->createdSuccessfully(bus->numberOfChannels()))
129 return buffer;
130 return 0;
131 }
132
createdSuccessfully(unsigned desiredNumberOfChannels) const133 bool AudioBuffer::createdSuccessfully(unsigned desiredNumberOfChannels) const
134 {
135 return numberOfChannels() == desiredNumberOfChannels;
136 }
137
AudioBuffer(unsigned numberOfChannels,size_t numberOfFrames,float sampleRate)138 AudioBuffer::AudioBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
139 : m_sampleRate(sampleRate)
140 , m_length(numberOfFrames)
141 {
142 m_channels.reserveCapacity(numberOfChannels);
143
144 for (unsigned i = 0; i < numberOfChannels; ++i) {
145 RefPtr<Float32Array> channelDataArray = Float32Array::create(m_length);
146 // If the channel data array could not be created, just return. The caller will need to
147 // check that the desired number of channels were created.
148 if (!channelDataArray) {
149 return;
150 }
151
152 channelDataArray->setNeuterable(false);
153 m_channels.append(channelDataArray);
154 }
155 }
156
AudioBuffer(AudioBus * bus)157 AudioBuffer::AudioBuffer(AudioBus* bus)
158 : m_sampleRate(bus->sampleRate())
159 , m_length(bus->length())
160 {
161 // Copy audio data from the bus to the Float32Arrays we manage.
162 unsigned numberOfChannels = bus->numberOfChannels();
163 m_channels.reserveCapacity(numberOfChannels);
164 for (unsigned i = 0; i < numberOfChannels; ++i) {
165 RefPtr<Float32Array> channelDataArray = Float32Array::create(m_length);
166 // If the channel data array could not be created, just return. The caller will need to
167 // check that the desired number of channels were created.
168 if (!channelDataArray)
169 return;
170
171 channelDataArray->setNeuterable(false);
172 channelDataArray->setRange(bus->channel(i)->data(), m_length, 0);
173 m_channels.append(channelDataArray);
174 }
175 }
176
getChannelData(unsigned channelIndex,ExceptionState & exceptionState)177 PassRefPtr<Float32Array> AudioBuffer::getChannelData(unsigned channelIndex, ExceptionState& exceptionState)
178 {
179 if (channelIndex >= m_channels.size()) {
180 exceptionState.throwDOMException(IndexSizeError, "channel index (" + String::number(channelIndex) + ") exceeds number of channels (" + String::number(m_channels.size()) + ")");
181 return nullptr;
182 }
183
184 Float32Array* channelData = m_channels[channelIndex].get();
185 return Float32Array::create(channelData->buffer(), channelData->byteOffset(), channelData->length());
186 }
187
getChannelData(unsigned channelIndex)188 Float32Array* AudioBuffer::getChannelData(unsigned channelIndex)
189 {
190 if (channelIndex >= m_channels.size())
191 return 0;
192
193 return m_channels[channelIndex].get();
194 }
195
zero()196 void AudioBuffer::zero()
197 {
198 for (unsigned i = 0; i < m_channels.size(); ++i) {
199 if (getChannelData(i))
200 getChannelData(i)->zeroRange(0, length());
201 }
202 }
203
associateWithWrapper(const WrapperTypeInfo * wrapperType,v8::Handle<v8::Object> wrapper,v8::Isolate * isolate)204 v8::Handle<v8::Object> AudioBuffer::associateWithWrapper(const WrapperTypeInfo* wrapperType, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate)
205 {
206 ScriptWrappable::associateWithWrapper(wrapperType, wrapper, isolate);
207
208 if (!wrapper.IsEmpty()) {
209 // We only setDeallocationObservers on array buffers that are held by
210 // some object in the V8 heap, not in the ArrayBuffer constructor
211 // itself. This is because V8 GC only cares about memory it can free on
212 // GC, and until the object is exposed to JavaScript, V8 GC doesn't
213 // affect it.
214 for (unsigned i = 0, n = numberOfChannels(); i < n; ++i) {
215 getChannelData(i)->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instanceTemplate());
216 }
217 }
218 return wrapper;
219 }
220
221 } // namespace blink
222
223 #endif // ENABLE(WEB_AUDIO)
224