michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef DelayBuffer_h_ michael@0: #define DelayBuffer_h_ michael@0: michael@0: #include "nsTArray.h" michael@0: #include "AudioSegment.h" michael@0: #include "mozilla/dom/AudioNodeBinding.h" // for ChannelInterpretation michael@0: michael@0: namespace mozilla { michael@0: michael@0: class DelayBuffer { michael@0: typedef dom::ChannelInterpretation ChannelInterpretation; michael@0: michael@0: public: michael@0: // See WebAudioUtils::ComputeSmoothingRate() for frame to frame exponential michael@0: // |smoothingRate| multiplier. michael@0: DelayBuffer(double aMaxDelayTicks, double aSmoothingRate) michael@0: : mSmoothingRate(aSmoothingRate) michael@0: , mCurrentDelay(-1.0) michael@0: // Round the maximum delay up to the next tick. michael@0: , mMaxDelayTicks(ceil(aMaxDelayTicks)) michael@0: , mCurrentChunk(0) michael@0: // mLastReadChunk is initialized in EnsureBuffer michael@0: #ifdef DEBUG michael@0: , mHaveWrittenBlock(false) michael@0: #endif michael@0: { michael@0: // The 180 second limit in AudioContext::CreateDelay() and the michael@0: // 1 << MEDIA_TIME_FRAC_BITS limit on sample rate provide a limit on the michael@0: // maximum delay. michael@0: MOZ_ASSERT(aMaxDelayTicks <= michael@0: std::numeric_limits::max()); michael@0: } michael@0: michael@0: // Write a WEBAUDIO_BLOCK_SIZE block for aChannelCount channels. michael@0: void Write(const AudioChunk& aInputChunk); michael@0: michael@0: // Read a block with an array of delays, in ticks, for each sample frame. michael@0: // Each delay should be >= 0 and <= MaxDelayTicks(). michael@0: void Read(const double aPerFrameDelays[WEBAUDIO_BLOCK_SIZE], michael@0: AudioChunk* aOutputChunk, michael@0: ChannelInterpretation aChannelInterpretation); michael@0: // Read a block with a constant delay, which will be smoothed with the michael@0: // previous delay. The delay should be >= 0 and <= MaxDelayTicks(). michael@0: void Read(double aDelayTicks, AudioChunk* aOutputChunk, michael@0: ChannelInterpretation aChannelInterpretation); michael@0: michael@0: // Read into one of the channels of aOutputChunk, given an array of michael@0: // delays in ticks. This is useful when delays are different on different michael@0: // channels. aOutputChunk must have already been allocated with at least as michael@0: // many channels as were in any of the blocks passed to Write(). michael@0: void ReadChannel(const double aPerFrameDelays[WEBAUDIO_BLOCK_SIZE], michael@0: const AudioChunk* aOutputChunk, uint32_t aChannel, michael@0: ChannelInterpretation aChannelInterpretation); michael@0: michael@0: // Advance the buffer pointer michael@0: void NextBlock() michael@0: { michael@0: mCurrentChunk = (mCurrentChunk + 1) % mChunks.Length(); michael@0: #ifdef DEBUG michael@0: MOZ_ASSERT(mHaveWrittenBlock); michael@0: mHaveWrittenBlock = false; michael@0: #endif michael@0: } michael@0: michael@0: void Reset() { michael@0: mChunks.Clear(); michael@0: mCurrentDelay = -1.0; michael@0: }; michael@0: michael@0: int MaxDelayTicks() const { return mMaxDelayTicks; } michael@0: michael@0: size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: void ReadChannels(const double aPerFrameDelays[WEBAUDIO_BLOCK_SIZE], michael@0: const AudioChunk* aOutputChunk, michael@0: uint32_t aFirstChannel, uint32_t aNumChannelsToRead, michael@0: ChannelInterpretation aChannelInterpretation); michael@0: bool EnsureBuffer(); michael@0: int PositionForDelay(int aDelay); michael@0: int ChunkForPosition(int aPosition); michael@0: int OffsetForPosition(int aPosition); michael@0: int ChunkForDelay(int aDelay); michael@0: void UpdateUpmixChannels(int aNewReadChunk, uint32_t channelCount, michael@0: ChannelInterpretation aChannelInterpretation); michael@0: michael@0: // Circular buffer for capturing delayed samples. michael@0: FallibleTArray mChunks; michael@0: // Cache upmixed channel arrays. michael@0: nsAutoTArray mUpmixChannels; michael@0: double mSmoothingRate; michael@0: // Current delay, in fractional ticks michael@0: double mCurrentDelay; michael@0: // Maximum delay, in ticks michael@0: int mMaxDelayTicks; michael@0: // The current position in the circular buffer. The next write will be to michael@0: // this chunk, and the next read may begin before this chunk. michael@0: int mCurrentChunk; michael@0: // The chunk owning the pointers in mUpmixChannels michael@0: int mLastReadChunk; michael@0: #ifdef DEBUG michael@0: bool mHaveWrittenBlock; michael@0: #endif michael@0: }; michael@0: michael@0: } // mozilla michael@0: michael@0: #endif // DelayBuffer_h_