content/media/webaudio/DynamicsCompressorNode.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/webaudio/DynamicsCompressorNode.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,286 @@
     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 "DynamicsCompressorNode.h"
    1.11 +#include "mozilla/dom/DynamicsCompressorNodeBinding.h"
    1.12 +#include "AudioNodeEngine.h"
    1.13 +#include "AudioNodeStream.h"
    1.14 +#include "AudioDestinationNode.h"
    1.15 +#include "WebAudioUtils.h"
    1.16 +#include "blink/DynamicsCompressor.h"
    1.17 +
    1.18 +using WebCore::DynamicsCompressor;
    1.19 +
    1.20 +namespace mozilla {
    1.21 +namespace dom {
    1.22 +
    1.23 +NS_IMPL_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode, AudioNode,
    1.24 +                                   mThreshold,
    1.25 +                                   mKnee,
    1.26 +                                   mRatio,
    1.27 +                                   mReduction,
    1.28 +                                   mAttack,
    1.29 +                                   mRelease)
    1.30 +
    1.31 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode)
    1.32 +NS_INTERFACE_MAP_END_INHERITING(AudioNode)
    1.33 +
    1.34 +NS_IMPL_ADDREF_INHERITED(DynamicsCompressorNode, AudioNode)
    1.35 +NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode)
    1.36 +
    1.37 +class DynamicsCompressorNodeEngine : public AudioNodeEngine
    1.38 +{
    1.39 +public:
    1.40 +  explicit DynamicsCompressorNodeEngine(AudioNode* aNode,
    1.41 +                                        AudioDestinationNode* aDestination)
    1.42 +    : AudioNodeEngine(aNode)
    1.43 +    , mSource(nullptr)
    1.44 +    , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
    1.45 +    // Keep the default value in sync with the default value in
    1.46 +    // DynamicsCompressorNode::DynamicsCompressorNode.
    1.47 +    , mThreshold(-24.f)
    1.48 +    , mKnee(30.f)
    1.49 +    , mRatio(12.f)
    1.50 +    , mAttack(0.003f)
    1.51 +    , mRelease(0.25f)
    1.52 +    , mCompressor(new DynamicsCompressor(mDestination->SampleRate(), 2))
    1.53 +  {
    1.54 +  }
    1.55 +
    1.56 +  void SetSourceStream(AudioNodeStream* aSource)
    1.57 +  {
    1.58 +    mSource = aSource;
    1.59 +  }
    1.60 +
    1.61 +  enum Parameters {
    1.62 +    THRESHOLD,
    1.63 +    KNEE,
    1.64 +    RATIO,
    1.65 +    ATTACK,
    1.66 +    RELEASE
    1.67 +  };
    1.68 +  void SetTimelineParameter(uint32_t aIndex,
    1.69 +                            const AudioParamTimeline& aValue,
    1.70 +                            TrackRate aSampleRate) MOZ_OVERRIDE
    1.71 +  {
    1.72 +    MOZ_ASSERT(mSource && mDestination);
    1.73 +    switch (aIndex) {
    1.74 +    case THRESHOLD:
    1.75 +      mThreshold = aValue;
    1.76 +      WebAudioUtils::ConvertAudioParamToTicks(mThreshold, mSource, mDestination);
    1.77 +      break;
    1.78 +    case KNEE:
    1.79 +      mKnee = aValue;
    1.80 +      WebAudioUtils::ConvertAudioParamToTicks(mKnee, mSource, mDestination);
    1.81 +      break;
    1.82 +    case RATIO:
    1.83 +      mRatio = aValue;
    1.84 +      WebAudioUtils::ConvertAudioParamToTicks(mRatio, mSource, mDestination);
    1.85 +      break;
    1.86 +    case ATTACK:
    1.87 +      mAttack = aValue;
    1.88 +      WebAudioUtils::ConvertAudioParamToTicks(mAttack, mSource, mDestination);
    1.89 +      break;
    1.90 +    case RELEASE:
    1.91 +      mRelease = aValue;
    1.92 +      WebAudioUtils::ConvertAudioParamToTicks(mRelease, mSource, mDestination);
    1.93 +      break;
    1.94 +    default:
    1.95 +      NS_ERROR("Bad DynamicsCompresssorNodeEngine TimelineParameter");
    1.96 +    }
    1.97 +  }
    1.98 +
    1.99 +  virtual void ProcessBlock(AudioNodeStream* aStream,
   1.100 +                            const AudioChunk& aInput,
   1.101 +                            AudioChunk* aOutput,
   1.102 +                            bool* aFinished) MOZ_OVERRIDE
   1.103 +  {
   1.104 +    if (aInput.IsNull()) {
   1.105 +      // Just output silence
   1.106 +      *aOutput = aInput;
   1.107 +      return;
   1.108 +    }
   1.109 +
   1.110 +    const uint32_t channelCount = aInput.mChannelData.Length();
   1.111 +    if (mCompressor->numberOfChannels() != channelCount) {
   1.112 +      // Create a new compressor object with a new channel count
   1.113 +      mCompressor = new WebCore::DynamicsCompressor(aStream->SampleRate(),
   1.114 +                                                    aInput.mChannelData.Length());
   1.115 +    }
   1.116 +
   1.117 +    TrackTicks pos = aStream->GetCurrentPosition();
   1.118 +    mCompressor->setParameterValue(DynamicsCompressor::ParamThreshold,
   1.119 +                                   mThreshold.GetValueAtTime(pos));
   1.120 +    mCompressor->setParameterValue(DynamicsCompressor::ParamKnee,
   1.121 +                                   mKnee.GetValueAtTime(pos));
   1.122 +    mCompressor->setParameterValue(DynamicsCompressor::ParamRatio,
   1.123 +                                   mRatio.GetValueAtTime(pos));
   1.124 +    mCompressor->setParameterValue(DynamicsCompressor::ParamAttack,
   1.125 +                                   mAttack.GetValueAtTime(pos));
   1.126 +    mCompressor->setParameterValue(DynamicsCompressor::ParamRelease,
   1.127 +                                   mRelease.GetValueAtTime(pos));
   1.128 +
   1.129 +    AllocateAudioBlock(channelCount, aOutput);
   1.130 +    mCompressor->process(&aInput, aOutput, aInput.GetDuration());
   1.131 +
   1.132 +    SendReductionParamToMainThread(aStream,
   1.133 +                                   mCompressor->parameterValue(DynamicsCompressor::ParamReduction));
   1.134 +  }
   1.135 +
   1.136 +  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   1.137 +  {
   1.138 +    // Not owned:
   1.139 +    // - mSource (probably)
   1.140 +    // - mDestination (probably)
   1.141 +    // - Don't count the AudioParamTimelines, their inner refs are owned by the
   1.142 +    // AudioNode.
   1.143 +    size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
   1.144 +    amount += mCompressor->sizeOfIncludingThis(aMallocSizeOf);
   1.145 +    return amount;
   1.146 +  }
   1.147 +
   1.148 +  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   1.149 +  {
   1.150 +    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   1.151 +  }
   1.152 +
   1.153 +private:
   1.154 +  void SendReductionParamToMainThread(AudioNodeStream* aStream, float aReduction)
   1.155 +  {
   1.156 +    MOZ_ASSERT(!NS_IsMainThread());
   1.157 +
   1.158 +    class Command : public nsRunnable
   1.159 +    {
   1.160 +    public:
   1.161 +      Command(AudioNodeStream* aStream, float aReduction)
   1.162 +        : mStream(aStream)
   1.163 +        , mReduction(aReduction)
   1.164 +      {
   1.165 +      }
   1.166 +
   1.167 +      NS_IMETHODIMP Run()
   1.168 +      {
   1.169 +        nsRefPtr<DynamicsCompressorNode> node;
   1.170 +        {
   1.171 +          // No need to keep holding the lock for the whole duration of this
   1.172 +          // function, since we're holding a strong reference to it, so if
   1.173 +          // we can obtain the reference, we will hold the node alive in
   1.174 +          // this function.
   1.175 +          MutexAutoLock lock(mStream->Engine()->NodeMutex());
   1.176 +          node = static_cast<DynamicsCompressorNode*>(mStream->Engine()->Node());
   1.177 +        }
   1.178 +        if (node) {
   1.179 +          AudioParam* reduction = node->Reduction();
   1.180 +          reduction->CancelAllEvents();
   1.181 +          reduction->SetValue(mReduction);
   1.182 +        }
   1.183 +        return NS_OK;
   1.184 +      }
   1.185 +
   1.186 +    private:
   1.187 +      nsRefPtr<AudioNodeStream> mStream;
   1.188 +      float mReduction;
   1.189 +    };
   1.190 +
   1.191 +    NS_DispatchToMainThread(new Command(aStream, aReduction));
   1.192 +  }
   1.193 +
   1.194 +private:
   1.195 +  AudioNodeStream* mSource;
   1.196 +  AudioNodeStream* mDestination;
   1.197 +  AudioParamTimeline mThreshold;
   1.198 +  AudioParamTimeline mKnee;
   1.199 +  AudioParamTimeline mRatio;
   1.200 +  AudioParamTimeline mAttack;
   1.201 +  AudioParamTimeline mRelease;
   1.202 +  nsAutoPtr<DynamicsCompressor> mCompressor;
   1.203 +};
   1.204 +
   1.205 +DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
   1.206 +  : AudioNode(aContext,
   1.207 +              2,
   1.208 +              ChannelCountMode::Explicit,
   1.209 +              ChannelInterpretation::Speakers)
   1.210 +  , mThreshold(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
   1.211 +                              SendThresholdToStream, -24.f))
   1.212 +  , mKnee(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
   1.213 +                         SendKneeToStream, 30.f))
   1.214 +  , mRatio(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
   1.215 +                          SendRatioToStream, 12.f))
   1.216 +  , mReduction(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
   1.217 +                              Callback, 0.f))
   1.218 +  , mAttack(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
   1.219 +                           SendAttackToStream, 0.003f))
   1.220 +  , mRelease(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
   1.221 +                            SendReleaseToStream, 0.25f))
   1.222 +{
   1.223 +  DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
   1.224 +  mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
   1.225 +  engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
   1.226 +}
   1.227 +
   1.228 +size_t
   1.229 +DynamicsCompressorNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   1.230 +{
   1.231 +  size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
   1.232 +  amount += mThreshold->SizeOfIncludingThis(aMallocSizeOf);
   1.233 +  amount += mKnee->SizeOfIncludingThis(aMallocSizeOf);
   1.234 +  amount += mRatio->SizeOfIncludingThis(aMallocSizeOf);
   1.235 +  amount += mAttack->SizeOfIncludingThis(aMallocSizeOf);
   1.236 +  amount += mRelease->SizeOfIncludingThis(aMallocSizeOf);
   1.237 +  return amount;
   1.238 +}
   1.239 +
   1.240 +size_t
   1.241 +DynamicsCompressorNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   1.242 +{
   1.243 +  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   1.244 +}
   1.245 +
   1.246 +JSObject*
   1.247 +DynamicsCompressorNode::WrapObject(JSContext* aCx)
   1.248 +{
   1.249 +  return DynamicsCompressorNodeBinding::Wrap(aCx, this);
   1.250 +}
   1.251 +
   1.252 +void
   1.253 +DynamicsCompressorNode::SendThresholdToStream(AudioNode* aNode)
   1.254 +{
   1.255 +  DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
   1.256 +  SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::THRESHOLD, *This->mThreshold);
   1.257 +}
   1.258 +
   1.259 +void
   1.260 +DynamicsCompressorNode::SendKneeToStream(AudioNode* aNode)
   1.261 +{
   1.262 +  DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
   1.263 +  SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::KNEE, *This->mKnee);
   1.264 +}
   1.265 +
   1.266 +void
   1.267 +DynamicsCompressorNode::SendRatioToStream(AudioNode* aNode)
   1.268 +{
   1.269 +  DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
   1.270 +  SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::RATIO, *This->mRatio);
   1.271 +}
   1.272 +
   1.273 +void
   1.274 +DynamicsCompressorNode::SendAttackToStream(AudioNode* aNode)
   1.275 +{
   1.276 +  DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
   1.277 +  SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::ATTACK, *This->mAttack);
   1.278 +}
   1.279 +
   1.280 +void
   1.281 +DynamicsCompressorNode::SendReleaseToStream(AudioNode* aNode)
   1.282 +{
   1.283 +  DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
   1.284 +  SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::RELEASE, *This->mRelease);
   1.285 +}
   1.286 +
   1.287 +}
   1.288 +}
   1.289 +

mercurial