|  | /* | 
|  | *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "webrtc/common_audio/lapped_transform.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <cstdlib> | 
|  | #include <cstring> | 
|  |  | 
|  | #include "webrtc/base/checks.h" | 
|  | #include "webrtc/common_audio/real_fourier.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | void LappedTransform::BlockThunk::ProcessBlock(const float* const* input, | 
|  | size_t num_frames, | 
|  | size_t num_input_channels, | 
|  | size_t num_output_channels, | 
|  | float* const* output) { | 
|  | RTC_CHECK_EQ(num_input_channels, parent_->num_in_channels_); | 
|  | RTC_CHECK_EQ(num_output_channels, parent_->num_out_channels_); | 
|  | RTC_CHECK_EQ(parent_->block_length_, num_frames); | 
|  |  | 
|  | for (size_t i = 0; i < num_input_channels; ++i) { | 
|  | memcpy(parent_->real_buf_.Row(i), input[i], | 
|  | num_frames * sizeof(*input[0])); | 
|  | parent_->fft_->Forward(parent_->real_buf_.Row(i), | 
|  | parent_->cplx_pre_.Row(i)); | 
|  | } | 
|  |  | 
|  | size_t block_length = RealFourier::ComplexLength( | 
|  | RealFourier::FftOrder(num_frames)); | 
|  | RTC_CHECK_EQ(parent_->cplx_length_, block_length); | 
|  | parent_->block_processor_->ProcessAudioBlock(parent_->cplx_pre_.Array(), | 
|  | num_input_channels, | 
|  | parent_->cplx_length_, | 
|  | num_output_channels, | 
|  | parent_->cplx_post_.Array()); | 
|  |  | 
|  | for (size_t i = 0; i < num_output_channels; ++i) { | 
|  | parent_->fft_->Inverse(parent_->cplx_post_.Row(i), | 
|  | parent_->real_buf_.Row(i)); | 
|  | memcpy(output[i], parent_->real_buf_.Row(i), | 
|  | num_frames * sizeof(*input[0])); | 
|  | } | 
|  | } | 
|  |  | 
|  | LappedTransform::LappedTransform(size_t num_in_channels, | 
|  | size_t num_out_channels, | 
|  | size_t chunk_length, | 
|  | const float* window, | 
|  | size_t block_length, | 
|  | size_t shift_amount, | 
|  | Callback* callback) | 
|  | : blocker_callback_(this), | 
|  | num_in_channels_(num_in_channels), | 
|  | num_out_channels_(num_out_channels), | 
|  | block_length_(block_length), | 
|  | chunk_length_(chunk_length), | 
|  | block_processor_(callback), | 
|  | blocker_(chunk_length_, | 
|  | block_length_, | 
|  | num_in_channels_, | 
|  | num_out_channels_, | 
|  | window, | 
|  | shift_amount, | 
|  | &blocker_callback_), | 
|  | fft_(RealFourier::Create(RealFourier::FftOrder(block_length_))), | 
|  | cplx_length_(RealFourier::ComplexLength(fft_->order())), | 
|  | real_buf_(num_in_channels, | 
|  | block_length_, | 
|  | RealFourier::kFftBufferAlignment), | 
|  | cplx_pre_(num_in_channels, | 
|  | cplx_length_, | 
|  | RealFourier::kFftBufferAlignment), | 
|  | cplx_post_(num_out_channels, | 
|  | cplx_length_, | 
|  | RealFourier::kFftBufferAlignment) { | 
|  | RTC_CHECK(num_in_channels_ > 0); | 
|  | RTC_CHECK_GT(block_length_, 0); | 
|  | RTC_CHECK_GT(chunk_length_, 0); | 
|  | RTC_CHECK(block_processor_); | 
|  |  | 
|  | // block_length_ power of 2? | 
|  | RTC_CHECK_EQ(0, block_length_ & (block_length_ - 1)); | 
|  | } | 
|  |  | 
|  | LappedTransform::~LappedTransform() = default; | 
|  |  | 
|  | void LappedTransform::ProcessChunk(const float* const* in_chunk, | 
|  | float* const* out_chunk) { | 
|  | blocker_.ProcessChunk(in_chunk, chunk_length_, num_in_channels_, | 
|  | num_out_channels_, out_chunk); | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |