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