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 "AudioBus.h"
34
35 #if !PLATFORM(MAC)
36 #include "SincResampler.h"
37 #endif
38 #include "VectorMath.h"
39 #include <algorithm>
40 #include <assert.h>
41 #include <math.h>
42 #include <wtf/OwnPtr.h>
43 #include <wtf/PassOwnPtr.h>
44
45 namespace WebCore {
46
47 using namespace VectorMath;
48
AudioBus(unsigned numberOfChannels,size_t length,bool allocate)49 AudioBus::AudioBus(unsigned numberOfChannels, size_t length, bool allocate)
50 : m_length(length)
51 , m_busGain(1.0)
52 , m_isFirstTime(true)
53 , m_sampleRate(0.0)
54 {
55 m_channels.reserveInitialCapacity(numberOfChannels);
56
57 for (unsigned i = 0; i < numberOfChannels; ++i) {
58 PassOwnPtr<AudioChannel> channel = allocate ? adoptPtr(new AudioChannel(length)) : adoptPtr(new AudioChannel(0, length));
59 m_channels.append(channel);
60 }
61
62 m_layout = LayoutCanonical; // for now this is the only layout we define
63 }
64
setChannelMemory(unsigned channelIndex,float * storage,size_t length)65 void AudioBus::setChannelMemory(unsigned channelIndex, float* storage, size_t length)
66 {
67 if (channelIndex < m_channels.size()) {
68 channel(channelIndex)->set(storage, length);
69 m_length = length; // FIXME: verify that this length matches all the other channel lengths
70 }
71 }
72
zero()73 void AudioBus::zero()
74 {
75 for (unsigned i = 0; i < m_channels.size(); ++i)
76 m_channels[i]->zero();
77 }
78
channelByType(unsigned channelType)79 AudioChannel* AudioBus::channelByType(unsigned channelType)
80 {
81 // For now we only support canonical channel layouts...
82 if (m_layout != LayoutCanonical)
83 return 0;
84
85 switch (numberOfChannels()) {
86 case 1: // mono
87 if (channelType == ChannelMono || channelType == ChannelLeft)
88 return channel(0);
89 return 0;
90
91 case 2: // stereo
92 switch (channelType) {
93 case ChannelLeft: return channel(0);
94 case ChannelRight: return channel(1);
95 default: return 0;
96 }
97
98 case 4: // quad
99 switch (channelType) {
100 case ChannelLeft: return channel(0);
101 case ChannelRight: return channel(1);
102 case ChannelSurroundLeft: return channel(2);
103 case ChannelSurroundRight: return channel(3);
104 default: return 0;
105 }
106
107 case 5: // 5.0
108 switch (channelType) {
109 case ChannelLeft: return channel(0);
110 case ChannelRight: return channel(1);
111 case ChannelCenter: return channel(2);
112 case ChannelSurroundLeft: return channel(3);
113 case ChannelSurroundRight: return channel(4);
114 default: return 0;
115 }
116
117 case 6: // 5.1
118 switch (channelType) {
119 case ChannelLeft: return channel(0);
120 case ChannelRight: return channel(1);
121 case ChannelCenter: return channel(2);
122 case ChannelLFE: return channel(3);
123 case ChannelSurroundLeft: return channel(4);
124 case ChannelSurroundRight: return channel(5);
125 default: return 0;
126 }
127 }
128
129 ASSERT_NOT_REACHED();
130 return 0;
131 }
132
133 // Returns true if the channel count and frame-size match.
topologyMatches(const AudioBus & bus) const134 bool AudioBus::topologyMatches(const AudioBus& bus) const
135 {
136 if (numberOfChannels() != bus.numberOfChannels())
137 return false; // channel mismatch
138
139 // Make sure source bus has enough frames.
140 if (length() > bus.length())
141 return false; // frame-size mismatch
142
143 return true;
144 }
145
createBufferFromRange(AudioBus * sourceBuffer,unsigned startFrame,unsigned endFrame)146 PassOwnPtr<AudioBus> AudioBus::createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame)
147 {
148 size_t numberOfSourceFrames = sourceBuffer->length();
149 unsigned numberOfChannels = sourceBuffer->numberOfChannels();
150
151 // Sanity checking
152 bool isRangeSafe = startFrame < endFrame && endFrame <= numberOfSourceFrames;
153 ASSERT(isRangeSafe);
154 if (!isRangeSafe)
155 return 0;
156
157 size_t rangeLength = endFrame - startFrame;
158
159 OwnPtr<AudioBus> audioBus = adoptPtr(new AudioBus(numberOfChannels, rangeLength));
160 audioBus->setSampleRate(sourceBuffer->sampleRate());
161
162 for (unsigned i = 0; i < numberOfChannels; ++i)
163 audioBus->channel(i)->copyFromRange(sourceBuffer->channel(i), startFrame, endFrame);
164
165 return audioBus.release();
166 }
167
maxAbsValue() const168 float AudioBus::maxAbsValue() const
169 {
170 float max = 0.0f;
171 for (unsigned i = 0; i < numberOfChannels(); ++i) {
172 const AudioChannel* channel = this->channel(i);
173 max = std::max(max, channel->maxAbsValue());
174 }
175
176 return max;
177 }
178
normalize()179 void AudioBus::normalize()
180 {
181 float max = maxAbsValue();
182 if (max)
183 scale(1.0f / max);
184 }
185
scale(double scale)186 void AudioBus::scale(double scale)
187 {
188 for (unsigned i = 0; i < numberOfChannels(); ++i)
189 channel(i)->scale(scale);
190 }
191
192 // Just copies the samples from the source bus to this one.
193 // This is just a simple copy if the number of channels match, otherwise a mixup or mixdown is done.
194 // For now, we just support a mixup from mono -> stereo.
copyFrom(const AudioBus & sourceBus)195 void AudioBus::copyFrom(const AudioBus& sourceBus)
196 {
197 if (&sourceBus == this)
198 return;
199
200 if (numberOfChannels() == sourceBus.numberOfChannels()) {
201 for (unsigned i = 0; i < numberOfChannels(); ++i)
202 channel(i)->copyFrom(sourceBus.channel(i));
203 } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
204 // Handle mono -> stereo case (for now simply copy mono channel into both left and right)
205 // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
206 const AudioChannel* sourceChannel = sourceBus.channel(0);
207 channel(0)->copyFrom(sourceChannel);
208 channel(1)->copyFrom(sourceChannel);
209 } else {
210 // Case not handled
211 ASSERT_NOT_REACHED();
212 }
213 }
214
sumFrom(const AudioBus & sourceBus)215 void AudioBus::sumFrom(const AudioBus &sourceBus)
216 {
217 if (numberOfChannels() == sourceBus.numberOfChannels()) {
218 for (unsigned i = 0; i < numberOfChannels(); ++i)
219 channel(i)->sumFrom(sourceBus.channel(i));
220 } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
221 // Handle mono -> stereo case (for now simply sum mono channel into both left and right)
222 // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
223 const AudioChannel* sourceChannel = sourceBus.channel(0);
224 channel(0)->sumFrom(sourceChannel);
225 channel(1)->sumFrom(sourceChannel);
226 } else {
227 // Case not handled
228 ASSERT_NOT_REACHED();
229 }
230 }
231
processWithGainFromMonoStereo(const AudioBus & sourceBus,double * lastMixGain,double targetGain,bool sumToBus)232 void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
233 {
234 // We don't want to suddenly change the gain from mixing one time slice to the next,
235 // so we "de-zipper" by slowly changing the gain each sample-frame until we've achieved the target gain.
236
237 // FIXME: optimize this method (SSE, etc.)
238 // FIXME: Need fast path here when gain has converged on targetGain. In this case, de-zippering is no longer needed.
239 // FIXME: Need fast path when this==sourceBus && lastMixGain==targetGain==1.0 && sumToBus==false (this is a NOP)
240
241 // Take master bus gain into account as well as the targetGain.
242 double totalDesiredGain = m_busGain * targetGain;
243
244 // First time, snap directly to totalDesiredGain.
245 double gain = m_isFirstTime ? totalDesiredGain : *lastMixGain;
246 m_isFirstTime = false;
247
248 int numberOfSourceChannels = sourceBus.numberOfChannels();
249 int numberOfDestinationChannels = numberOfChannels();
250
251 AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
252 const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
253 const float* sourceR = numberOfSourceChannels > 1 ? sourceBusSafe.channelByType(ChannelRight)->data() : 0;
254
255 float* destinationL = channelByType(ChannelLeft)->data();
256 float* destinationR = numberOfDestinationChannels > 1 ? channelByType(ChannelRight)->data() : 0;
257
258 const double DezipperRate = 0.005;
259 int framesToProcess = length();
260
261 if (sumToBus) {
262 // Sum to our bus
263 if (sourceR && destinationR) {
264 // Stereo
265 while (framesToProcess--) {
266 float sampleL = *sourceL++;
267 float sampleR = *sourceR++;
268 *destinationL++ += static_cast<float>(gain * sampleL);
269 *destinationR++ += static_cast<float>(gain * sampleR);
270
271 // Slowly change gain to desired gain.
272 gain += (totalDesiredGain - gain) * DezipperRate;
273 }
274 } else if (destinationR) {
275 // Mono -> stereo (mix equally into L and R)
276 // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
277 while (framesToProcess--) {
278 float sample = *sourceL++;
279 *destinationL++ += static_cast<float>(gain * sample);
280 *destinationR++ += static_cast<float>(gain * sample);
281
282 // Slowly change gain to desired gain.
283 gain += (totalDesiredGain - gain) * DezipperRate;
284 }
285 } else {
286 // Mono
287 while (framesToProcess--) {
288 float sampleL = *sourceL++;
289 *destinationL++ += static_cast<float>(gain * sampleL);
290
291 // Slowly change gain to desired gain.
292 gain += (totalDesiredGain - gain) * DezipperRate;
293 }
294 }
295 } else {
296 // Process directly (without summing) to our bus
297 if (sourceR && destinationR) {
298 // Stereo
299 while (framesToProcess--) {
300 float sampleL = *sourceL++;
301 float sampleR = *sourceR++;
302 *destinationL++ = static_cast<float>(gain * sampleL);
303 *destinationR++ = static_cast<float>(gain * sampleR);
304
305 // Slowly change gain to desired gain.
306 gain += (totalDesiredGain - gain) * DezipperRate;
307 }
308 } else if (destinationR) {
309 // Mono -> stereo (mix equally into L and R)
310 // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
311 while (framesToProcess--) {
312 float sample = *sourceL++;
313 *destinationL++ = static_cast<float>(gain * sample);
314 *destinationR++ = static_cast<float>(gain * sample);
315
316 // Slowly change gain to desired gain.
317 gain += (totalDesiredGain - gain) * DezipperRate;
318 }
319 } else {
320 // Mono
321 while (framesToProcess--) {
322 float sampleL = *sourceL++;
323 *destinationL++ = static_cast<float>(gain * sampleL);
324
325 // Slowly change gain to desired gain.
326 gain += (totalDesiredGain - gain) * DezipperRate;
327 }
328 }
329 }
330
331 // Save the target gain as the starting point for next time around.
332 *lastMixGain = gain;
333 }
334
processWithGainFrom(const AudioBus & sourceBus,double * lastMixGain,double targetGain,bool sumToBus)335 void AudioBus::processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
336 {
337 // Make sure we're summing from same type of bus.
338 // We *are* able to sum from mono -> stereo
339 if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus))
340 return;
341
342 // Dispatch for different channel layouts
343 switch (numberOfChannels()) {
344 case 1: // mono
345 case 2: // stereo
346 processWithGainFromMonoStereo(sourceBus, lastMixGain, targetGain, sumToBus);
347 break;
348 case 4: // FIXME: implement quad
349 case 5: // FIXME: implement 5.0
350 default:
351 ASSERT_NOT_REACHED();
352 break;
353 }
354 }
355
copyWithGainFrom(const AudioBus & sourceBus,double * lastMixGain,double targetGain)356 void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
357 {
358 processWithGainFrom(sourceBus, lastMixGain, targetGain, false);
359 }
360
sumWithGainFrom(const AudioBus & sourceBus,double * lastMixGain,double targetGain)361 void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
362 {
363 processWithGainFrom(sourceBus, lastMixGain, targetGain, true);
364 }
365
366 #if !PLATFORM(MAC)
createBySampleRateConverting(AudioBus * sourceBus,bool mixToMono,double newSampleRate)367 PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, bool mixToMono, double newSampleRate)
368 {
369 // sourceBus's sample-rate must be known.
370 ASSERT(sourceBus && sourceBus->sampleRate());
371 if (!sourceBus || !sourceBus->sampleRate())
372 return 0;
373
374 double sourceSampleRate = sourceBus->sampleRate();
375 double destinationSampleRate = newSampleRate;
376 unsigned numberOfSourceChannels = sourceBus->numberOfChannels();
377
378 if (numberOfSourceChannels == 1)
379 mixToMono = false; // already mono
380
381 if (sourceSampleRate == destinationSampleRate) {
382 // No sample-rate conversion is necessary.
383 if (mixToMono)
384 return AudioBus::createByMixingToMono(sourceBus);
385
386 // Return exact copy.
387 return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length());
388 }
389
390 // First, mix to mono (if necessary) then sample-rate convert.
391 AudioBus* resamplerSourceBus;
392 OwnPtr<AudioBus> mixedMonoBus;
393 if (mixToMono) {
394 mixedMonoBus = AudioBus::createByMixingToMono(sourceBus);
395 resamplerSourceBus = mixedMonoBus.get();
396 } else {
397 // Directly resample without down-mixing.
398 resamplerSourceBus = sourceBus;
399 }
400
401 // Calculate destination length based on the sample-rates.
402 double sampleRateRatio = sourceSampleRate / destinationSampleRate;
403 int sourceLength = resamplerSourceBus->length();
404 int destinationLength = sourceLength / sampleRateRatio;
405
406 // Create destination bus with same number of channels.
407 unsigned numberOfDestinationChannels = resamplerSourceBus->numberOfChannels();
408 OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(numberOfDestinationChannels, destinationLength)));
409
410 // Sample-rate convert each channel.
411 for (unsigned i = 0; i < numberOfDestinationChannels; ++i) {
412 float* source = resamplerSourceBus->channel(i)->data();
413 float* destination = destinationBus->channel(i)->data();
414
415 SincResampler resampler(sampleRateRatio);
416 resampler.process(source, destination, sourceLength);
417 }
418
419 return destinationBus.release();
420 }
421 #endif // !PLATFORM(MAC)
422
createByMixingToMono(AudioBus * sourceBus)423 PassOwnPtr<AudioBus> AudioBus::createByMixingToMono(AudioBus* sourceBus)
424 {
425 switch (sourceBus->numberOfChannels()) {
426 case 1:
427 // Simply create an exact copy.
428 return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length());
429 case 2:
430 {
431 unsigned n = sourceBus->length();
432 OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(1, n)));
433
434 float* sourceL = sourceBus->channel(0)->data();
435 float* sourceR = sourceBus->channel(1)->data();
436 float* destination = destinationBus->channel(0)->data();
437
438 // Do the mono mixdown.
439 for (unsigned i = 0; i < n; ++i)
440 destination[i] = 0.5 * (sourceL[i] + sourceR[i]);
441
442 return destinationBus.release();
443 }
444 }
445
446 ASSERT_NOT_REACHED();
447 return 0;
448 }
449
450 } // WebCore
451
452 #endif // ENABLE(WEB_AUDIO)
453