2011-06-03 Chris Rogers <crogers@google.com>
[WebKit-https.git] / Source / WebCore / platform / audio / AudioBus.cpp
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     
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
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
73 void AudioBus::zero()
74 {
75     for (unsigned i = 0; i < m_channels.size(); ++i)
76         m_channels[i]->zero();
77 }
78
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.
134 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
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 nullptr;
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
168 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
179 void AudioBus::normalize()
180 {
181     float max = maxAbsValue();
182     if (max)
183         scale(1.0f / max);
184 }
185
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.
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
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
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
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         ASSERT_NOT_REACHED();
341         return;
342     }
343
344     // Dispatch for different channel layouts
345     switch (numberOfChannels()) {
346     case 1: // mono
347     case 2: // stereo
348         processWithGainFromMonoStereo(sourceBus, lastMixGain, targetGain, sumToBus);
349         break;
350     case 4: // FIXME: implement quad
351     case 5: // FIXME: implement 5.0
352     default:
353         ASSERT_NOT_REACHED();
354         break;
355     }
356 }
357
358 void AudioBus::copyWithSampleAccurateGainValuesFrom(const AudioBus &sourceBus, float* gainValues, unsigned numberOfGainValues)
359 {
360     // Make sure we're processing from the same type of bus.
361     // We *are* able to process from mono -> stereo
362     if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus)) {
363         ASSERT_NOT_REACHED();
364         return;
365     }
366
367     if (!gainValues || numberOfGainValues > sourceBus.length()) {
368         ASSERT_NOT_REACHED();
369         return;
370     }
371
372     // FIXME: this can potentially use SIMD optimizations with vector libraries.
373     // We handle both the 1 -> N and N -> N case here.
374     const float* source = sourceBus.channel(0)->data();
375     for (unsigned channelIndex = 0; channelIndex < numberOfChannels(); ++channelIndex) {
376         if (sourceBus.numberOfChannels() == numberOfChannels())
377             source = sourceBus.channel(channelIndex)->data();
378         float* destination = channel(channelIndex)->data();
379         for (unsigned i = 0; i < numberOfGainValues; ++i)
380             destination[i] = source[i] * gainValues[i];
381     }
382 }
383
384 void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
385 {
386     processWithGainFrom(sourceBus, lastMixGain, targetGain, false);
387 }
388
389 void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
390 {
391     processWithGainFrom(sourceBus, lastMixGain, targetGain, true);
392 }
393
394 #if !PLATFORM(MAC)
395 PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, bool mixToMono, double newSampleRate)
396 {
397     // sourceBus's sample-rate must be known.
398     ASSERT(sourceBus && sourceBus->sampleRate());
399     if (!sourceBus || !sourceBus->sampleRate())
400         return nullptr;
401
402     double sourceSampleRate = sourceBus->sampleRate();
403     double destinationSampleRate = newSampleRate;
404     unsigned numberOfSourceChannels = sourceBus->numberOfChannels();
405
406     if (numberOfSourceChannels == 1)
407         mixToMono = false; // already mono
408         
409     if (sourceSampleRate == destinationSampleRate) {
410         // No sample-rate conversion is necessary.
411         if (mixToMono)
412             return AudioBus::createByMixingToMono(sourceBus);
413
414         // Return exact copy.
415         return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length());
416     }
417     
418     // First, mix to mono (if necessary) then sample-rate convert.
419     AudioBus* resamplerSourceBus;
420     OwnPtr<AudioBus> mixedMonoBus;
421     if (mixToMono) {
422         mixedMonoBus = AudioBus::createByMixingToMono(sourceBus);
423         resamplerSourceBus = mixedMonoBus.get();
424     } else {
425         // Directly resample without down-mixing.
426         resamplerSourceBus = sourceBus;
427     }
428
429     // Calculate destination length based on the sample-rates.
430     double sampleRateRatio = sourceSampleRate / destinationSampleRate;
431     int sourceLength = resamplerSourceBus->length();
432     int destinationLength = sourceLength / sampleRateRatio;
433
434     // Create destination bus with same number of channels.
435     unsigned numberOfDestinationChannels = resamplerSourceBus->numberOfChannels();
436     OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(numberOfDestinationChannels, destinationLength)));
437
438     // Sample-rate convert each channel.
439     for (unsigned i = 0; i < numberOfDestinationChannels; ++i) {
440         float* source = resamplerSourceBus->channel(i)->data();
441         float* destination = destinationBus->channel(i)->data();
442
443         SincResampler resampler(sampleRateRatio);
444         resampler.process(source, destination, sourceLength);
445     }
446
447     destinationBus->setSampleRate(newSampleRate);    
448     return destinationBus.release();
449 }
450 #endif // !PLATFORM(MAC)
451
452 PassOwnPtr<AudioBus> AudioBus::createByMixingToMono(AudioBus* sourceBus)
453 {
454     switch (sourceBus->numberOfChannels()) {
455     case 1:
456         // Simply create an exact copy.
457         return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length());
458     case 2:
459         {
460             unsigned n = sourceBus->length();
461             OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(1, n)));
462
463             float* sourceL = sourceBus->channel(0)->data();
464             float* sourceR = sourceBus->channel(1)->data();
465             float* destination = destinationBus->channel(0)->data();
466         
467             // Do the mono mixdown.
468             for (unsigned i = 0; i < n; ++i)
469                 destination[i] = 0.5 * (sourceL[i] + sourceR[i]);
470
471             destinationBus->setSampleRate(sourceBus->sampleRate());    
472             return destinationBus.release();
473         }
474     }
475
476     ASSERT_NOT_REACHED();
477     return nullptr;
478 }
479
480 } // WebCore
481
482 #endif // ENABLE(WEB_AUDIO)