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) * 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer in the 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * documentation and/or other materials provided with the distribution. 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * its contributors may be used to endorse or promote products derived 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * from this software without specific prior written permission. 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if ENABLE(WEB_AUDIO) 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/Reverb.h" 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <math.h> 361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/AudioBus.h" 371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/VectorMath.h" 387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/MathExtras.h" 397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/OwnPtr.h" 407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/PassOwnPtr.h" 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 428abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)#if OS(MACOSX) 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace std; 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 46c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink { 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace VectorMath; 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Empirical gain calibration tested across many impulse responses to ensure perceived volume is same as dry (unprocessed) signal 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const float GainCalibration = -58; 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const float GainCalibrationSampleRate = 44100; 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// A minimum power value to when normalizing a silent (or very quiet) impulse response 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const float MinPower = 0.000125f; 5602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static float calculateNormalizationScale(AudioBus* response) 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Normalize by RMS power 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numberOfChannels = response->numberOfChannels(); 615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t length = response->length(); 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float power = 0; 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < numberOfChannels; ++i) { 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float channelPower = 0; 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) vsvesq(response->channel(i)->data(), 1, &channelPower, length); 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) power += channelPower; 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) power = sqrt(power / (numberOfChannels * length)); 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Protect against accidental overload 74926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (std::isinf(power) || std::isnan(power) || power < MinPower) 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) power = MinPower; 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float scale = 1 / power; 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scale *= powf(10, GainCalibration * 0.05f); // calibrate to make perceived volume same as unprocessed 805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Scale depends on sample-rate. 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (response->sampleRate()) 835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scale *= GainCalibrationSampleRate / response->sampleRate(); 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // True-stereo compensation 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (response->numberOfChannels() == 4) 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scale *= 0.5f; 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return scale; 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Reverb::Reverb(AudioBus* impulseResponse, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads, bool normalize) 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float scale = 1; 955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (normalize) { 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) scale = calculateNormalizationScale(impulseResponse); 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (scale) 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) impulseResponse->scale(scale); 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) initialize(impulseResponse, renderSliceSize, maxFFTSize, numberOfChannels, useBackgroundThreads); 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Undo scaling since this shouldn't be a destructive operation on impulseResponse. 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy 1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // instead of scaling and unscaling in place. 1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (normalize && scale) 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) impulseResponse->scale(1 / scale); 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void Reverb::initialize(AudioBus* impulseResponseBuffer, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads) 1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_impulseResponseLength = impulseResponseBuffer->length(); 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // The reverb can handle a mono impulse response and still do stereo processing 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers.reserveCapacity(numberOfChannels); 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int convolverRenderPhase = 0; 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < numResponseChannels; ++i) { 1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* channel = impulseResponseBuffer->channel(i); 1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) OwnPtr<ReverbConvolver> convolver = adoptPtr(new ReverbConvolver(channel, renderSliceSize, maxFFTSize, convolverRenderPhase, useBackgroundThreads)); 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers.append(convolver.release()); 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) convolverRenderPhase += renderSliceSize; 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // For "True" stereo processing we allocate a temporary buffer to avoid repeatedly allocating it in the process() method. 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // It can be bad to allocate memory in a real-time thread. 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (numResponseChannels == 4) 13381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) m_tempBuffer = AudioBus::create(2, MaxFrameSize); 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void Reverb::process(const AudioBus* sourceBus, AudioBus* destinationBus, size_t framesToProcess) 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Do a fairly comprehensive sanity check. 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If these conditions are satisfied, all of the source and destination pointers will be valid for the various matrixing cases. 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool isSafeToProcess = sourceBus && destinationBus && sourceBus->numberOfChannels() > 0 && destinationBus->numberOfChannels() > 0 14102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch && framesToProcess <= MaxFrameSize && framesToProcess <= sourceBus->length() && framesToProcess <= destinationBus->length(); 14202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(isSafeToProcess); 1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isSafeToProcess) 1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // For now only handle mono or stereo output 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (destinationBus->numberOfChannels() > 2) { 1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) destinationBus->zero(); 1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* destinationChannelL = destinationBus->channel(0); 1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const AudioChannel* sourceChannelL = sourceBus->channel(0); 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Handle input -> output matrixing... 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numInputChannels = sourceBus->numberOfChannels(); 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numOutputChannels = destinationBus->numberOfChannels(); 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numReverbChannels = m_convolvers.size(); 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (numInputChannels == 2 && numReverbChannels == 2 && numOutputChannels == 2) { 1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // 2 -> 2 -> 2 1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const AudioChannel* sourceChannelR = sourceBus->channel(1); 1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* destinationChannelR = destinationBus->channel(1); 1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess); 1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[1]->process(sourceChannelR, destinationChannelR, framesToProcess); 1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (numInputChannels == 1 && numOutputChannels == 2 && numReverbChannels == 2) { 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // 1 -> 2 -> 2 1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < 2; ++i) { 1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* destinationChannel = destinationBus->channel(i); 1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[i]->process(sourceChannelL, destinationChannel, framesToProcess); 1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 2) { 1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // 1 -> 1 -> 2 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess); 1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // simply copy L -> R 1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* destinationChannelR = destinationBus->channel(1); 1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool isCopySafe = destinationChannelL->data() && destinationChannelR->data() && destinationChannelL->length() >= framesToProcess && destinationChannelR->length() >= framesToProcess; 1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(isCopySafe); 1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!isCopySafe) 1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) memcpy(destinationChannelR->mutableData(), destinationChannelL->data(), sizeof(float) * framesToProcess); 1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) { 1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // 1 -> 1 -> 1 1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess); 1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) { 1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // 2 -> 4 -> 2 ("True" stereo) 1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const AudioChannel* sourceChannelR = sourceBus->channel(1); 1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* destinationChannelR = destinationBus->channel(1); 1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* tempChannelL = m_tempBuffer->channel(0); 1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* tempChannelR = m_tempBuffer->channel(1); 1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Process left virtual source 1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess); 1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[1]->process(sourceChannelL, destinationChannelR, framesToProcess); 1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Process right virtual source 2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); 2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); 2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) destinationBus->sumFrom(*m_tempBuffer); 2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (numInputChannels == 1 && numReverbChannels == 4 && numOutputChannels == 2) { 2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response) 2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // This is an inefficient use of a four-channel impulse response, but we should handle the case. 2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* destinationChannelR = destinationBus->channel(1); 2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* tempChannelL = m_tempBuffer->channel(0); 2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AudioChannel* tempChannelR = m_tempBuffer->channel(1); 2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Process left virtual source 2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[0]->process(sourceChannelL, destinationChannelL, framesToProcess); 2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[1]->process(sourceChannelL, destinationChannelR, framesToProcess); 2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Process right virtual source 2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[2]->process(sourceChannelL, tempChannelL, framesToProcess); 2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[3]->process(sourceChannelL, tempChannelR, framesToProcess); 2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) destinationBus->sumFrom(*m_tempBuffer); 2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Handle gracefully any unexpected / unsupported matrixing 2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: add code for 5.1 support... 2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) destinationBus->zero(); 2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void Reverb::reset() 2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < m_convolvers.size(); ++i) 2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_convolvers[i]->reset(); 2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)size_t Reverb::latencyFrames() const 2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return !m_convolvers.isEmpty() ? m_convolvers.first()->latencyFrames() : 0; 2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 239c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink 2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif // ENABLE(WEB_AUDIO) 242