push_sinc_resampler.cc (4029B)
1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "common_audio/resampler/push_sinc_resampler.h" 12 13 #include <cstdint> 14 #include <cstring> 15 16 #include "common_audio/include/audio_util.h" 17 #include "common_audio/resampler/sinc_resampler.h" 18 #include "rtc_base/checks.h" 19 20 namespace webrtc { 21 22 PushSincResampler::PushSincResampler(size_t source_frames, 23 size_t destination_frames) 24 : resampler_(new SincResampler(source_frames * 1.0 / destination_frames, 25 source_frames, 26 this)), 27 source_ptr_(nullptr), 28 source_ptr_int_(nullptr), 29 destination_frames_(destination_frames), 30 first_pass_(true), 31 source_available_(0) {} 32 33 PushSincResampler::~PushSincResampler() {} 34 35 size_t PushSincResampler::Resample(const int16_t* source, 36 size_t source_length, 37 int16_t* destination, 38 size_t /* destination_capacity */) { 39 if (!float_buffer_) 40 float_buffer_.reset(new float[destination_frames_]); 41 42 source_ptr_int_ = source; 43 // Pass nullptr as the float source to have Run() read from the int16 source. 44 Resample(nullptr, source_length, float_buffer_.get(), destination_frames_); 45 FloatS16ToS16(float_buffer_.get(), destination_frames_, destination); 46 source_ptr_int_ = nullptr; 47 return destination_frames_; 48 } 49 50 size_t PushSincResampler::Resample(const float* source, 51 size_t source_length, 52 float* destination, 53 size_t destination_capacity) { 54 RTC_CHECK_EQ(source_length, resampler_->request_frames()); 55 RTC_CHECK_GE(destination_capacity, destination_frames_); 56 // Cache the source pointer. Calling Resample() will immediately trigger 57 // the Run() callback whereupon we provide the cached value. 58 source_ptr_ = source; 59 source_available_ = source_length; 60 61 // On the first pass, we call Resample() twice. During the first call, we 62 // provide dummy input and discard the output. This is done to prime the 63 // SincResampler buffer with the correct delay (half the kernel size), thereby 64 // ensuring that all later Resample() calls will only result in one input 65 // request through Run(). 66 // 67 // If this wasn't done, SincResampler would call Run() twice on the first 68 // pass, and we'd have to introduce an entire `source_frames` of delay, rather 69 // than the minimum half kernel. 70 // 71 // It works out that ChunkSize() is exactly the amount of output we need to 72 // request in order to prime the buffer with a single Run() request for 73 // `source_frames`. 74 if (first_pass_) 75 resampler_->Resample(resampler_->ChunkSize(), destination); 76 77 resampler_->Resample(destination_frames_, destination); 78 source_ptr_ = nullptr; 79 return destination_frames_; 80 } 81 82 void PushSincResampler::Run(size_t frames, float* destination) { 83 // Ensure we are only asked for the available samples. This would fail if 84 // Run() was triggered more than once per Resample() call. 85 RTC_CHECK_EQ(source_available_, frames); 86 87 if (first_pass_) { 88 // Provide dummy input on the first pass, the output of which will be 89 // discarded, as described in Resample(). 90 std::memset(destination, 0, frames * sizeof(*destination)); 91 first_pass_ = false; 92 return; 93 } 94 95 if (source_ptr_) { 96 std::memcpy(destination, source_ptr_, frames * sizeof(*destination)); 97 } else { 98 for (size_t i = 0; i < frames; ++i) 99 destination[i] = static_cast<float>(source_ptr_int_[i]); 100 } 101 source_available_ -= frames; 102 } 103 104 } // namespace webrtc