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
45namespace WebCore {
46
47using namespace VectorMath;
48
49AudioBus::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
65void 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
73void AudioBus::zero()
74{
75    for (unsigned i = 0; i < m_channels.size(); ++i)
76        m_channels[i]->zero();
77}
78
79AudioChannel* 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.
134bool 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
146PassOwnPtr<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
168float 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
179void AudioBus::normalize()
180{
181    float max = maxAbsValue();
182    if (max)
183        scale(1.0f / max);
184}
185
186void 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.
195void 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
215void 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
232void 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
335void 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
356void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
357{
358    processWithGainFrom(sourceBus, lastMixGain, targetGain, false);
359}
360
361void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
362{
363    processWithGainFrom(sourceBus, lastMixGain, targetGain, true);
364}
365
366#if !PLATFORM(MAC)
367PassOwnPtr<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
423PassOwnPtr<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