1/*
2 * Copyright (C) 2011 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 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 "MultiChannelResampler.h"
34
35#include "AudioBus.h"
36
37namespace WebCore {
38
39namespace {
40
41// ChannelProvider provides a single channel of audio data (one channel at a time) for each channel
42// of data provided to us in a multi-channel provider.
43
44class ChannelProvider : public AudioSourceProvider {
45public:
46    ChannelProvider(AudioSourceProvider* multiChannelProvider, unsigned numberOfChannels)
47        : m_multiChannelProvider(multiChannelProvider)
48        , m_numberOfChannels(numberOfChannels)
49        , m_currentChannel(0)
50        , m_framesToProcess(0)
51    {
52    }
53
54    // provideInput() will be called once for each channel, starting with the first channel.
55    // Each time it's called, it will provide the next channel of data.
56    virtual void provideInput(AudioBus* bus, size_t framesToProcess)
57    {
58        bool isBusGood = bus && bus->numberOfChannels() == 1;
59        ASSERT(isBusGood);
60        if (!isBusGood)
61            return;
62
63        // Get the data from the multi-channel provider when the first channel asks for it.
64        // For subsequent channels, we can just dish out the channel data from that (stored in m_multiChannelBus).
65        if (!m_currentChannel) {
66            m_framesToProcess = framesToProcess;
67            m_multiChannelBus = AudioBus::create(m_numberOfChannels, framesToProcess);
68            m_multiChannelProvider->provideInput(m_multiChannelBus.get(), framesToProcess);
69        }
70
71        // All channels must ask for the same amount. This should always be the case, but let's just make sure.
72        bool isGood = m_multiChannelBus.get() && framesToProcess == m_framesToProcess;
73        ASSERT(isGood);
74        if (!isGood)
75            return;
76
77        // Copy the channel data from what we received from m_multiChannelProvider.
78        ASSERT(m_currentChannel <= m_numberOfChannels);
79        if (m_currentChannel < m_numberOfChannels) {
80            memcpy(bus->channel(0)->mutableData(), m_multiChannelBus->channel(m_currentChannel)->data(), sizeof(float) * framesToProcess);
81            ++m_currentChannel;
82        }
83    }
84
85private:
86    AudioSourceProvider* m_multiChannelProvider;
87    RefPtr<AudioBus> m_multiChannelBus;
88    unsigned m_numberOfChannels;
89    unsigned m_currentChannel;
90    size_t m_framesToProcess; // Used to verify that all channels ask for the same amount.
91};
92
93} // namespace
94
95MultiChannelResampler::MultiChannelResampler(double scaleFactor, unsigned numberOfChannels)
96    : m_numberOfChannels(numberOfChannels)
97{
98    // Create each channel's resampler.
99    for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex)
100        m_kernels.append(std::make_unique<SincResampler>(scaleFactor));
101}
102
103void MultiChannelResampler::process(AudioSourceProvider* provider, AudioBus* destination, size_t framesToProcess)
104{
105    // The provider can provide us with multi-channel audio data. But each of our single-channel resamplers (kernels)
106    // below requires a provider which provides a single unique channel of data.
107    // channelProvider wraps the original multi-channel provider and dishes out one channel at a time.
108    ChannelProvider channelProvider(provider, m_numberOfChannels);
109
110    for (unsigned channelIndex = 0; channelIndex < m_numberOfChannels; ++channelIndex) {
111        // Depending on the sample-rate scale factor, and the internal buffering used in a SincResampler
112        // kernel, this call to process() will only sometimes call provideInput() on the channelProvider.
113        // However, if it calls provideInput() for the first channel, then it will call it for the remaining
114        // channels, since they all buffer in the same way and are processing the same number of frames.
115        m_kernels[channelIndex]->process(&channelProvider,
116                                         destination->channel(channelIndex)->mutableData(),
117                                         framesToProcess);
118    }
119}
120
121} // namespace WebCore
122
123#endif // ENABLE(WEB_AUDIO)
124