summaryrefslogtreecommitdiffstats
path: root/dom/media/webaudio/GainNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webaudio/GainNode.cpp')
-rw-r--r--dom/media/webaudio/GainNode.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/dom/media/webaudio/GainNode.cpp b/dom/media/webaudio/GainNode.cpp
new file mode 100644
index 000000000..46ac99763
--- /dev/null
+++ b/dom/media/webaudio/GainNode.cpp
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GainNode.h"
+#include "mozilla/dom/GainNodeBinding.h"
+#include "AlignmentUtils.h"
+#include "AudioNodeEngine.h"
+#include "AudioNodeStream.h"
+#include "AudioDestinationNode.h"
+#include "WebAudioUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(GainNode, AudioNode,
+ mGain)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GainNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+
+NS_IMPL_ADDREF_INHERITED(GainNode, AudioNode)
+NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode)
+
+class GainNodeEngine final : public AudioNodeEngine
+{
+public:
+ GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
+ : AudioNodeEngine(aNode)
+ , mDestination(aDestination->Stream())
+ // Keep the default value in sync with the default value in GainNode::GainNode.
+ , mGain(1.f)
+ {
+ }
+
+ enum Parameters {
+ GAIN
+ };
+ void RecvTimelineEvent(uint32_t aIndex,
+ AudioTimelineEvent& aEvent) override
+ {
+ MOZ_ASSERT(mDestination);
+ WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
+ mDestination);
+
+ switch (aIndex) {
+ case GAIN:
+ mGain.InsertEvent<int64_t>(aEvent);
+ break;
+ default:
+ NS_ERROR("Bad GainNodeEngine TimelineParameter");
+ }
+ }
+
+ void ProcessBlock(AudioNodeStream* aStream,
+ GraphTime aFrom,
+ const AudioBlock& aInput,
+ AudioBlock* aOutput,
+ bool* aFinished) override
+ {
+ if (aInput.IsNull()) {
+ // If input is silent, so is the output
+ aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
+ } else if (mGain.HasSimpleValue()) {
+ // Optimize the case where we only have a single value set as the volume
+ float gain = mGain.GetValue();
+ if (gain == 0.0f) {
+ aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
+ } else {
+ *aOutput = aInput;
+ aOutput->mVolume *= gain;
+ }
+ } else {
+ // First, compute a vector of gains for each track tick based on the
+ // timeline at hand, and then for each channel, multiply the values
+ // in the buffer with the gain vector.
+ aOutput->AllocateChannels(aInput.ChannelCount());
+
+ // Compute the gain values for the duration of the input AudioChunk
+ StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
+ float computedGain[WEBAUDIO_BLOCK_SIZE + 4];
+ float* alignedComputedGain = ALIGNED16(computedGain);
+ ASSERT_ALIGNED16(alignedComputedGain);
+ mGain.GetValuesAtTime(tick, alignedComputedGain, WEBAUDIO_BLOCK_SIZE);
+
+ for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
+ alignedComputedGain[counter] *= aInput.mVolume;
+ }
+
+ // Apply the gain to the output buffer
+ for (size_t channel = 0; channel < aOutput->ChannelCount(); ++channel) {
+ const float* inputBuffer = static_cast<const float*> (aInput.mChannelData[channel]);
+ float* buffer = aOutput->ChannelFloatsForWrite(channel);
+ AudioBlockCopyChannelWithScale(inputBuffer, alignedComputedGain, buffer);
+ }
+ }
+ }
+
+ size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
+ {
+ // Not owned:
+ // - mDestination (probably)
+ // - mGain - Internal ref owned by AudioNode
+ return AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
+ }
+
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
+ {
+ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+ }
+
+ AudioNodeStream* mDestination;
+ AudioParamTimeline mGain;
+};
+
+GainNode::GainNode(AudioContext* aContext)
+ : AudioNode(aContext,
+ 2,
+ ChannelCountMode::Max,
+ ChannelInterpretation::Speakers)
+ , mGain(new AudioParam(this, GainNodeEngine::GAIN, 1.0f, "gain"))
+{
+ GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
+ mStream = AudioNodeStream::Create(aContext, engine,
+ AudioNodeStream::NO_STREAM_FLAGS,
+ aContext->Graph());
+}
+
+GainNode::~GainNode()
+{
+}
+
+size_t
+GainNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+ size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
+ amount += mGain->SizeOfIncludingThis(aMallocSizeOf);
+ return amount;
+}
+
+size_t
+GainNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+}
+
+JSObject*
+GainNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return GainNodeBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla