Exemple #1
0
void
PannerNodeEngine::EqualPowerPanningFunction(const AudioBlock& aInput,
        AudioBlock* aOutput)
{
    float azimuth, elevation, gainL, gainR, normalizedAzimuth, distanceGain, coneGain;
    int inputChannels = aInput.ChannelCount();

    // If both the listener are in the same spot, and no cone gain is specified,
    // this node is noop.
    if (mListenerPosition == mPosition &&
            mConeInnerAngle == 360 &&
            mConeOuterAngle == 360) {
        *aOutput = aInput;
        return;
    }

    // The output of this node is always stereo, no matter what the inputs are.
    aOutput->AllocateChannels(2);

    ComputeAzimuthAndElevation(azimuth, elevation);
    coneGain = ComputeConeGain();

    // The following algorithm is described in the spec.
    // Clamp azimuth in the [-90, 90] range.
    azimuth = min(180.f, max(-180.f, azimuth));

    // Wrap around
    if (azimuth < -90.f) {
        azimuth = -180.f - azimuth;
    } else if (azimuth > 90) {
        azimuth = 180.f - azimuth;
    }

    // Normalize the value in the [0, 1] range.
    if (inputChannels == 1) {
        normalizedAzimuth = (azimuth + 90.f) / 180.f;
    } else {
        if (azimuth <= 0) {
            normalizedAzimuth = (azimuth + 90.f) / 90.f;
        } else {
            normalizedAzimuth = azimuth / 90.f;
        }
    }

    distanceGain = ComputeDistanceGain();

    // Actually compute the left and right gain.
    gainL = cos(0.5 * M_PI * normalizedAzimuth);
    gainR = sin(0.5 * M_PI * normalizedAzimuth);

    // Compute the output.
    ApplyStereoPanning(aInput, aOutput, gainL, gainR, azimuth <= 0);

    aOutput->mVolume = aInput.mVolume * distanceGain * coneGain;
}
  void ProcessBlock(AudioNodeStream* aStream,
                    GraphTime aFrom,
                    const AudioBlock& aInput,
                    AudioBlock* aOutput,
                    bool* aFinished) override
  {
    // This node is not connected to anything. Per spec, we don't fire the
    // onaudioprocess event. We also want to clear out the input and output
    // buffer queue, and output a null buffer.
    if (!mIsConnected) {
      aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
      mSharedBuffers->Reset();
      mInputWriteIndex = 0;
      return;
    }

    // The input buffer is allocated lazily when non-null input is received.
    if (!aInput.IsNull() && !mInputBuffer) {
      mInputBuffer = ThreadSharedFloatArrayBufferList::
        Create(mInputChannelCount, mBufferSize, fallible);
      if (mInputBuffer && mInputWriteIndex) {
        // Zero leading for null chunks that were skipped.
        for (uint32_t i = 0; i < mInputChannelCount; ++i) {
          float* channelData = mInputBuffer->GetDataForWrite(i);
          PodZero(channelData, mInputWriteIndex);
        }
      }
    }

    // First, record our input buffer, if its allocation succeeded.
    uint32_t inputChannelCount = mInputBuffer ? mInputBuffer->GetChannels() : 0;
    for (uint32_t i = 0; i < inputChannelCount; ++i) {
      float* writeData = mInputBuffer->GetDataForWrite(i) + mInputWriteIndex;
      if (aInput.IsNull()) {
        PodZero(writeData, aInput.GetDuration());
      } else {
        MOZ_ASSERT(aInput.GetDuration() == WEBAUDIO_BLOCK_SIZE, "sanity check");
        MOZ_ASSERT(aInput.ChannelCount() == inputChannelCount);
        AudioBlockCopyChannelWithScale(static_cast<const float*>(aInput.mChannelData[i]),
                                       aInput.mVolume, writeData);
      }
    }
    mInputWriteIndex += aInput.GetDuration();

    // Now, see if we have data to output
    // Note that we need to do this before sending the buffer to the main
    // thread so that our delay time is updated.
    *aOutput = mSharedBuffers->GetOutputBuffer();

    if (mInputWriteIndex >= mBufferSize) {
      SendBuffersToMainThread(aStream, aFrom);
      mInputWriteIndex -= mBufferSize;
    }
  }
void
DelayBuffer::Write(const AudioBlock& aInputChunk)
{
  // We must have a reference to the buffer if there are channels
  MOZ_ASSERT(aInputChunk.IsNull() == !aInputChunk.ChannelCount());
#ifdef DEBUG
  MOZ_ASSERT(!mHaveWrittenBlock);
  mHaveWrittenBlock = true;
#endif

  if (!EnsureBuffer()) {
    return;
  }

  if (mCurrentChunk == mLastReadChunk) {
    mLastReadChunk = -1; // invalidate cache
  }
  mChunks[mCurrentChunk] = aInputChunk.AsAudioChunk();
}
Exemple #4
0
void
PannerNodeEngine::EqualPowerPanningFunction(const AudioBlock& aInput,
                                            AudioBlock* aOutput,
                                            StreamTime tick)
{
  float azimuth, elevation, gainL, gainR, normalizedAzimuth, distanceGain, coneGain;
  int inputChannels = aInput.ChannelCount();

  // Optimize the case where the position and orientation is constant for this
  // processing block: we can just apply a constant gain on the left and right
  // channel
  if (mPositionX.HasSimpleValue() &&
      mPositionY.HasSimpleValue() &&
      mPositionZ.HasSimpleValue() &&
      mOrientationX.HasSimpleValue() &&
      mOrientationY.HasSimpleValue() &&
      mOrientationZ.HasSimpleValue()) {

    ThreeDPoint position = ConvertAudioParamTimelineTo3DP(mPositionX, mPositionY, mPositionZ, tick);
    ThreeDPoint orientation = ConvertAudioParamTimelineTo3DP(mOrientationX, mOrientationY, mOrientationZ, tick);
    if (!orientation.IsZero()) {
      orientation.Normalize();
    }

    // If both the listener are in the same spot, and no cone gain is specified,
    // this node is noop.
    if (mListenerPosition ==  position &&
        mConeInnerAngle == 360 &&
        mConeOuterAngle == 360) {
      *aOutput = aInput;
      return;
    }

    // The output of this node is always stereo, no matter what the inputs are.
    aOutput->AllocateChannels(2);

    ComputeAzimuthAndElevation(position, azimuth, elevation);
    coneGain = ComputeConeGain(position, orientation);

    // The following algorithm is described in the spec.
    // Clamp azimuth in the [-90, 90] range.
    azimuth = min(180.f, max(-180.f, azimuth));

    // Wrap around
    if (azimuth < -90.f) {
      azimuth = -180.f - azimuth;
    } else if (azimuth > 90) {
      azimuth = 180.f - azimuth;
    }

    // Normalize the value in the [0, 1] range.
    if (inputChannels == 1) {
      normalizedAzimuth = (azimuth + 90.f) / 180.f;
    } else {
      if (azimuth <= 0) {
        normalizedAzimuth = (azimuth + 90.f) / 90.f;
      } else {
        normalizedAzimuth = azimuth / 90.f;
      }
    }

    distanceGain = ComputeDistanceGain(position);

    // Actually compute the left and right gain.
    gainL = cos(0.5 * M_PI * normalizedAzimuth);
    gainR = sin(0.5 * M_PI * normalizedAzimuth);

    // Compute the output.
    ApplyStereoPanning(aInput, aOutput, gainL, gainR, azimuth <= 0);

    aOutput->mVolume = aInput.mVolume * distanceGain * coneGain;
  } else {
    float positionX[WEBAUDIO_BLOCK_SIZE];
    float positionY[WEBAUDIO_BLOCK_SIZE];
    float positionZ[WEBAUDIO_BLOCK_SIZE];
    float orientationX[WEBAUDIO_BLOCK_SIZE];
    float orientationY[WEBAUDIO_BLOCK_SIZE];
    float orientationZ[WEBAUDIO_BLOCK_SIZE];

    // The output of this node is always stereo, no matter what the inputs are.
    aOutput->AllocateChannels(2);

    if (!mPositionX.HasSimpleValue()) {
      mPositionX.GetValuesAtTime(tick, positionX, WEBAUDIO_BLOCK_SIZE);
    } else {
      positionX[0] = mPositionX.GetValueAtTime(tick);
    }
    if (!mPositionY.HasSimpleValue()) {
      mPositionY.GetValuesAtTime(tick, positionY, WEBAUDIO_BLOCK_SIZE);
    } else {
      positionY[0] = mPositionY.GetValueAtTime(tick);
    }
    if (!mPositionZ.HasSimpleValue()) {
      mPositionZ.GetValuesAtTime(tick, positionZ, WEBAUDIO_BLOCK_SIZE);
    } else {
      positionZ[0] = mPositionZ.GetValueAtTime(tick);
    }
    if (!mOrientationX.HasSimpleValue()) {
      mOrientationX.GetValuesAtTime(tick, orientationX, WEBAUDIO_BLOCK_SIZE);
    } else {
      orientationX[0] = mOrientationX.GetValueAtTime(tick);
    }
    if (!mOrientationY.HasSimpleValue()) {
      mOrientationY.GetValuesAtTime(tick, orientationY, WEBAUDIO_BLOCK_SIZE);
    } else {
      orientationY[0] = mOrientationY.GetValueAtTime(tick);
    }
    if (!mOrientationZ.HasSimpleValue()) {
      mOrientationZ.GetValuesAtTime(tick, orientationZ, WEBAUDIO_BLOCK_SIZE);
    } else {
      orientationZ[0] = mOrientationZ.GetValueAtTime(tick);
    }

    float computedGain[2*WEBAUDIO_BLOCK_SIZE + 4];
    bool onLeft[WEBAUDIO_BLOCK_SIZE];

    float* alignedComputedGain = ALIGNED16(computedGain);
    ASSERT_ALIGNED16(alignedComputedGain);
    for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
      ThreeDPoint position(mPositionX.HasSimpleValue() ? positionX[0] : positionX[counter],
                           mPositionY.HasSimpleValue() ? positionY[0] : positionY[counter],
                           mPositionZ.HasSimpleValue() ? positionZ[0] : positionZ[counter]);
      ThreeDPoint orientation(mOrientationX.HasSimpleValue() ? orientationX[0] : orientationX[counter],
                              mOrientationY.HasSimpleValue() ? orientationY[0] : orientationY[counter],
                              mOrientationZ.HasSimpleValue() ? orientationZ[0] : orientationZ[counter]);
      if (!orientation.IsZero()) {
        orientation.Normalize();
      }

      ComputeAzimuthAndElevation(position, azimuth, elevation);
      coneGain = ComputeConeGain(position, orientation);

      // The following algorithm is described in the spec.
      // Clamp azimuth in the [-90, 90] range.
      azimuth = min(180.f, max(-180.f, azimuth));

      // Wrap around
      if (azimuth < -90.f) {
        azimuth = -180.f - azimuth;
      } else if (azimuth > 90) {
        azimuth = 180.f - azimuth;
      }

      // Normalize the value in the [0, 1] range.
      if (inputChannels == 1) {
        normalizedAzimuth = (azimuth + 90.f) / 180.f;
      } else {
        if (azimuth <= 0) {
          normalizedAzimuth = (azimuth + 90.f) / 90.f;
        } else {
          normalizedAzimuth = azimuth / 90.f;
        }
      }

      distanceGain = ComputeDistanceGain(position);

      // Actually compute the left and right gain.
      float gainL = cos(0.5 * M_PI * normalizedAzimuth) * aInput.mVolume * distanceGain * coneGain;
      float gainR = sin(0.5 * M_PI * normalizedAzimuth) * aInput.mVolume * distanceGain * coneGain;

      alignedComputedGain[counter] = gainL;
      alignedComputedGain[WEBAUDIO_BLOCK_SIZE + counter] = gainR;
      onLeft[counter] = azimuth <= 0;
    }

    // Apply the gain to the output buffer
    ApplyStereoPanning(aInput, aOutput, alignedComputedGain, &alignedComputedGain[WEBAUDIO_BLOCK_SIZE], onLeft);

  }
}