Home | History | Annotate | Download | only in audio
      1 /*
      2  * Copyright (C) 2010 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 Computer, 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 "AudioBus.h"
     34 
     35 #if !PLATFORM(MAC)
     36 #include "SincResampler.h"
     37 #endif
     38 #include "VectorMath.h"
     39 #include <algorithm>
     40 #include <assert.h>
     41 #include <math.h>
     42 #include <wtf/OwnPtr.h>
     43 #include <wtf/PassOwnPtr.h>
     44 
     45 namespace WebCore {
     46 
     47 using namespace VectorMath;
     48 
     49 AudioBus::AudioBus(unsigned numberOfChannels, size_t length, bool allocate)
     50     : m_length(length)
     51     , m_busGain(1.0)
     52     , m_isFirstTime(true)
     53     , m_sampleRate(0.0)
     54 {
     55     m_channels.reserveInitialCapacity(numberOfChannels);
     56 
     57     for (unsigned i = 0; i < numberOfChannels; ++i) {
     58         PassOwnPtr<AudioChannel> channel = allocate ? adoptPtr(new AudioChannel(length)) : adoptPtr(new AudioChannel(0, length));
     59         m_channels.append(channel);
     60     }
     61 
     62     m_layout = LayoutCanonical; // for now this is the only layout we define
     63 }
     64 
     65 void AudioBus::setChannelMemory(unsigned channelIndex, float* storage, size_t length)
     66 {
     67     if (channelIndex < m_channels.size()) {
     68         channel(channelIndex)->set(storage, length);
     69         m_length = length; // FIXME: verify that this length matches all the other channel lengths
     70     }
     71 }
     72 
     73 void AudioBus::zero()
     74 {
     75     for (unsigned i = 0; i < m_channels.size(); ++i)
     76         m_channels[i]->zero();
     77 }
     78 
     79 AudioChannel* AudioBus::channelByType(unsigned channelType)
     80 {
     81     // For now we only support canonical channel layouts...
     82     if (m_layout != LayoutCanonical)
     83         return 0;
     84 
     85     switch (numberOfChannels()) {
     86     case 1: // mono
     87         if (channelType == ChannelMono || channelType == ChannelLeft)
     88             return channel(0);
     89         return 0;
     90 
     91     case 2: // stereo
     92         switch (channelType) {
     93         case ChannelLeft: return channel(0);
     94         case ChannelRight: return channel(1);
     95         default: return 0;
     96         }
     97 
     98     case 4: // quad
     99         switch (channelType) {
    100         case ChannelLeft: return channel(0);
    101         case ChannelRight: return channel(1);
    102         case ChannelSurroundLeft: return channel(2);
    103         case ChannelSurroundRight: return channel(3);
    104         default: return 0;
    105         }
    106 
    107     case 5: // 5.0
    108         switch (channelType) {
    109         case ChannelLeft: return channel(0);
    110         case ChannelRight: return channel(1);
    111         case ChannelCenter: return channel(2);
    112         case ChannelSurroundLeft: return channel(3);
    113         case ChannelSurroundRight: return channel(4);
    114         default: return 0;
    115         }
    116 
    117     case 6: // 5.1
    118         switch (channelType) {
    119         case ChannelLeft: return channel(0);
    120         case ChannelRight: return channel(1);
    121         case ChannelCenter: return channel(2);
    122         case ChannelLFE: return channel(3);
    123         case ChannelSurroundLeft: return channel(4);
    124         case ChannelSurroundRight: return channel(5);
    125         default: return 0;
    126         }
    127     }
    128 
    129     ASSERT_NOT_REACHED();
    130     return 0;
    131 }
    132 
    133 // Returns true if the channel count and frame-size match.
    134 bool AudioBus::topologyMatches(const AudioBus& bus) const
    135 {
    136     if (numberOfChannels() != bus.numberOfChannels())
    137         return false; // channel mismatch
    138 
    139     // Make sure source bus has enough frames.
    140     if (length() > bus.length())
    141         return false; // frame-size mismatch
    142 
    143     return true;
    144 }
    145 
    146 PassOwnPtr<AudioBus> AudioBus::createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame)
    147 {
    148     size_t numberOfSourceFrames = sourceBuffer->length();
    149     unsigned numberOfChannels = sourceBuffer->numberOfChannels();
    150 
    151     // Sanity checking
    152     bool isRangeSafe = startFrame < endFrame && endFrame <= numberOfSourceFrames;
    153     ASSERT(isRangeSafe);
    154     if (!isRangeSafe)
    155         return 0;
    156 
    157     size_t rangeLength = endFrame - startFrame;
    158 
    159     OwnPtr<AudioBus> audioBus = adoptPtr(new AudioBus(numberOfChannels, rangeLength));
    160     audioBus->setSampleRate(sourceBuffer->sampleRate());
    161 
    162     for (unsigned i = 0; i < numberOfChannels; ++i)
    163         audioBus->channel(i)->copyFromRange(sourceBuffer->channel(i), startFrame, endFrame);
    164 
    165     return audioBus.release();
    166 }
    167 
    168 float AudioBus::maxAbsValue() const
    169 {
    170     float max = 0.0f;
    171     for (unsigned i = 0; i < numberOfChannels(); ++i) {
    172         const AudioChannel* channel = this->channel(i);
    173         max = std::max(max, channel->maxAbsValue());
    174     }
    175 
    176     return max;
    177 }
    178 
    179 void AudioBus::normalize()
    180 {
    181     float max = maxAbsValue();
    182     if (max)
    183         scale(1.0f / max);
    184 }
    185 
    186 void AudioBus::scale(double scale)
    187 {
    188     for (unsigned i = 0; i < numberOfChannels(); ++i)
    189         channel(i)->scale(scale);
    190 }
    191 
    192 // Just copies the samples from the source bus to this one.
    193 // This is just a simple copy if the number of channels match, otherwise a mixup or mixdown is done.
    194 // For now, we just support a mixup from mono -> stereo.
    195 void AudioBus::copyFrom(const AudioBus& sourceBus)
    196 {
    197     if (&sourceBus == this)
    198         return;
    199 
    200     if (numberOfChannels() == sourceBus.numberOfChannels()) {
    201         for (unsigned i = 0; i < numberOfChannels(); ++i)
    202             channel(i)->copyFrom(sourceBus.channel(i));
    203     } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
    204         // Handle mono -> stereo case (for now simply copy mono channel into both left and right)
    205         // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
    206         const AudioChannel* sourceChannel = sourceBus.channel(0);
    207         channel(0)->copyFrom(sourceChannel);
    208         channel(1)->copyFrom(sourceChannel);
    209     } else {
    210         // Case not handled
    211         ASSERT_NOT_REACHED();
    212     }
    213 }
    214 
    215 void AudioBus::sumFrom(const AudioBus &sourceBus)
    216 {
    217     if (numberOfChannels() == sourceBus.numberOfChannels()) {
    218         for (unsigned i = 0; i < numberOfChannels(); ++i)
    219             channel(i)->sumFrom(sourceBus.channel(i));
    220     } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
    221         // Handle mono -> stereo case (for now simply sum mono channel into both left and right)
    222         // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
    223         const AudioChannel* sourceChannel = sourceBus.channel(0);
    224         channel(0)->sumFrom(sourceChannel);
    225         channel(1)->sumFrom(sourceChannel);
    226     } else {
    227         // Case not handled
    228         ASSERT_NOT_REACHED();
    229     }
    230 }
    231 
    232 void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
    233 {
    234     // We don't want to suddenly change the gain from mixing one time slice to the next,
    235     // so we "de-zipper" by slowly changing the gain each sample-frame until we've achieved the target gain.
    236 
    237     // FIXME: optimize this method (SSE, etc.)
    238     // FIXME: Need fast path here when gain has converged on targetGain. In this case, de-zippering is no longer needed.
    239     // FIXME: Need fast path when this==sourceBus && lastMixGain==targetGain==1.0 && sumToBus==false (this is a NOP)
    240 
    241     // Take master bus gain into account as well as the targetGain.
    242     double totalDesiredGain = m_busGain * targetGain;
    243 
    244     // First time, snap directly to totalDesiredGain.
    245     double gain = m_isFirstTime ? totalDesiredGain : *lastMixGain;
    246     m_isFirstTime = false;
    247 
    248     int numberOfSourceChannels = sourceBus.numberOfChannels();
    249     int numberOfDestinationChannels = numberOfChannels();
    250 
    251     AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
    252     const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
    253     const float* sourceR = numberOfSourceChannels > 1 ? sourceBusSafe.channelByType(ChannelRight)->data() : 0;
    254 
    255     float* destinationL = channelByType(ChannelLeft)->data();
    256     float* destinationR = numberOfDestinationChannels > 1 ? channelByType(ChannelRight)->data() : 0;
    257 
    258     const double DezipperRate = 0.005;
    259     int framesToProcess = length();
    260 
    261     if (sumToBus) {
    262         // Sum to our bus
    263         if (sourceR && destinationR) {
    264             // Stereo
    265             while (framesToProcess--) {
    266                 float sampleL = *sourceL++;
    267                 float sampleR = *sourceR++;
    268                 *destinationL++ += static_cast<float>(gain * sampleL);
    269                 *destinationR++ += static_cast<float>(gain * sampleR);
    270 
    271                 // Slowly change gain to desired gain.
    272                 gain += (totalDesiredGain - gain) * DezipperRate;
    273             }
    274         } else if (destinationR) {
    275             // Mono -> stereo (mix equally into L and R)
    276             // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
    277             while (framesToProcess--) {
    278                 float sample = *sourceL++;
    279                 *destinationL++ += static_cast<float>(gain * sample);
    280                 *destinationR++ += static_cast<float>(gain * sample);
    281 
    282                 // Slowly change gain to desired gain.
    283                 gain += (totalDesiredGain - gain) * DezipperRate;
    284             }
    285         } else {
    286             // Mono
    287             while (framesToProcess--) {
    288                 float sampleL = *sourceL++;
    289                 *destinationL++ += static_cast<float>(gain * sampleL);
    290 
    291                 // Slowly change gain to desired gain.
    292                 gain += (totalDesiredGain - gain) * DezipperRate;
    293             }
    294         }
    295     } else {
    296         // Process directly (without summing) to our bus
    297         if (sourceR && destinationR) {
    298             // Stereo
    299             while (framesToProcess--) {
    300                 float sampleL = *sourceL++;
    301                 float sampleR = *sourceR++;
    302                 *destinationL++ = static_cast<float>(gain * sampleL);
    303                 *destinationR++ = static_cast<float>(gain * sampleR);
    304 
    305                 // Slowly change gain to desired gain.
    306                 gain += (totalDesiredGain - gain) * DezipperRate;
    307             }
    308         } else if (destinationR) {
    309             // Mono -> stereo (mix equally into L and R)
    310             // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
    311             while (framesToProcess--) {
    312                 float sample = *sourceL++;
    313                 *destinationL++ = static_cast<float>(gain * sample);
    314                 *destinationR++ = static_cast<float>(gain * sample);
    315 
    316                 // Slowly change gain to desired gain.
    317                 gain += (totalDesiredGain - gain) * DezipperRate;
    318             }
    319         } else {
    320             // Mono
    321             while (framesToProcess--) {
    322                 float sampleL = *sourceL++;
    323                 *destinationL++ = static_cast<float>(gain * sampleL);
    324 
    325                 // Slowly change gain to desired gain.
    326                 gain += (totalDesiredGain - gain) * DezipperRate;
    327             }
    328         }
    329     }
    330 
    331     // Save the target gain as the starting point for next time around.
    332     *lastMixGain = gain;
    333 }
    334 
    335 void AudioBus::processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
    336 {
    337     // Make sure we're summing from same type of bus.
    338     // We *are* able to sum from mono -> stereo
    339     if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus))
    340         return;
    341 
    342     // Dispatch for different channel layouts
    343     switch (numberOfChannels()) {
    344     case 1: // mono
    345     case 2: // stereo
    346         processWithGainFromMonoStereo(sourceBus, lastMixGain, targetGain, sumToBus);
    347         break;
    348     case 4: // FIXME: implement quad
    349     case 5: // FIXME: implement 5.0
    350     default:
    351         ASSERT_NOT_REACHED();
    352         break;
    353     }
    354 }
    355 
    356 void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
    357 {
    358     processWithGainFrom(sourceBus, lastMixGain, targetGain, false);
    359 }
    360 
    361 void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
    362 {
    363     processWithGainFrom(sourceBus, lastMixGain, targetGain, true);
    364 }
    365 
    366 #if !PLATFORM(MAC)
    367 PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(AudioBus* sourceBus, bool mixToMono, double newSampleRate)
    368 {
    369     // sourceBus's sample-rate must be known.
    370     ASSERT(sourceBus && sourceBus->sampleRate());
    371     if (!sourceBus || !sourceBus->sampleRate())
    372         return 0;
    373 
    374     double sourceSampleRate = sourceBus->sampleRate();
    375     double destinationSampleRate = newSampleRate;
    376     unsigned numberOfSourceChannels = sourceBus->numberOfChannels();
    377 
    378     if (numberOfSourceChannels == 1)
    379         mixToMono = false; // already mono
    380 
    381     if (sourceSampleRate == destinationSampleRate) {
    382         // No sample-rate conversion is necessary.
    383         if (mixToMono)
    384             return AudioBus::createByMixingToMono(sourceBus);
    385 
    386         // Return exact copy.
    387         return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length());
    388     }
    389 
    390     // First, mix to mono (if necessary) then sample-rate convert.
    391     AudioBus* resamplerSourceBus;
    392     OwnPtr<AudioBus> mixedMonoBus;
    393     if (mixToMono) {
    394         mixedMonoBus = AudioBus::createByMixingToMono(sourceBus);
    395         resamplerSourceBus = mixedMonoBus.get();
    396     } else {
    397         // Directly resample without down-mixing.
    398         resamplerSourceBus = sourceBus;
    399     }
    400 
    401     // Calculate destination length based on the sample-rates.
    402     double sampleRateRatio = sourceSampleRate / destinationSampleRate;
    403     int sourceLength = resamplerSourceBus->length();
    404     int destinationLength = sourceLength / sampleRateRatio;
    405 
    406     // Create destination bus with same number of channels.
    407     unsigned numberOfDestinationChannels = resamplerSourceBus->numberOfChannels();
    408     OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(numberOfDestinationChannels, destinationLength)));
    409 
    410     // Sample-rate convert each channel.
    411     for (unsigned i = 0; i < numberOfDestinationChannels; ++i) {
    412         float* source = resamplerSourceBus->channel(i)->data();
    413         float* destination = destinationBus->channel(i)->data();
    414 
    415         SincResampler resampler(sampleRateRatio);
    416         resampler.process(source, destination, sourceLength);
    417     }
    418 
    419     return destinationBus.release();
    420 }
    421 #endif // !PLATFORM(MAC)
    422 
    423 PassOwnPtr<AudioBus> AudioBus::createByMixingToMono(AudioBus* sourceBus)
    424 {
    425     switch (sourceBus->numberOfChannels()) {
    426     case 1:
    427         // Simply create an exact copy.
    428         return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length());
    429     case 2:
    430         {
    431             unsigned n = sourceBus->length();
    432             OwnPtr<AudioBus> destinationBus(adoptPtr(new AudioBus(1, n)));
    433 
    434             float* sourceL = sourceBus->channel(0)->data();
    435             float* sourceR = sourceBus->channel(1)->data();
    436             float* destination = destinationBus->channel(0)->data();
    437 
    438             // Do the mono mixdown.
    439             for (unsigned i = 0; i < n; ++i)
    440                 destination[i] = 0.5 * (sourceL[i] + sourceR[i]);
    441 
    442             return destinationBus.release();
    443         }
    444     }
    445 
    446     ASSERT_NOT_REACHED();
    447     return 0;
    448 }
    449 
    450 } // WebCore
    451 
    452 #endif // ENABLE(WEB_AUDIO)
    453