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 | |
37 | namespace WebCore { |
38 | |
39 | namespace { |
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 | |
44 | class ChannelProvider : public AudioSourceProvider { |
45 | public: |
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 | void provideInput(AudioBus* bus, size_t framesToProcess) override |
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 | |
85 | private: |
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 | |
95 | MultiChannelResampler::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 | |
103 | void 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 | |