tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GainNode.cpp (5376B)


      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 "GainNode.h"
      8 
      9 #include "AlignmentUtils.h"
     10 #include "AudioDestinationNode.h"
     11 #include "AudioNodeEngine.h"
     12 #include "AudioNodeTrack.h"
     13 #include "Tracing.h"
     14 #include "WebAudioUtils.h"
     15 #include "mozilla/dom/GainNodeBinding.h"
     16 
     17 namespace mozilla::dom {
     18 
     19 NS_IMPL_CYCLE_COLLECTION_INHERITED(GainNode, AudioNode, mGain)
     20 
     21 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GainNode)
     22 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
     23 
     24 NS_IMPL_ADDREF_INHERITED(GainNode, AudioNode)
     25 NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode)
     26 
     27 class GainNodeEngine final : public AudioNodeEngine {
     28 public:
     29  GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
     30      : AudioNodeEngine(aNode),
     31        mDestination(aDestination->Track())
     32        // Keep the default value in sync with the default value in
     33        // GainNode::GainNode.
     34        ,
     35        mGain(1.f) {}
     36 
     37  enum Parameters { GAIN };
     38  void RecvTimelineEvent(uint32_t aIndex, AudioParamEvent& aEvent) override {
     39    MOZ_ASSERT(mDestination);
     40    aEvent.ConvertToTicks(mDestination);
     41 
     42    switch (aIndex) {
     43      case GAIN:
     44        mGain.InsertEvent<int64_t>(aEvent);
     45        break;
     46      default:
     47        NS_ERROR("Bad GainNodeEngine TimelineParameter");
     48    }
     49  }
     50 
     51  void ProcessBlock(AudioNodeTrack* aTrack, GraphTime aFrom,
     52                    const AudioBlock& aInput, AudioBlock* aOutput,
     53                    bool* aFinished) override {
     54    TRACE("GainNodeEngine::ProcessBlock");
     55    if (aInput.IsNull()) {
     56      // If input is silent, so is the output
     57      aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     58    } else if (mGain.HasSimpleValue()) {
     59      // Optimize the case where we only have a single value set as the volume
     60      float gain = mGain.GetValue();
     61      if (gain == 0.0f) {
     62        aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     63      } else {
     64        *aOutput = aInput;
     65        aOutput->mVolume *= gain;
     66      }
     67    } else {
     68      // First, compute a vector of gains for each track tick based on the
     69      // timeline at hand, and then for each channel, multiply the values
     70      // in the buffer with the gain vector.
     71      aOutput->AllocateChannels(aInput.ChannelCount());
     72 
     73      // Compute the gain values for the duration of the input AudioChunk
     74      TrackTime tick = mDestination->GraphTimeToTrackTime(aFrom);
     75      float computedGain[WEBAUDIO_BLOCK_SIZE + 4];
     76      float* alignedComputedGain = ALIGNED16(computedGain);
     77      ASSERT_ALIGNED16(alignedComputedGain);
     78      mGain.GetValuesAtTime(tick, alignedComputedGain, WEBAUDIO_BLOCK_SIZE);
     79 
     80      for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
     81        alignedComputedGain[counter] *= aInput.mVolume;
     82      }
     83 
     84      // Apply the gain to the output buffer
     85      for (size_t channel = 0; channel < aOutput->ChannelCount(); ++channel) {
     86        const float* inputBuffer =
     87            static_cast<const float*>(aInput.mChannelData[channel]);
     88        float* buffer = aOutput->ChannelFloatsForWrite(channel);
     89        AudioBlockCopyChannelWithScale(inputBuffer, alignedComputedGain,
     90                                       buffer);
     91      }
     92    }
     93  }
     94 
     95  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
     96    // Not owned:
     97    // - mDestination - MediaTrackGraphImpl::CollectSizesForMemoryReport()
     98    // accounts for mDestination.
     99    // - mGain - Internal ref owned by AudioNode
    100    return AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
    101  }
    102 
    103  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
    104    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    105  }
    106 
    107  RefPtr<AudioNodeTrack> mDestination;
    108  AudioParamTimeline mGain;
    109 };
    110 
    111 GainNode::GainNode(AudioContext* aContext)
    112    : AudioNode(aContext, 2, ChannelCountMode::Max,
    113                ChannelInterpretation::Speakers) {
    114  mGain = CreateAudioParam(GainNodeEngine::GAIN, u"gain"_ns, 1.0f);
    115  GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
    116  mTrack = AudioNodeTrack::Create(
    117      aContext, engine, AudioNodeTrack::NO_TRACK_FLAGS, aContext->Graph());
    118 }
    119 
    120 /* static */
    121 already_AddRefed<GainNode> GainNode::Create(AudioContext& aAudioContext,
    122                                            const GainOptions& aOptions,
    123                                            ErrorResult& aRv) {
    124  RefPtr<GainNode> audioNode = new GainNode(&aAudioContext);
    125 
    126  audioNode->Initialize(aOptions, aRv);
    127  if (NS_WARN_IF(aRv.Failed())) {
    128    return nullptr;
    129  }
    130 
    131  audioNode->Gain()->SetInitialValue(aOptions.mGain);
    132  return audioNode.forget();
    133 }
    134 
    135 size_t GainNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    136  size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
    137  amount += mGain->SizeOfIncludingThis(aMallocSizeOf);
    138  return amount;
    139 }
    140 
    141 size_t GainNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    142  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    143 }
    144 
    145 JSObject* GainNode::WrapObject(JSContext* aCx,
    146                               JS::Handle<JSObject*> aGivenProto) {
    147  return GainNode_Binding::Wrap(aCx, this, aGivenProto);
    148 }
    149 
    150 }  // namespace mozilla::dom