PeriodicWave.cpp (4307B)
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 "PeriodicWave.h" 8 9 #include "AudioContext.h" 10 #include "mozilla/dom/PeriodicWaveBinding.h" 11 12 namespace mozilla::dom { 13 14 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PeriodicWave, mContext) 15 16 PeriodicWave::PeriodicWave(AudioContext* aContext, const float* aRealData, 17 const uint32_t aRealSize, const float* aImagData, 18 const uint32_t aImagSize, 19 const bool aDisableNormalization, ErrorResult& aRv) 20 : mContext(aContext), mDisableNormalization(aDisableNormalization) { 21 if (aRealData && aImagData && aRealSize != aImagSize) { 22 aRv.ThrowIndexSizeError("\"real\" and \"imag\" are different in length"); 23 return; 24 } 25 26 uint32_t length = 0; 27 if (aRealData) { 28 length = aRealSize; 29 } else if (aImagData) { 30 length = aImagSize; 31 } else { 32 // If nothing has been passed, this PeriodicWave will be a sine wave: 2 33 // elements for each array, the second imaginary component set to 1.0. 34 length = 2; 35 } 36 37 if (length < 2) { 38 aRv.ThrowIndexSizeError( 39 "\"real\" and \"imag\" must have a length of " 40 "at least 2"); 41 return; 42 } 43 44 MOZ_ASSERT(aContext); 45 MOZ_ASSERT((aRealData || aImagData) || length == 2); 46 47 // Caller should have checked this and thrown. 48 MOZ_ASSERT(length >= 2); 49 mCoefficients.mDuration = length; 50 51 // Copy coefficient data. 52 // The SharedBuffer and two arrays share a single allocation. 53 CheckedInt<size_t> bufferSize(sizeof(float)); 54 bufferSize *= length; 55 bufferSize *= 2; 56 RefPtr<SharedBuffer> buffer = SharedBuffer::Create(bufferSize, fallible); 57 if (!buffer) { 58 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 59 return; 60 } 61 62 auto data = static_cast<float*>(buffer->Data()); 63 mCoefficients.mBuffer = std::move(buffer); 64 65 if (!aRealData && !aImagData) { 66 PodZero(data, length); 67 mCoefficients.mChannelData.AppendElement(data); 68 data += length; 69 data[0] = 0.0f; 70 data[1] = 1.0f; 71 mCoefficients.mChannelData.AppendElement(data); 72 } else { 73 if (aRealData) { 74 PodCopy(data, aRealData, length); 75 } else { 76 PodZero(data, length); 77 } 78 mCoefficients.mChannelData.AppendElement(data); 79 80 data += length; 81 if (aImagData) { 82 PodCopy(data, aImagData, length); 83 } else { 84 PodZero(data, length); 85 } 86 mCoefficients.mChannelData.AppendElement(data); 87 } 88 mCoefficients.mVolume = 1.0f; 89 mCoefficients.mBufferFormat = AUDIO_FORMAT_FLOAT32; 90 } 91 92 /* static */ 93 already_AddRefed<PeriodicWave> PeriodicWave::Constructor( 94 const GlobalObject& aGlobal, AudioContext& aAudioContext, 95 const PeriodicWaveOptions& aOptions, ErrorResult& aRv) { 96 const float* realData; 97 const float* imagData; 98 uint32_t realSize; 99 uint32_t imagSize; 100 101 if (aOptions.mReal.WasPassed()) { 102 realData = aOptions.mReal.Value().Elements(); 103 realSize = aOptions.mReal.Value().Length(); 104 } else { 105 realData = nullptr; 106 realSize = 0; 107 } 108 109 if (aOptions.mImag.WasPassed()) { 110 imagData = aOptions.mImag.Value().Elements(); 111 imagSize = aOptions.mImag.Value().Length(); 112 } else { 113 imagData = nullptr; 114 imagSize = 0; 115 } 116 117 RefPtr<PeriodicWave> wave = 118 new PeriodicWave(&aAudioContext, realData, realSize, imagData, imagSize, 119 aOptions.mDisableNormalization, aRv); 120 if (aRv.Failed()) { 121 return nullptr; 122 } 123 124 return wave.forget(); 125 } 126 127 size_t PeriodicWave::SizeOfExcludingThisIfNotShared( 128 MallocSizeOf aMallocSizeOf) const { 129 // Not owned: 130 // - mContext 131 size_t amount = 0; 132 amount += mCoefficients.SizeOfExcludingThisIfUnshared(aMallocSizeOf); 133 134 return amount; 135 } 136 137 size_t PeriodicWave::SizeOfIncludingThisIfNotShared( 138 MallocSizeOf aMallocSizeOf) const { 139 return aMallocSizeOf(this) + SizeOfExcludingThisIfNotShared(aMallocSizeOf); 140 } 141 142 JSObject* PeriodicWave::WrapObject(JSContext* aCx, 143 JS::Handle<JSObject*> aGivenProto) { 144 return PeriodicWave_Binding::Wrap(aCx, this, aGivenProto); 145 } 146 147 } // namespace mozilla::dom