diff options
Diffstat (limited to 'Source/WebCore/platform/audio/AudioBus.cpp')
-rw-r--r-- | Source/WebCore/platform/audio/AudioBus.cpp | 228 |
1 files changed, 57 insertions, 171 deletions
diff --git a/Source/WebCore/platform/audio/AudioBus.cpp b/Source/WebCore/platform/audio/AudioBus.cpp index b486a38b4..58a5e340d 100644 --- a/Source/WebCore/platform/audio/AudioBus.cpp +++ b/Source/WebCore/platform/audio/AudioBus.cpp @@ -45,13 +45,19 @@ namespace WebCore { using namespace VectorMath; - + +const unsigned MaxBusChannels = 32; + AudioBus::AudioBus(unsigned numberOfChannels, size_t length, bool allocate) : m_length(length) , m_busGain(1) , m_isFirstTime(true) , m_sampleRate(0) { + ASSERT(numberOfChannels <= MaxBusChannels); + if (numberOfChannels > MaxBusChannels) + return; + m_channels.reserveInitialCapacity(numberOfChannels); for (unsigned i = 0; i < numberOfChannels; ++i) { @@ -307,106 +313,37 @@ void AudioBus::sumFrom(const AudioBus &sourceBus) } } -// Slowly change gain to desired gain. -#define GAIN_DEZIPPER \ - gain += (totalDesiredGain - gain) * DezipperRate; \ - gain = DenormalDisabler::flushDenormalFloatToZero(gain); - -// De-zipper for the first framesToDezipper frames and skip de-zippering for the remaining frames -// because the gain is close enough to the target gain. -#define PROCESS_WITH_GAIN(OP) \ - for (k = 0; k < framesToDezipper; ++k) { \ - OP \ - GAIN_DEZIPPER \ - } \ - if (!framesToDezipper) \ - gain = totalDesiredGain; \ - OP##_V - -#define STEREO_SUM \ - { \ - float sumL = DenormalDisabler::flushDenormalFloatToZero(*destinationL + gain * *sourceL++); \ - float sumR = DenormalDisabler::flushDenormalFloatToZero(*destinationR + gain * *sourceR++); \ - *destinationL++ = sumL; \ - *destinationR++ = sumR; \ - } - -#define STEREO_SUM_V \ - { \ - vsma(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ - vsma(sourceR, 1, &gain, destinationR, 1, framesToProcess - k); \ - } - -// Mono -> stereo (mix equally into L and R) -// FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center... -#define MONO2STEREO_SUM \ - { \ - float scaled = gain * *sourceL++; \ - float sumL = DenormalDisabler::flushDenormalFloatToZero(*destinationL + scaled); \ - float sumR = DenormalDisabler::flushDenormalFloatToZero(*destinationR + scaled); \ - *destinationL++ = sumL; \ - *destinationR++ = sumR; \ - } - -#define MONO2STEREO_SUM_V \ - { \ - vsma(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ - vsma(sourceL, 1, &gain, destinationR, 1, framesToProcess - k); \ - } - -#define MONO_SUM \ - { \ - float sum = DenormalDisabler::flushDenormalFloatToZero(*destinationL + gain * *sourceL++); \ - *destinationL++ = sum; \ +void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain) +{ + if (!topologyMatches(sourceBus)) { + ASSERT_NOT_REACHED(); + zero(); + return; } -#define MONO_SUM_V \ - { \ - vsma(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ - } - -#define STEREO_NO_SUM \ - { \ - float sampleL = *sourceL++; \ - float sampleR = *sourceR++; \ - *destinationL++ = DenormalDisabler::flushDenormalFloatToZero(gain * sampleL); \ - *destinationR++ = DenormalDisabler::flushDenormalFloatToZero(gain * sampleR); \ + if (sourceBus.isSilent()) { + zero(); + return; } -#define STEREO_NO_SUM_V \ - { \ - vsmul(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ - vsmul(sourceR, 1, &gain, destinationR, 1, framesToProcess - k); \ - } + unsigned numberOfChannels = this->numberOfChannels(); + ASSERT(numberOfChannels <= MaxBusChannels); + if (numberOfChannels > MaxBusChannels) + return; -// Mono -> stereo (mix equally into L and R) -// FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center... -#define MONO2STEREO_NO_SUM \ - { \ - float sample = *sourceL++; \ - *destinationL++ = DenormalDisabler::flushDenormalFloatToZero(gain * sample); \ - *destinationR++ = DenormalDisabler::flushDenormalFloatToZero(gain * sample); \ - } + // If it is copying from the same bus and no need to change gain, just return. + if (this == &sourceBus && *lastMixGain == targetGain && targetGain == 1) + return; -#define MONO2STEREO_NO_SUM_V \ - { \ - vsmul(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ - vsmul(sourceL, 1, &gain, destinationR, 1, framesToProcess - k); \ - } + AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); + const float* sources[MaxBusChannels]; + float* destinations[MaxBusChannels]; -#define MONO_NO_SUM \ - { \ - float sampleL = *sourceL++; \ - *destinationL++ = DenormalDisabler::flushDenormalFloatToZero(gain * sampleL); \ + for (unsigned i = 0; i < numberOfChannels; ++i) { + sources[i] = sourceBusSafe.channel(i)->data(); + destinations[i] = channel(i)->mutableData(); } -#define MONO_NO_SUM_V \ - { \ - vsmul(sourceL, 1, &gain, destinationL, 1, framesToProcess - k); \ - } - -void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, float* lastMixGain, float targetGain, bool sumToBus) -{ // We don't want to suddenly change the gain from mixing one time slice to the next, // so we "de-zipper" by slowly changing the gain each sample-frame until we've achieved the target gain. @@ -417,24 +354,8 @@ void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, float* l float gain = static_cast<float>(m_isFirstTime ? totalDesiredGain : *lastMixGain); m_isFirstTime = false; - int numberOfSourceChannels = sourceBus.numberOfChannels(); - int numberOfDestinationChannels = numberOfChannels(); - - AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); - const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); - const float* sourceR = numberOfSourceChannels > 1 ? sourceBusSafe.channelByType(ChannelRight)->data() : 0; - - if (sourceBusSafe.isSilent()) { - if (!sumToBus) - zero(); - return; - } - - float* destinationL = channelByType(ChannelLeft)->mutableData(); - float* destinationR = numberOfDestinationChannels > 1 ? channelByType(ChannelRight)->mutableData() : 0; - const float DezipperRate = 0.005f; - int framesToProcess = length(); + unsigned framesToProcess = length(); // If the gain is within epsilon of totalDesiredGain, we can skip dezippering. // FIXME: this value may need tweaking. @@ -442,66 +363,41 @@ void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, float* l float gainDiff = fabs(totalDesiredGain - gain); // Number of frames to de-zipper before we are close enough to the target gain. - int framesToDezipper = (gainDiff < epsilon) ? 0 : framesToProcess; - - int k = 0; - - if (sumToBus) { - // Sum to our bus - if (sourceR && destinationR) { - // Stereo - PROCESS_WITH_GAIN(STEREO_SUM) - } else if (destinationR) { - // Mono -> stereo - PROCESS_WITH_GAIN(MONO2STEREO_SUM) - } else { - // Mono - PROCESS_WITH_GAIN(MONO_SUM) + // FIXME: framesToDezipper could be smaller when target gain is close enough within this process loop. + unsigned framesToDezipper = (gainDiff < epsilon) ? 0 : framesToProcess; + + if (framesToDezipper) { + if (!m_dezipperGainValues.get() || m_dezipperGainValues->size() < framesToDezipper) + m_dezipperGainValues = adoptPtr(new AudioFloatArray(framesToDezipper)); + + float* gainValues = m_dezipperGainValues->data(); + for (unsigned i = 0; i < framesToDezipper; ++i) { + gain += (totalDesiredGain - gain) * DezipperRate; + + // FIXME: If we are clever enough in calculating the framesToDezipper value, we can probably get + // rid of this DenormalDisabler::flushDenormalFloatToZero() call. + gain = DenormalDisabler::flushDenormalFloatToZero(gain); + *gainValues++ = gain; } - } else { - // Process directly (without summing) to our bus - if (sourceR && destinationR) { - // Stereo - PROCESS_WITH_GAIN(STEREO_NO_SUM) - } else if (destinationR) { - // Mono -> stereo - PROCESS_WITH_GAIN(MONO2STEREO_NO_SUM) - } else { - // Mono - PROCESS_WITH_GAIN(MONO_NO_SUM) + + for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) { + vmul(sources[channelIndex], 1, m_dezipperGainValues->data(), 1, destinations[channelIndex], 1, framesToDezipper); + sources[channelIndex] += framesToDezipper; + destinations[channelIndex] += framesToDezipper; } + } else + gain = totalDesiredGain; + + // Apply constant gain after de-zippering has converged on target gain. + if (framesToDezipper < framesToProcess) { + for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) + vsmul(sources[channelIndex], 1, &gain, destinations[channelIndex], 1, framesToProcess - framesToDezipper); } // Save the target gain as the starting point for next time around. *lastMixGain = gain; } -void AudioBus::processWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain, bool sumToBus) -{ - // Make sure we're summing from same type of bus. - // We *are* able to sum from mono -> stereo - if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus)) { - ASSERT_NOT_REACHED(); - return; - } - // If it is copying from the same bus and no need to change gain, just return - if (!sumToBus && this == &sourceBus && *lastMixGain == targetGain && targetGain == 1.0) - return; - - // Dispatch for different channel layouts - switch (numberOfChannels()) { - case 1: // mono - case 2: // stereo - processWithGainFromMonoStereo(sourceBus, lastMixGain, targetGain, sumToBus); - break; - case 4: // FIXME: implement quad - case 5: // FIXME: implement 5.0 - default: - ASSERT_NOT_REACHED(); - break; - } -} - void AudioBus::copyWithSampleAccurateGainValuesFrom(const AudioBus &sourceBus, float* gainValues, unsigned numberOfGainValues) { // Make sure we're processing from the same type of bus. @@ -531,16 +427,6 @@ void AudioBus::copyWithSampleAccurateGainValuesFrom(const AudioBus &sourceBus, f } } -void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain) -{ - processWithGainFrom(sourceBus, lastMixGain, targetGain, false); -} - -void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain) -{ - processWithGainFrom(sourceBus, lastMixGain, targetGain, true); -} - PassOwnPtr<AudioBus> AudioBus::createBySampleRateConverting(const AudioBus* sourceBus, bool mixToMono, double newSampleRate) { // sourceBus's sample-rate must be known. |