15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2010, Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1.  Redistributions of source code must retain the above copyright
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    documentation and/or other materials provided with the distribution.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if ENABLE(WEB_AUDIO)
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
291e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/AudioResampler.h"
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <algorithm>
327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/MathExtras.h"
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace std;
3502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const double AudioResampler::MaxRate = 8.0;
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)AudioResampler::AudioResampler()
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_rate(1.0)
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
4481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    m_sourceBus = AudioBus::create(1, 0, false);
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)AudioResampler::AudioResampler(unsigned numberOfChannels)
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_rate(1.0)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < numberOfChannels; ++i)
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    m_sourceBus = AudioBus::create(numberOfChannels, 0, false);
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void AudioResampler::configureChannels(unsigned numberOfChannels)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned currentSize = m_kernels.size();
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (numberOfChannels == currentSize)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return; // already setup
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // First deal with adding or removing kernels.
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (numberOfChannels > currentSize) {
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (unsigned i = currentSize; i < numberOfChannels; ++i)
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            m_kernels.append(adoptPtr(new AudioResamplerKernel(this)));
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_kernels.resize(numberOfChannels);
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Reconfigure our source bus to the new channel size.
7081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    m_sourceBus = AudioBus::create(numberOfChannels, 0, false);
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void AudioResampler::process(AudioSourceProvider* provider, AudioBus* destinationBus, size_t framesToProcess)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(provider);
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!provider)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
7802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned numberOfChannels = m_kernels.size();
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Make sure our configuration matches the bus we're rendering to.
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool channelsMatch = (destinationBus && destinationBus->numberOfChannels() == numberOfChannels);
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(channelsMatch);
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!channelsMatch)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Setup the source bus.
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < numberOfChannels; ++i) {
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Figure out how many frames we need to get from the provider, and a pointer to the buffer.
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t framesNeeded;
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        float* fillPointer = m_kernels[i]->getSourcePointer(framesToProcess, &framesNeeded);
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(fillPointer);
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!fillPointer)
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
9502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_sourceBus->setChannelMemory(i, fillPointer, framesNeeded);
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Ask the provider to supply the desired number of source frames.
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    provider->provideInput(m_sourceBus.get(), m_sourceBus->length());
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Now that we have the source data, resample each channel into the destination bus.
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: optimize for the common stereo case where it's faster to process both left/right channels in the same inner loop.
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < numberOfChannels; ++i) {
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        float* destination = destinationBus->channel(i)->mutableData();
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_kernels[i]->process(destination, framesToProcess);
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void AudioResampler::setRate(double rate)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
112926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (std::isnan(rate) || std::isinf(rate) || rate <= 0.0)
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
11402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_rate = min(AudioResampler::MaxRate, rate);
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void AudioResampler::reset()
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned numberOfChannels = m_kernels.size();
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < numberOfChannels; ++i)
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_kernels[i]->reset();
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif // ENABLE(WEB_AUDIO)
128