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