AudioNodeEngine.cpp (13505B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "AudioNodeEngine.h" 8 9 #include "mozilla/AbstractThread.h" 10 #ifdef USE_NEON 11 # include "AudioNodeEngineGeneric.h" 12 # include "mozilla/arm.h" 13 #endif 14 #ifdef USE_SSE2 15 # include "AudioNodeEngineGeneric.h" 16 # include "mozilla/SSE.h" 17 #endif 18 #if defined(USE_SSE42) && defined(USE_FMA3) 19 # include "AudioNodeEngineGeneric.h" 20 # include "mozilla/SSE.h" 21 #endif 22 #include "AudioBlock.h" 23 #include "Tracing.h" 24 25 namespace mozilla { 26 27 already_AddRefed<ThreadSharedFloatArrayBufferList> 28 ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount, size_t aLength, 29 const mozilla::fallible_t&) { 30 RefPtr<ThreadSharedFloatArrayBufferList> buffer = 31 new ThreadSharedFloatArrayBufferList(aChannelCount); 32 33 for (uint32_t i = 0; i < aChannelCount; ++i) { 34 float* channelData = js_pod_malloc<float>(aLength); 35 if (!channelData) { 36 return nullptr; 37 } 38 39 buffer->SetData(i, channelData, js_free, channelData); 40 } 41 42 return buffer.forget(); 43 } 44 45 void WriteZeroesToAudioBlock(AudioBlock* aChunk, uint32_t aStart, 46 uint32_t aLength) { 47 MOZ_ASSERT(aStart + aLength <= WEBAUDIO_BLOCK_SIZE); 48 MOZ_ASSERT(!aChunk->IsNull(), "You should pass a non-null chunk"); 49 if (aLength == 0) { 50 return; 51 } 52 53 for (uint32_t i = 0; i < aChunk->ChannelCount(); ++i) { 54 PodZero(aChunk->ChannelFloatsForWrite(i) + aStart, aLength); 55 } 56 } 57 58 void AudioBufferCopyWithScale(const float* aInput, float aScale, float* aOutput, 59 uint32_t aSize) { 60 if (aScale == 1.0f) { 61 PodCopy(aOutput, aInput, aSize); 62 } else { 63 for (uint32_t i = 0; i < aSize; ++i) { 64 aOutput[i] = aInput[i] * aScale; 65 } 66 } 67 } 68 69 void AudioBufferAddWithScale(const float* aInput, float aScale, float* aOutput, 70 uint32_t aSize) { 71 #ifdef USE_NEON 72 if (mozilla::supports_neon()) { 73 Engine<xsimd::neon>::AudioBufferAddWithScale(aInput, aScale, aOutput, 74 aSize); 75 return; 76 } 77 #endif 78 79 #ifdef USE_SSE2 80 if (mozilla::supports_sse2()) { 81 # if defined(USE_SSE42) && defined(USE_FMA3) 82 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) { 83 Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBufferAddWithScale( 84 aInput, aScale, aOutput, aSize); 85 } else 86 # endif 87 { 88 Engine<xsimd::sse2>::AudioBufferAddWithScale(aInput, aScale, aOutput, 89 aSize); 90 } 91 return; 92 } 93 #endif 94 95 if (aScale == 1.0f) { 96 for (uint32_t i = 0; i < aSize; ++i) { 97 aOutput[i] += aInput[i]; 98 } 99 } else { 100 for (uint32_t i = 0; i < aSize; ++i) { 101 aOutput[i] += aInput[i] * aScale; 102 } 103 } 104 } 105 106 void AudioBlockAddChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE], 107 float aScale, 108 float aOutput[WEBAUDIO_BLOCK_SIZE]) { 109 AudioBufferAddWithScale(aInput, aScale, aOutput, WEBAUDIO_BLOCK_SIZE); 110 } 111 112 void AudioBlockCopyChannelWithScale(const float* aInput, float aScale, 113 float* aOutput) { 114 if (aScale == 1.0f) { 115 memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE * sizeof(float)); 116 } else { 117 #ifdef USE_NEON 118 if (mozilla::supports_neon()) { 119 Engine<xsimd::neon>::AudioBlockCopyChannelWithScale(aInput, aScale, 120 aOutput); 121 return; 122 } 123 #endif 124 125 #ifdef USE_SSE2 126 if (mozilla::supports_sse2()) { 127 Engine<xsimd::sse2>::AudioBlockCopyChannelWithScale(aInput, aScale, 128 aOutput); 129 return; 130 } 131 #endif 132 133 for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { 134 aOutput[i] = aInput[i] * aScale; 135 } 136 } 137 } 138 139 void BufferComplexMultiply(const float* aInput, const float* aScale, 140 float* aOutput, uint32_t aSize) { 141 #ifdef USE_NEON 142 if (mozilla::supports_neon()) { 143 Engine<xsimd::neon>::BufferComplexMultiply(aInput, aScale, aOutput, aSize); 144 return; 145 } 146 #endif 147 #ifdef USE_SSE2 148 if (mozilla::supports_sse()) { 149 # if defined(USE_SSE42) && defined(USE_FMA3) 150 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) { 151 Engine<xsimd::fma3<xsimd::sse4_2>>::BufferComplexMultiply(aInput, aScale, 152 aOutput, aSize); 153 } else 154 # endif 155 { 156 Engine<xsimd::sse2>::BufferComplexMultiply(aInput, aScale, aOutput, 157 aSize); 158 } 159 return; 160 } 161 #endif 162 163 for (uint32_t i = 0; i < aSize * 2; i += 2) { 164 float real1 = aInput[i]; 165 float imag1 = aInput[i + 1]; 166 float real2 = aScale[i]; 167 float imag2 = aScale[i + 1]; 168 float realResult = real1 * real2 - imag1 * imag2; 169 float imagResult = real1 * imag2 + imag1 * real2; 170 aOutput[i] = realResult; 171 aOutput[i + 1] = imagResult; 172 } 173 } 174 175 float AudioBufferPeakValue(const float* aInput, uint32_t aSize) { 176 float max = 0.0f; 177 for (uint32_t i = 0; i < aSize; i++) { 178 float mag = fabs(aInput[i]); 179 if (mag > max) { 180 max = mag; 181 } 182 } 183 return max; 184 } 185 186 void AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE], 187 const float aScale[WEBAUDIO_BLOCK_SIZE], 188 float aOutput[WEBAUDIO_BLOCK_SIZE]) { 189 #ifdef USE_NEON 190 if (mozilla::supports_neon()) { 191 Engine<xsimd::neon>::AudioBlockCopyChannelWithScale(aInput, aScale, 192 aOutput); 193 return; 194 } 195 #endif 196 197 #ifdef USE_SSE2 198 if (mozilla::supports_sse2()) { 199 Engine<xsimd::sse2>::AudioBlockCopyChannelWithScale(aInput, aScale, 200 aOutput); 201 return; 202 } 203 #endif 204 205 for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { 206 aOutput[i] = aInput[i] * aScale[i]; 207 } 208 } 209 210 void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE], float aScale) { 211 AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE); 212 } 213 214 void AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE], 215 float aScale[WEBAUDIO_BLOCK_SIZE]) { 216 AudioBufferInPlaceScale(aBlock, aScale, WEBAUDIO_BLOCK_SIZE); 217 } 218 219 void AudioBufferInPlaceScale(float* aBlock, float aScale, uint32_t aSize) { 220 if (aScale == 1.0f) { 221 return; 222 } 223 #ifdef USE_NEON 224 if (mozilla::supports_neon()) { 225 Engine<xsimd::neon>::AudioBufferInPlaceScale(aBlock, aScale, aSize); 226 return; 227 } 228 #endif 229 230 #ifdef USE_SSE2 231 if (mozilla::supports_sse2()) { 232 Engine<xsimd::sse2>::AudioBufferInPlaceScale(aBlock, aScale, aSize); 233 return; 234 } 235 #endif 236 237 for (uint32_t i = 0; i < aSize; ++i) { 238 *aBlock++ *= aScale; 239 } 240 } 241 242 void AudioBufferInPlaceScale(float* aBlock, float* aScale, uint32_t aSize) { 243 #ifdef USE_NEON 244 if (mozilla::supports_neon()) { 245 Engine<xsimd::neon>::AudioBufferInPlaceScale(aBlock, aScale, aSize); 246 return; 247 } 248 #endif 249 250 #ifdef USE_SSE2 251 if (mozilla::supports_sse2()) { 252 Engine<xsimd::sse2>::AudioBufferInPlaceScale(aBlock, aScale, aSize); 253 return; 254 } 255 #endif 256 257 for (uint32_t i = 0; i < aSize; ++i) { 258 *aBlock++ *= *aScale++; 259 } 260 } 261 262 void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE], 263 float aGainL[WEBAUDIO_BLOCK_SIZE], 264 float aGainR[WEBAUDIO_BLOCK_SIZE], 265 float aOutputL[WEBAUDIO_BLOCK_SIZE], 266 float aOutputR[WEBAUDIO_BLOCK_SIZE]) { 267 AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL); 268 AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR); 269 } 270 271 void AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE], 272 float aGainL, float aGainR, 273 float aOutputL[WEBAUDIO_BLOCK_SIZE], 274 float aOutputR[WEBAUDIO_BLOCK_SIZE]) { 275 AudioBlockCopyChannelWithScale(aInput, aGainL, aOutputL); 276 AudioBlockCopyChannelWithScale(aInput, aGainR, aOutputR); 277 } 278 279 void AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE], 280 const float aInputR[WEBAUDIO_BLOCK_SIZE], 281 float aGainL, float aGainR, bool aIsOnTheLeft, 282 float aOutputL[WEBAUDIO_BLOCK_SIZE], 283 float aOutputR[WEBAUDIO_BLOCK_SIZE]) { 284 #ifdef USE_NEON 285 if (mozilla::supports_neon()) { 286 Engine<xsimd::neon>::AudioBlockPanStereoToStereo( 287 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR); 288 return; 289 } 290 #endif 291 292 #ifdef USE_SSE2 293 if (mozilla::supports_sse2()) { 294 # if defined(USE_SSE42) && defined(USE_FMA3) 295 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) { 296 Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBlockPanStereoToStereo( 297 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR); 298 } else 299 # endif 300 { 301 Engine<xsimd::sse2>::AudioBlockPanStereoToStereo( 302 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR); 303 } 304 return; 305 } 306 #endif 307 308 uint32_t i; 309 310 if (aIsOnTheLeft) { 311 for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { 312 aOutputL[i] = aInputL[i] + aInputR[i] * aGainL; 313 aOutputR[i] = aInputR[i] * aGainR; 314 } 315 } else { 316 for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) { 317 aOutputL[i] = aInputL[i] * aGainL; 318 aOutputR[i] = aInputR[i] + aInputL[i] * aGainR; 319 } 320 } 321 } 322 323 void AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE], 324 const float aInputR[WEBAUDIO_BLOCK_SIZE], 325 const float aGainL[WEBAUDIO_BLOCK_SIZE], 326 const float aGainR[WEBAUDIO_BLOCK_SIZE], 327 const bool aIsOnTheLeft[WEBAUDIO_BLOCK_SIZE], 328 float aOutputL[WEBAUDIO_BLOCK_SIZE], 329 float aOutputR[WEBAUDIO_BLOCK_SIZE]) { 330 #ifdef USE_NEON 331 if (mozilla::supports_neon()) { 332 Engine<xsimd::neon>::AudioBlockPanStereoToStereo( 333 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR); 334 return; 335 } 336 #endif 337 338 #ifdef USE_SSE2 339 if (mozilla::supports_sse2()) { 340 # if defined(USE_SSE42) && defined(USE_FMA3) 341 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) { 342 Engine<xsimd::fma3<xsimd::sse2>>::AudioBlockPanStereoToStereo( 343 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR); 344 } else 345 # endif 346 { 347 Engine<xsimd::sse2>::AudioBlockPanStereoToStereo( 348 aInputL, aInputR, aGainL, aGainR, aIsOnTheLeft, aOutputL, aOutputR); 349 } 350 return; 351 } 352 #endif 353 354 uint32_t i; 355 for (i = 0; i < WEBAUDIO_BLOCK_SIZE; i++) { 356 if (aIsOnTheLeft[i]) { 357 aOutputL[i] = aInputL[i] + aInputR[i] * aGainL[i]; 358 aOutputR[i] = aInputR[i] * aGainR[i]; 359 } else { 360 aOutputL[i] = aInputL[i] * aGainL[i]; 361 aOutputR[i] = aInputR[i] + aInputL[i] * aGainR[i]; 362 } 363 } 364 } 365 366 float AudioBufferSumOfSquares(const float* aInput, uint32_t aLength) { 367 #ifdef USE_NEON 368 if (mozilla::supports_neon()) { 369 return Engine<xsimd::neon>::AudioBufferSumOfSquares(aInput, aLength); 370 } 371 #endif 372 373 #ifdef USE_SSE2 374 if (mozilla::supports_sse()) { 375 # if defined(USE_SSE42) && defined(USE_FMA3) 376 if (mozilla::supports_fma3() && mozilla::supports_sse4_2()) { 377 return Engine<xsimd::fma3<xsimd::sse4_2>>::AudioBufferSumOfSquares( 378 aInput, aLength); 379 } else 380 # endif 381 { 382 return Engine<xsimd::sse2>::AudioBufferSumOfSquares(aInput, aLength); 383 } 384 } 385 #endif 386 387 float sum = 0.f; 388 while (aLength--) { 389 sum += *aInput * *aInput; 390 ++aInput; 391 } 392 return sum; 393 } 394 395 void NaNToZeroInPlace(float* aSamples, size_t aCount) { 396 #ifdef USE_SSE2 397 if (mozilla::supports_sse2()) { 398 Engine<xsimd::sse2>::NaNToZeroInPlace(aSamples, aCount); 399 return; 400 } 401 #endif 402 for (size_t i = 0; i < aCount; i++) { 403 if (aSamples[i] != aSamples[i]) { 404 aSamples[i] = 0.0; 405 } 406 } 407 } 408 409 AudioNodeEngine::AudioNodeEngine(dom::AudioNode* aNode) 410 : mNode(aNode), 411 mNodeType(aNode ? aNode->NodeType() : nullptr), 412 mInputCount(aNode ? aNode->NumberOfInputs() : 1), 413 mOutputCount(aNode ? aNode->NumberOfOutputs() : 0) { 414 MOZ_ASSERT(NS_IsMainThread()); 415 MOZ_COUNT_CTOR(AudioNodeEngine); 416 } 417 418 void AudioNodeEngine::ProcessBlock(AudioNodeTrack* aTrack, GraphTime aFrom, 419 const AudioBlock& aInput, 420 AudioBlock* aOutput, bool* aFinished) { 421 MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1); 422 TRACE("AudioNodeEngine::ProcessBlock"); 423 *aOutput = aInput; 424 } 425 426 void AudioNodeEngine::ProcessBlocksOnPorts(AudioNodeTrack* aTrack, 427 GraphTime aFrom, 428 Span<const AudioBlock> aInput, 429 Span<AudioBlock> aOutput, 430 bool* aFinished) { 431 MOZ_ASSERT(mInputCount > 1 || mOutputCount > 1); 432 TRACE("AudioNodeEngine::ProcessBlocksOnPorts"); 433 // Only produce one output port, and drop all other input ports. 434 aOutput[0] = aInput[0]; 435 } 436 437 } // namespace mozilla