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 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 | #include "DenormalDisabler.h" |
36 | |
37 | #include "SincResampler.h" |
38 | #include "VectorMath.h" |
39 | #include <algorithm> |
40 | #include <assert.h> |
41 | #include <math.h> |
42 | |
43 | namespace WebCore { |
44 | |
45 | using namespace VectorMath; |
46 | |
47 | const unsigned MaxBusChannels = 32; |
48 | |
49 | RefPtr<AudioBus> AudioBus::create(unsigned numberOfChannels, size_t length, bool allocate) |
50 | { |
51 | ASSERT(numberOfChannels <= MaxBusChannels); |
52 | if (numberOfChannels > MaxBusChannels) |
53 | return nullptr; |
54 | |
55 | return adoptRef(*new AudioBus(numberOfChannels, length, allocate)); |
56 | } |
57 | |
58 | AudioBus::AudioBus(unsigned numberOfChannels, size_t length, bool allocate) |
59 | : m_length(length) |
60 | , m_busGain(1) |
61 | , m_isFirstTime(true) |
62 | , m_sampleRate(0) |
63 | { |
64 | m_channels.reserveInitialCapacity(numberOfChannels); |
65 | |
66 | for (unsigned i = 0; i < numberOfChannels; ++i) { |
67 | auto channel = allocate ? std::make_unique<AudioChannel>(length) : std::make_unique<AudioChannel>(nullptr, length); |
68 | m_channels.uncheckedAppend(WTFMove(channel)); |
69 | } |
70 | |
71 | m_layout = LayoutCanonical; // for now this is the only layout we define |
72 | } |
73 | |
74 | void AudioBus::setChannelMemory(unsigned channelIndex, float* storage, size_t length) |
75 | { |
76 | if (channelIndex < m_channels.size()) { |
77 | channel(channelIndex)->set(storage, length); |
78 | m_length = length; // FIXME: verify that this length matches all the other channel lengths |
79 | } |
80 | } |
81 | |
82 | void AudioBus::resizeSmaller(size_t newLength) |
83 | { |
84 | ASSERT(newLength <= m_length); |
85 | if (newLength <= m_length) |
86 | m_length = newLength; |
87 | |
88 | for (unsigned i = 0; i < m_channels.size(); ++i) |
89 | m_channels[i]->resizeSmaller(newLength); |
90 | } |
91 | |
92 | void AudioBus::zero() |
93 | { |
94 | for (unsigned i = 0; i < m_channels.size(); ++i) |
95 | m_channels[i]->zero(); |
96 | } |
97 | |
98 | AudioChannel* AudioBus::channelByType(unsigned channelType) |
99 | { |
100 | // For now we only support canonical channel layouts... |
101 | if (m_layout != LayoutCanonical) |
102 | return 0; |
103 | |
104 | switch (numberOfChannels()) { |
105 | case 1: // mono |
106 | if (channelType == ChannelMono || channelType == ChannelLeft) |
107 | return channel(0); |
108 | return 0; |
109 | |
110 | case 2: // stereo |
111 | switch (channelType) { |
112 | case ChannelLeft: return channel(0); |
113 | case ChannelRight: return channel(1); |
114 | default: return 0; |
115 | } |
116 | |
117 | case 4: // quad |
118 | switch (channelType) { |
119 | case ChannelLeft: return channel(0); |
120 | case ChannelRight: return channel(1); |
121 | case ChannelSurroundLeft: return channel(2); |
122 | case ChannelSurroundRight: return channel(3); |
123 | default: return 0; |
124 | } |
125 | |
126 | case 5: // 5.0 |
127 | switch (channelType) { |
128 | case ChannelLeft: return channel(0); |
129 | case ChannelRight: return channel(1); |
130 | case ChannelCenter: return channel(2); |
131 | case ChannelSurroundLeft: return channel(3); |
132 | case ChannelSurroundRight: return channel(4); |
133 | default: return 0; |
134 | } |
135 | |
136 | case 6: // 5.1 |
137 | switch (channelType) { |
138 | case ChannelLeft: return channel(0); |
139 | case ChannelRight: return channel(1); |
140 | case ChannelCenter: return channel(2); |
141 | case ChannelLFE: return channel(3); |
142 | case ChannelSurroundLeft: return channel(4); |
143 | case ChannelSurroundRight: return channel(5); |
144 | default: return 0; |
145 | } |
146 | } |
147 | |
148 | ASSERT_NOT_REACHED(); |
149 | return 0; |
150 | } |
151 | |
152 | const AudioChannel* AudioBus::channelByType(unsigned type) const |
153 | { |
154 | return const_cast<AudioBus*>(this)->channelByType(type); |
155 | } |
156 | |
157 | // Returns true if the channel count and frame-size match. |
158 | bool AudioBus::topologyMatches(const AudioBus& bus) const |
159 | { |
160 | if (numberOfChannels() != bus.numberOfChannels()) |
161 | return false; // channel mismatch |
162 | |
163 | // Make sure source bus has enough frames. |
164 | if (length() > bus.length()) |
165 | return false; // frame-size mismatch |
166 | |
167 | return true; |
168 | } |
169 | |
170 | RefPtr<AudioBus> AudioBus::createBufferFromRange(const AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame) |
171 | { |
172 | size_t numberOfSourceFrames = sourceBuffer->length(); |
173 | unsigned numberOfChannels = sourceBuffer->numberOfChannels(); |
174 | |
175 | // Sanity checking |
176 | bool isRangeSafe = startFrame < endFrame && endFrame <= numberOfSourceFrames; |
177 | ASSERT(isRangeSafe); |
178 | if (!isRangeSafe) |
179 | return nullptr; |
180 | |
181 | size_t rangeLength = endFrame - startFrame; |
182 | |
183 | RefPtr<AudioBus> audioBus = create(numberOfChannels, rangeLength); |
184 | audioBus->setSampleRate(sourceBuffer->sampleRate()); |
185 | |
186 | for (unsigned i = 0; i < numberOfChannels; ++i) |
187 | audioBus->channel(i)->copyFromRange(sourceBuffer->channel(i), startFrame, endFrame); |
188 | |
189 | return audioBus; |
190 | } |
191 | |
192 | float AudioBus::maxAbsValue() const |
193 | { |
194 | float max = 0.0f; |
195 | for (unsigned i = 0; i < numberOfChannels(); ++i) { |
196 | const AudioChannel* channel = this->channel(i); |
197 | max = std::max(max, channel->maxAbsValue()); |
198 | } |
199 | |
200 | return max; |
201 | } |
202 | |
203 | void AudioBus::normalize() |
204 | { |
205 | float max = maxAbsValue(); |
206 | if (max) |
207 | scale(1.0f / max); |
208 | } |
209 | |
210 | void AudioBus::scale(float scale) |
211 | { |
212 | for (unsigned i = 0; i < numberOfChannels(); ++i) |
213 | channel(i)->scale(scale); |
214 | } |
215 | |
216 | void AudioBus::copyFromRange(const AudioBus& sourceBus, unsigned startFrame, unsigned endFrame) |
217 | { |
218 | if (!topologyMatches(sourceBus)) { |
219 | ASSERT_NOT_REACHED(); |
220 | zero(); |
221 | return; |
222 | } |
223 | |
224 | size_t numberOfSourceFrames = sourceBus.length(); |
225 | bool isRangeSafe = startFrame < endFrame && endFrame <= numberOfSourceFrames; |
226 | ASSERT(isRangeSafe); |
227 | if (!isRangeSafe) { |
228 | zero(); |
229 | return; |
230 | } |
231 | |
232 | unsigned numberOfChannels = this->numberOfChannels(); |
233 | ASSERT(numberOfChannels <= MaxBusChannels); |
234 | if (numberOfChannels > MaxBusChannels) { |
235 | zero(); |
236 | return; |
237 | } |
238 | |
239 | for (unsigned i = 0; i < numberOfChannels; ++i) |
240 | channel(i)->copyFromRange(sourceBus.channel(i), startFrame, endFrame); |
241 | } |
242 | |
243 | void AudioBus::copyFrom(const AudioBus& sourceBus, ChannelInterpretation channelInterpretation) |
244 | { |
245 | if (&sourceBus == this) |
246 | return; |
247 | |
248 | unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); |
249 | unsigned numberOfDestinationChannels = numberOfChannels(); |
250 | |
251 | if (numberOfDestinationChannels == numberOfSourceChannels) { |
252 | for (unsigned i = 0; i < numberOfSourceChannels; ++i) |
253 | channel(i)->copyFrom(sourceBus.channel(i)); |
254 | } else { |
255 | switch (channelInterpretation) { |
256 | case Speakers: |
257 | speakersCopyFrom(sourceBus); |
258 | break; |
259 | case Discrete: |
260 | discreteCopyFrom(sourceBus); |
261 | break; |
262 | default: |
263 | ASSERT_NOT_REACHED(); |
264 | } |
265 | } |
266 | } |
267 | |
268 | void AudioBus::sumFrom(const AudioBus& sourceBus, ChannelInterpretation channelInterpretation) |
269 | { |
270 | if (&sourceBus == this) |
271 | return; |
272 | |
273 | unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); |
274 | unsigned numberOfDestinationChannels = numberOfChannels(); |
275 | |
276 | if (numberOfDestinationChannels == numberOfSourceChannels) { |
277 | for (unsigned i = 0; i < numberOfSourceChannels; ++i) |
278 | channel(i)->sumFrom(sourceBus.channel(i)); |
279 | } else { |
280 | switch (channelInterpretation) { |
281 | case Speakers: |
282 | speakersSumFrom(sourceBus); |
283 | break; |
284 | case Discrete: |
285 | discreteSumFrom(sourceBus); |
286 | break; |
287 | default: |
288 | ASSERT_NOT_REACHED(); |
289 | } |
290 | } |
291 | } |
292 | |
293 | void AudioBus::speakersCopyFrom(const AudioBus& sourceBus) |
294 | { |
295 | // FIXME: Implement down mixing 5.1 to stereo. |
296 | // https://bugs.webkit.org/show_bug.cgi?id=79192 |
297 | |
298 | unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); |
299 | unsigned numberOfDestinationChannels = numberOfChannels(); |
300 | |
301 | if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) { |
302 | // Handle mono -> stereo case (for now simply copy mono channel into both left and right) |
303 | // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center... |
304 | const AudioChannel* sourceChannel = sourceBus.channel(0); |
305 | channel(0)->copyFrom(sourceChannel); |
306 | channel(1)->copyFrom(sourceChannel); |
307 | } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) { |
308 | // Handle stereo -> mono case. output = 0.5 * (input.L + input.R). |
309 | AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); |
310 | |
311 | const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); |
312 | const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data(); |
313 | |
314 | float* destination = channelByType(ChannelLeft)->mutableData(); |
315 | vadd(sourceL, 1, sourceR, 1, destination, 1, length()); |
316 | float scale = 0.5; |
317 | vsmul(destination, 1, &scale, destination, 1, length()); |
318 | } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) { |
319 | // Handle mono -> 5.1 case, copy mono channel to center. |
320 | channel(2)->copyFrom(sourceBus.channel(0)); |
321 | channel(0)->zero(); |
322 | channel(1)->zero(); |
323 | channel(3)->zero(); |
324 | channel(4)->zero(); |
325 | channel(5)->zero(); |
326 | } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) { |
327 | // Handle 5.1 -> mono case. |
328 | zero(); |
329 | speakersSumFrom5_1_ToMono(sourceBus); |
330 | } else { |
331 | // Fallback for unknown combinations. |
332 | discreteCopyFrom(sourceBus); |
333 | } |
334 | } |
335 | |
336 | void AudioBus::(const AudioBus& sourceBus) |
337 | { |
338 | // FIXME: Implement down mixing 5.1 to stereo. |
339 | // https://bugs.webkit.org/show_bug.cgi?id=79192 |
340 | |
341 | unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); |
342 | unsigned numberOfDestinationChannels = numberOfChannels(); |
343 | |
344 | if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) { |
345 | // Handle mono -> stereo case (summing mono channel into both left and right). |
346 | const AudioChannel* sourceChannel = sourceBus.channel(0); |
347 | channel(0)->sumFrom(sourceChannel); |
348 | channel(1)->sumFrom(sourceChannel); |
349 | } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) { |
350 | // Handle stereo -> mono case. output += 0.5 * (input.L + input.R). |
351 | AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); |
352 | |
353 | const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); |
354 | const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data(); |
355 | |
356 | float* destination = channelByType(ChannelLeft)->mutableData(); |
357 | float scale = 0.5; |
358 | vsma(sourceL, 1, &scale, destination, 1, length()); |
359 | vsma(sourceR, 1, &scale, destination, 1, length()); |
360 | } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) { |
361 | // Handle mono -> 5.1 case, sum mono channel into center. |
362 | channel(2)->sumFrom(sourceBus.channel(0)); |
363 | } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) { |
364 | // Handle 5.1 -> mono case. |
365 | speakersSumFrom5_1_ToMono(sourceBus); |
366 | } else { |
367 | // Fallback for unknown combinations. |
368 | discreteSumFrom(sourceBus); |
369 | } |
370 | } |
371 | |
372 | void AudioBus::(const AudioBus& sourceBus) |
373 | { |
374 | AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); |
375 | |
376 | const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); |
377 | const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data(); |
378 | const float* sourceC = sourceBusSafe.channelByType(ChannelCenter)->data(); |
379 | const float* sourceSL = sourceBusSafe.channelByType(ChannelSurroundLeft)->data(); |
380 | const float* sourceSR = sourceBusSafe.channelByType(ChannelSurroundRight)->data(); |
381 | |
382 | float* destination = channelByType(ChannelLeft)->mutableData(); |
383 | |
384 | AudioFloatArray temp(length()); |
385 | float* tempData = temp.data(); |
386 | |
387 | // Sum in L and R. |
388 | vadd(sourceL, 1, sourceR, 1, tempData, 1, length()); |
389 | float scale = 0.7071; |
390 | vsmul(tempData, 1, &scale, tempData, 1, length()); |
391 | vadd(tempData, 1, destination, 1, destination, 1, length()); |
392 | |
393 | // Sum in SL and SR. |
394 | vadd(sourceSL, 1, sourceSR, 1, tempData, 1, length()); |
395 | scale = 0.5; |
396 | vsmul(tempData, 1, &scale, tempData, 1, length()); |
397 | vadd(tempData, 1, destination, 1, destination, 1, length()); |
398 | |
399 | // Sum in center. |
400 | vadd(sourceC, 1, destination, 1, destination, 1, length()); |
401 | } |
402 | |
403 | void AudioBus::discreteCopyFrom(const AudioBus& sourceBus) |
404 | { |
405 | unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); |
406 | unsigned numberOfDestinationChannels = numberOfChannels(); |
407 | |
408 | if (numberOfDestinationChannels < numberOfSourceChannels) { |
409 | // Down-mix by copying channels and dropping the remaining. |
410 | for (unsigned i = 0; i < numberOfDestinationChannels; ++i) |
411 | channel(i)->copyFrom(sourceBus.channel(i)); |
412 | } else if (numberOfDestinationChannels > numberOfSourceChannels) { |
413 | // Up-mix by copying as many channels as we have, then zeroing remaining channels. |
414 | for (unsigned i = 0; i < numberOfSourceChannels; ++i) |
415 | channel(i)->copyFrom(sourceBus.channel(i)); |
416 | for (unsigned i = numberOfSourceChannels; i < numberOfDestinationChannels; ++i) |
417 | channel(i)->zero(); |
418 | } |
419 | } |
420 | |
421 | void AudioBus::discreteSumFrom(const AudioBus& sourceBus) |
422 | { |
423 | unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); |
424 | unsigned numberOfDestinationChannels = numberOfChannels(); |
425 | |
426 | if (numberOfDestinationChannels < numberOfSourceChannels) { |
427 | // Down-mix by summing channels and dropping the remaining. |
428 | for (unsigned i = 0; i < numberOfDestinationChannels; ++i) |
429 | channel(i)->sumFrom(sourceBus.channel(i)); |
430 | } else if (numberOfDestinationChannels > numberOfSourceChannels) { |
431 | // Up-mix by summing as many channels as we have. |
432 | for (unsigned i = 0; i < numberOfSourceChannels; ++i) |
433 | channel(i)->sumFrom(sourceBus.channel(i)); |
434 | } |
435 | } |
436 | |
437 | void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain) |
438 | { |
439 | if (!topologyMatches(sourceBus)) { |
440 | ASSERT_NOT_REACHED(); |
441 | zero(); |
442 | return; |
443 | } |
444 | |
445 | if (sourceBus.isSilent()) { |
446 | zero(); |
447 | return; |
448 | } |
449 | |
450 | unsigned numberOfChannels = this->numberOfChannels(); |
451 | ASSERT(numberOfChannels <= MaxBusChannels); |
452 | if (numberOfChannels > MaxBusChannels) |
453 | return; |
454 | |
455 | // If it is copying from the same bus and no need to change gain, just return. |
456 | if (this == &sourceBus && *lastMixGain == targetGain && targetGain == 1) |
457 | return; |
458 | |
459 | AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); |
460 | const float* sources[MaxBusChannels]; |
461 | float* destinations[MaxBusChannels]; |
462 | |
463 | for (unsigned i = 0; i < numberOfChannels; ++i) { |
464 | sources[i] = sourceBusSafe.channel(i)->data(); |
465 | destinations[i] = channel(i)->mutableData(); |
466 | } |
467 | |
468 | // We don't want to suddenly change the gain from mixing one time slice to the next, |
469 | // so we "de-zipper" by slowly changing the gain each sample-frame until we've achieved the target gain. |
470 | |
471 | // Take master bus gain into account as well as the targetGain. |
472 | float totalDesiredGain = static_cast<float>(m_busGain * targetGain); |
473 | |
474 | // First time, snap directly to totalDesiredGain. |
475 | float gain = static_cast<float>(m_isFirstTime ? totalDesiredGain : *lastMixGain); |
476 | m_isFirstTime = false; |
477 | |
478 | const float DezipperRate = 0.005f; |
479 | unsigned framesToProcess = length(); |
480 | |
481 | // If the gain is within epsilon of totalDesiredGain, we can skip dezippering. |
482 | // FIXME: this value may need tweaking. |
483 | const float epsilon = 0.001f; |
484 | float gainDiff = fabs(totalDesiredGain - gain); |
485 | |
486 | // Number of frames to de-zipper before we are close enough to the target gain. |
487 | // FIXME: framesToDezipper could be smaller when target gain is close enough within this process loop. |
488 | unsigned framesToDezipper = (gainDiff < epsilon) ? 0 : framesToProcess; |
489 | |
490 | if (framesToDezipper) { |
491 | if (!m_dezipperGainValues.get() || m_dezipperGainValues->size() < framesToDezipper) |
492 | m_dezipperGainValues = std::make_unique<AudioFloatArray>(framesToDezipper); |
493 | |
494 | float* gainValues = m_dezipperGainValues->data(); |
495 | for (unsigned i = 0; i < framesToDezipper; ++i) { |
496 | gain += (totalDesiredGain - gain) * DezipperRate; |
497 | |
498 | // FIXME: If we are clever enough in calculating the framesToDezipper value, we can probably get |
499 | // rid of this DenormalDisabler::flushDenormalFloatToZero() call. |
500 | gain = DenormalDisabler::flushDenormalFloatToZero(gain); |
501 | *gainValues++ = gain; |
502 | } |
503 | |
504 | for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) { |
505 | vmul(sources[channelIndex], 1, m_dezipperGainValues->data(), 1, destinations[channelIndex], 1, framesToDezipper); |
506 | sources[channelIndex] += framesToDezipper; |
507 | destinations[channelIndex] += framesToDezipper; |
508 | } |
509 | } else |
510 | gain = totalDesiredGain; |
511 | |
512 | // Apply constant gain after de-zippering has converged on target gain. |
513 | if (framesToDezipper < framesToProcess) { |
514 | // Handle gains of 0 and 1 (exactly) specially. |
515 | if (gain == 1) { |
516 | for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) |
517 | memcpy(destinations[channelIndex], sources[channelIndex], (framesToProcess - framesToDezipper) * sizeof(*destinations[channelIndex])); |
518 | } else if (!gain) { |
519 | for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) |
520 | memset(destinations[channelIndex], 0, (framesToProcess - framesToDezipper) * sizeof(*destinations[channelIndex])); |
521 | } else { |
522 | for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) |
523 | vsmul(sources[channelIndex], 1, &gain, destinations[channelIndex], 1, framesToProcess - framesToDezipper); |
524 | } |
525 | } |
526 | |
527 | // Save the target gain as the starting point for next time around. |
528 | *lastMixGain = gain; |
529 | } |
530 | |
531 | void AudioBus::copyWithSampleAccurateGainValuesFrom(const AudioBus &sourceBus, float* gainValues, unsigned numberOfGainValues) |
532 | { |
533 | // Make sure we're processing from the same type of bus. |
534 | // We *are* able to process from mono -> stereo |
535 | if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus)) { |
536 | ASSERT_NOT_REACHED(); |
537 | return; |
538 | } |
539 | |
540 | if (!gainValues || numberOfGainValues > sourceBus.length()) { |
541 | ASSERT_NOT_REACHED(); |
542 | return; |
543 | } |
544 | |
545 | if (sourceBus.length() == numberOfGainValues && sourceBus.length() == length() && sourceBus.isSilent()) { |
546 | zero(); |
547 | return; |
548 | } |
549 | |
550 | // We handle both the 1 -> N and N -> N case here. |
551 | const float* source = sourceBus.channel(0)->data(); |
552 | for (unsigned channelIndex = 0; channelIndex < numberOfChannels(); ++channelIndex) { |
553 | if (sourceBus.numberOfChannels() == numberOfChannels()) |
554 | source = sourceBus.channel(channelIndex)->data(); |
555 | float* destination = channel(channelIndex)->mutableData(); |
556 | vmul(source, 1, gainValues, 1, destination, 1, numberOfGainValues); |
557 | } |
558 | } |
559 | |
560 | RefPtr<AudioBus> AudioBus::createBySampleRateConverting(const AudioBus* sourceBus, bool mixToMono, double newSampleRate) |
561 | { |
562 | // sourceBus's sample-rate must be known. |
563 | ASSERT(sourceBus && sourceBus->sampleRate()); |
564 | if (!sourceBus || !sourceBus->sampleRate()) |
565 | return nullptr; |
566 | |
567 | double sourceSampleRate = sourceBus->sampleRate(); |
568 | double destinationSampleRate = newSampleRate; |
569 | double sampleRateRatio = sourceSampleRate / destinationSampleRate; |
570 | unsigned numberOfSourceChannels = sourceBus->numberOfChannels(); |
571 | |
572 | if (numberOfSourceChannels == 1) |
573 | mixToMono = false; // already mono |
574 | |
575 | if (sourceSampleRate == destinationSampleRate) { |
576 | // No sample-rate conversion is necessary. |
577 | if (mixToMono) |
578 | return AudioBus::createByMixingToMono(sourceBus); |
579 | |
580 | // Return exact copy. |
581 | return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length()); |
582 | } |
583 | |
584 | if (sourceBus->isSilent()) { |
585 | RefPtr<AudioBus> silentBus = create(numberOfSourceChannels, sourceBus->length() / sampleRateRatio); |
586 | silentBus->setSampleRate(newSampleRate); |
587 | return silentBus; |
588 | } |
589 | |
590 | // First, mix to mono (if necessary) then sample-rate convert. |
591 | const AudioBus* resamplerSourceBus; |
592 | RefPtr<AudioBus> mixedMonoBus; |
593 | if (mixToMono) { |
594 | mixedMonoBus = AudioBus::createByMixingToMono(sourceBus); |
595 | resamplerSourceBus = mixedMonoBus.get(); |
596 | } else { |
597 | // Directly resample without down-mixing. |
598 | resamplerSourceBus = sourceBus; |
599 | } |
600 | |
601 | // Calculate destination length based on the sample-rates. |
602 | int sourceLength = resamplerSourceBus->length(); |
603 | int destinationLength = sourceLength / sampleRateRatio; |
604 | |
605 | // Create destination bus with same number of channels. |
606 | unsigned numberOfDestinationChannels = resamplerSourceBus->numberOfChannels(); |
607 | RefPtr<AudioBus> destinationBus = create(numberOfDestinationChannels, destinationLength); |
608 | |
609 | // Sample-rate convert each channel. |
610 | for (unsigned i = 0; i < numberOfDestinationChannels; ++i) { |
611 | const float* source = resamplerSourceBus->channel(i)->data(); |
612 | float* destination = destinationBus->channel(i)->mutableData(); |
613 | |
614 | SincResampler resampler(sampleRateRatio); |
615 | resampler.process(source, destination, sourceLength); |
616 | } |
617 | |
618 | destinationBus->clearSilentFlag(); |
619 | destinationBus->setSampleRate(newSampleRate); |
620 | return destinationBus; |
621 | } |
622 | |
623 | RefPtr<AudioBus> AudioBus::createByMixingToMono(const AudioBus* sourceBus) |
624 | { |
625 | if (sourceBus->isSilent()) |
626 | return create(1, sourceBus->length()); |
627 | |
628 | switch (sourceBus->numberOfChannels()) { |
629 | case 1: |
630 | // Simply create an exact copy. |
631 | return AudioBus::createBufferFromRange(sourceBus, 0, sourceBus->length()); |
632 | case 2: |
633 | { |
634 | unsigned n = sourceBus->length(); |
635 | RefPtr<AudioBus> destinationBus = create(1, n); |
636 | |
637 | const float* sourceL = sourceBus->channel(0)->data(); |
638 | const float* sourceR = sourceBus->channel(1)->data(); |
639 | float* destination = destinationBus->channel(0)->mutableData(); |
640 | |
641 | // Do the mono mixdown. |
642 | for (unsigned i = 0; i < n; ++i) |
643 | destination[i] = (sourceL[i] + sourceR[i]) / 2; |
644 | |
645 | destinationBus->clearSilentFlag(); |
646 | destinationBus->setSampleRate(sourceBus->sampleRate()); |
647 | return destinationBus; |
648 | } |
649 | } |
650 | |
651 | ASSERT_NOT_REACHED(); |
652 | return nullptr; |
653 | } |
654 | |
655 | bool AudioBus::isSilent() const |
656 | { |
657 | for (size_t i = 0; i < m_channels.size(); ++i) { |
658 | if (!m_channels[i]->isSilent()) |
659 | return false; |
660 | } |
661 | return true; |
662 | } |
663 | |
664 | void AudioBus::clearSilentFlag() |
665 | { |
666 | for (size_t i = 0; i < m_channels.size(); ++i) |
667 | m_channels[i]->clearSilentFlag(); |
668 | } |
669 | |
670 | } // WebCore |
671 | |
672 | #endif // ENABLE(WEB_AUDIO) |
673 | |