1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webaudio/GainNode.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,165 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "GainNode.h" 1.11 +#include "mozilla/dom/GainNodeBinding.h" 1.12 +#include "AudioNodeEngine.h" 1.13 +#include "AudioNodeStream.h" 1.14 +#include "AudioDestinationNode.h" 1.15 +#include "WebAudioUtils.h" 1.16 + 1.17 +namespace mozilla { 1.18 +namespace dom { 1.19 + 1.20 +NS_IMPL_CYCLE_COLLECTION_INHERITED(GainNode, AudioNode, 1.21 + mGain) 1.22 + 1.23 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GainNode) 1.24 +NS_INTERFACE_MAP_END_INHERITING(AudioNode) 1.25 + 1.26 +NS_IMPL_ADDREF_INHERITED(GainNode, AudioNode) 1.27 +NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode) 1.28 + 1.29 +class GainNodeEngine : public AudioNodeEngine 1.30 +{ 1.31 +public: 1.32 + GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) 1.33 + : AudioNodeEngine(aNode) 1.34 + , mSource(nullptr) 1.35 + , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream())) 1.36 + // Keep the default value in sync with the default value in GainNode::GainNode. 1.37 + , mGain(1.f) 1.38 + { 1.39 + } 1.40 + 1.41 + void SetSourceStream(AudioNodeStream* aSource) 1.42 + { 1.43 + mSource = aSource; 1.44 + } 1.45 + 1.46 + enum Parameters { 1.47 + GAIN 1.48 + }; 1.49 + void SetTimelineParameter(uint32_t aIndex, 1.50 + const AudioParamTimeline& aValue, 1.51 + TrackRate aSampleRate) MOZ_OVERRIDE 1.52 + { 1.53 + switch (aIndex) { 1.54 + case GAIN: 1.55 + MOZ_ASSERT(mSource && mDestination); 1.56 + mGain = aValue; 1.57 + WebAudioUtils::ConvertAudioParamToTicks(mGain, mSource, mDestination); 1.58 + break; 1.59 + default: 1.60 + NS_ERROR("Bad GainNodeEngine TimelineParameter"); 1.61 + } 1.62 + } 1.63 + 1.64 + virtual void ProcessBlock(AudioNodeStream* aStream, 1.65 + const AudioChunk& aInput, 1.66 + AudioChunk* aOutput, 1.67 + bool* aFinished) 1.68 + { 1.69 + MOZ_ASSERT(mSource == aStream, "Invalid source stream"); 1.70 + 1.71 + if (aInput.IsNull()) { 1.72 + // If input is silent, so is the output 1.73 + aOutput->SetNull(WEBAUDIO_BLOCK_SIZE); 1.74 + } else if (mGain.HasSimpleValue()) { 1.75 + // Optimize the case where we only have a single value set as the volume 1.76 + float gain = mGain.GetValue(); 1.77 + if (gain == 0.0f) { 1.78 + aOutput->SetNull(WEBAUDIO_BLOCK_SIZE); 1.79 + } else { 1.80 + *aOutput = aInput; 1.81 + aOutput->mVolume *= gain; 1.82 + } 1.83 + } else { 1.84 + // First, compute a vector of gains for each track tick based on the 1.85 + // timeline at hand, and then for each channel, multiply the values 1.86 + // in the buffer with the gain vector. 1.87 + AllocateAudioBlock(aInput.mChannelData.Length(), aOutput); 1.88 + 1.89 + // Compute the gain values for the duration of the input AudioChunk 1.90 + // XXX we need to add a method to AudioEventTimeline to compute this buffer directly. 1.91 + float computedGain[WEBAUDIO_BLOCK_SIZE]; 1.92 + for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) { 1.93 + TrackTicks tick = aStream->GetCurrentPosition(); 1.94 + computedGain[counter] = mGain.GetValueAtTime(tick, counter) * aInput.mVolume; 1.95 + } 1.96 + 1.97 + // Apply the gain to the output buffer 1.98 + for (size_t channel = 0; channel < aOutput->mChannelData.Length(); ++channel) { 1.99 + const float* inputBuffer = static_cast<const float*> (aInput.mChannelData[channel]); 1.100 + float* buffer = static_cast<float*> (const_cast<void*> 1.101 + (aOutput->mChannelData[channel])); 1.102 + AudioBlockCopyChannelWithScale(inputBuffer, computedGain, buffer); 1.103 + } 1.104 + } 1.105 + } 1.106 + 1.107 + virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE 1.108 + { 1.109 + // Not owned: 1.110 + // - mSource (probably) 1.111 + // - mDestination (probably) 1.112 + // - mGain - Internal ref owned by AudioNode 1.113 + return AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf); 1.114 + } 1.115 + 1.116 + virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE 1.117 + { 1.118 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.119 + } 1.120 + 1.121 + AudioNodeStream* mSource; 1.122 + AudioNodeStream* mDestination; 1.123 + AudioParamTimeline mGain; 1.124 +}; 1.125 + 1.126 +GainNode::GainNode(AudioContext* aContext) 1.127 + : AudioNode(aContext, 1.128 + 2, 1.129 + ChannelCountMode::Max, 1.130 + ChannelInterpretation::Speakers) 1.131 + , mGain(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(), 1.132 + SendGainToStream, 1.0f)) 1.133 +{ 1.134 + GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination()); 1.135 + mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); 1.136 + engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get())); 1.137 +} 1.138 + 1.139 +size_t 1.140 +GainNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.141 +{ 1.142 + size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf); 1.143 + amount += mGain->SizeOfIncludingThis(aMallocSizeOf); 1.144 + return amount; 1.145 +} 1.146 + 1.147 +size_t 1.148 +GainNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const 1.149 +{ 1.150 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.151 +} 1.152 + 1.153 +JSObject* 1.154 +GainNode::WrapObject(JSContext* aCx) 1.155 +{ 1.156 + return GainNodeBinding::Wrap(aCx, this); 1.157 +} 1.158 + 1.159 +void 1.160 +GainNode::SendGainToStream(AudioNode* aNode) 1.161 +{ 1.162 + GainNode* This = static_cast<GainNode*>(aNode); 1.163 + SendTimelineParameterToStream(This, GainNodeEngine::GAIN, *This->mGain); 1.164 +} 1.165 + 1.166 +} 1.167 +} 1.168 +