1*d9f75844SAndroid Build Coastguard Worker /* 2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard Worker // Modified from the Chromium original here: 12*d9f75844SAndroid Build Coastguard Worker // src/media/base/sinc_resampler.h 13*d9f75844SAndroid Build Coastguard Worker 14*d9f75844SAndroid Build Coastguard Worker #ifndef COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ 15*d9f75844SAndroid Build Coastguard Worker #define COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ 16*d9f75844SAndroid Build Coastguard Worker 17*d9f75844SAndroid Build Coastguard Worker #include <stddef.h> 18*d9f75844SAndroid Build Coastguard Worker 19*d9f75844SAndroid Build Coastguard Worker #include <memory> 20*d9f75844SAndroid Build Coastguard Worker 21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/gtest_prod_util.h" 22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/memory/aligned_malloc.h" 23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/system/arch.h" 24*d9f75844SAndroid Build Coastguard Worker 25*d9f75844SAndroid Build Coastguard Worker namespace webrtc { 26*d9f75844SAndroid Build Coastguard Worker 27*d9f75844SAndroid Build Coastguard Worker // Callback class for providing more data into the resampler. Expects `frames` 28*d9f75844SAndroid Build Coastguard Worker // of data to be rendered into `destination`; zero padded if not enough frames 29*d9f75844SAndroid Build Coastguard Worker // are available to satisfy the request. 30*d9f75844SAndroid Build Coastguard Worker class SincResamplerCallback { 31*d9f75844SAndroid Build Coastguard Worker public: ~SincResamplerCallback()32*d9f75844SAndroid Build Coastguard Worker virtual ~SincResamplerCallback() {} 33*d9f75844SAndroid Build Coastguard Worker virtual void Run(size_t frames, float* destination) = 0; 34*d9f75844SAndroid Build Coastguard Worker }; 35*d9f75844SAndroid Build Coastguard Worker 36*d9f75844SAndroid Build Coastguard Worker // SincResampler is a high-quality single-channel sample-rate converter. 37*d9f75844SAndroid Build Coastguard Worker class SincResampler { 38*d9f75844SAndroid Build Coastguard Worker public: 39*d9f75844SAndroid Build Coastguard Worker // The kernel size can be adjusted for quality (higher is better) at the 40*d9f75844SAndroid Build Coastguard Worker // expense of performance. Must be a multiple of 32. 41*d9f75844SAndroid Build Coastguard Worker // TODO(dalecurtis): Test performance to see if we can jack this up to 64+. 42*d9f75844SAndroid Build Coastguard Worker static const size_t kKernelSize = 32; 43*d9f75844SAndroid Build Coastguard Worker 44*d9f75844SAndroid Build Coastguard Worker // Default request size. Affects how often and for how much SincResampler 45*d9f75844SAndroid Build Coastguard Worker // calls back for input. Must be greater than kKernelSize. 46*d9f75844SAndroid Build Coastguard Worker static const size_t kDefaultRequestSize = 512; 47*d9f75844SAndroid Build Coastguard Worker 48*d9f75844SAndroid Build Coastguard Worker // The kernel offset count is used for interpolation and is the number of 49*d9f75844SAndroid Build Coastguard Worker // sub-sample kernel shifts. Can be adjusted for quality (higher is better) 50*d9f75844SAndroid Build Coastguard Worker // at the expense of allocating more memory. 51*d9f75844SAndroid Build Coastguard Worker static const size_t kKernelOffsetCount = 32; 52*d9f75844SAndroid Build Coastguard Worker static const size_t kKernelStorageSize = 53*d9f75844SAndroid Build Coastguard Worker kKernelSize * (kKernelOffsetCount + 1); 54*d9f75844SAndroid Build Coastguard Worker 55*d9f75844SAndroid Build Coastguard Worker // Constructs a SincResampler with the specified `read_cb`, which is used to 56*d9f75844SAndroid Build Coastguard Worker // acquire audio data for resampling. `io_sample_rate_ratio` is the ratio 57*d9f75844SAndroid Build Coastguard Worker // of input / output sample rates. `request_frames` controls the size in 58*d9f75844SAndroid Build Coastguard Worker // frames of the buffer requested by each `read_cb` call. The value must be 59*d9f75844SAndroid Build Coastguard Worker // greater than kKernelSize. Specify kDefaultRequestSize if there are no 60*d9f75844SAndroid Build Coastguard Worker // request size constraints. 61*d9f75844SAndroid Build Coastguard Worker SincResampler(double io_sample_rate_ratio, 62*d9f75844SAndroid Build Coastguard Worker size_t request_frames, 63*d9f75844SAndroid Build Coastguard Worker SincResamplerCallback* read_cb); 64*d9f75844SAndroid Build Coastguard Worker virtual ~SincResampler(); 65*d9f75844SAndroid Build Coastguard Worker 66*d9f75844SAndroid Build Coastguard Worker SincResampler(const SincResampler&) = delete; 67*d9f75844SAndroid Build Coastguard Worker SincResampler& operator=(const SincResampler&) = delete; 68*d9f75844SAndroid Build Coastguard Worker 69*d9f75844SAndroid Build Coastguard Worker // Resample `frames` of data from `read_cb_` into `destination`. 70*d9f75844SAndroid Build Coastguard Worker void Resample(size_t frames, float* destination); 71*d9f75844SAndroid Build Coastguard Worker 72*d9f75844SAndroid Build Coastguard Worker // The maximum size in frames that guarantees Resample() will only make a 73*d9f75844SAndroid Build Coastguard Worker // single call to `read_cb_` for more data. 74*d9f75844SAndroid Build Coastguard Worker size_t ChunkSize() const; 75*d9f75844SAndroid Build Coastguard Worker request_frames()76*d9f75844SAndroid Build Coastguard Worker size_t request_frames() const { return request_frames_; } 77*d9f75844SAndroid Build Coastguard Worker 78*d9f75844SAndroid Build Coastguard Worker // Flush all buffered data and reset internal indices. Not thread safe, do 79*d9f75844SAndroid Build Coastguard Worker // not call while Resample() is in progress. 80*d9f75844SAndroid Build Coastguard Worker void Flush(); 81*d9f75844SAndroid Build Coastguard Worker 82*d9f75844SAndroid Build Coastguard Worker // Update `io_sample_rate_ratio_`. SetRatio() will cause a reconstruction of 83*d9f75844SAndroid Build Coastguard Worker // the kernels used for resampling. Not thread safe, do not call while 84*d9f75844SAndroid Build Coastguard Worker // Resample() is in progress. 85*d9f75844SAndroid Build Coastguard Worker // 86*d9f75844SAndroid Build Coastguard Worker // TODO(ajm): Use this in PushSincResampler rather than reconstructing 87*d9f75844SAndroid Build Coastguard Worker // SincResampler. We would also need a way to update `request_frames_`. 88*d9f75844SAndroid Build Coastguard Worker void SetRatio(double io_sample_rate_ratio); 89*d9f75844SAndroid Build Coastguard Worker get_kernel_for_testing()90*d9f75844SAndroid Build Coastguard Worker float* get_kernel_for_testing() { return kernel_storage_.get(); } 91*d9f75844SAndroid Build Coastguard Worker 92*d9f75844SAndroid Build Coastguard Worker private: 93*d9f75844SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve); 94*d9f75844SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark); 95*d9f75844SAndroid Build Coastguard Worker 96*d9f75844SAndroid Build Coastguard Worker void InitializeKernel(); 97*d9f75844SAndroid Build Coastguard Worker void UpdateRegions(bool second_load); 98*d9f75844SAndroid Build Coastguard Worker 99*d9f75844SAndroid Build Coastguard Worker // Selects runtime specific CPU features like SSE. Must be called before 100*d9f75844SAndroid Build Coastguard Worker // using SincResampler. 101*d9f75844SAndroid Build Coastguard Worker // TODO(ajm): Currently managed by the class internally. See the note with 102*d9f75844SAndroid Build Coastguard Worker // `convolve_proc_` below. 103*d9f75844SAndroid Build Coastguard Worker void InitializeCPUSpecificFeatures(); 104*d9f75844SAndroid Build Coastguard Worker 105*d9f75844SAndroid Build Coastguard Worker // Compute convolution of `k1` and `k2` over `input_ptr`, resultant sums are 106*d9f75844SAndroid Build Coastguard Worker // linearly interpolated using `kernel_interpolation_factor`. On x86 and ARM 107*d9f75844SAndroid Build Coastguard Worker // the underlying implementation is chosen at run time. 108*d9f75844SAndroid Build Coastguard Worker static float Convolve_C(const float* input_ptr, 109*d9f75844SAndroid Build Coastguard Worker const float* k1, 110*d9f75844SAndroid Build Coastguard Worker const float* k2, 111*d9f75844SAndroid Build Coastguard Worker double kernel_interpolation_factor); 112*d9f75844SAndroid Build Coastguard Worker #if defined(WEBRTC_ARCH_X86_FAMILY) 113*d9f75844SAndroid Build Coastguard Worker static float Convolve_SSE(const float* input_ptr, 114*d9f75844SAndroid Build Coastguard Worker const float* k1, 115*d9f75844SAndroid Build Coastguard Worker const float* k2, 116*d9f75844SAndroid Build Coastguard Worker double kernel_interpolation_factor); 117*d9f75844SAndroid Build Coastguard Worker static float Convolve_AVX2(const float* input_ptr, 118*d9f75844SAndroid Build Coastguard Worker const float* k1, 119*d9f75844SAndroid Build Coastguard Worker const float* k2, 120*d9f75844SAndroid Build Coastguard Worker double kernel_interpolation_factor); 121*d9f75844SAndroid Build Coastguard Worker #elif defined(WEBRTC_HAS_NEON) 122*d9f75844SAndroid Build Coastguard Worker static float Convolve_NEON(const float* input_ptr, 123*d9f75844SAndroid Build Coastguard Worker const float* k1, 124*d9f75844SAndroid Build Coastguard Worker const float* k2, 125*d9f75844SAndroid Build Coastguard Worker double kernel_interpolation_factor); 126*d9f75844SAndroid Build Coastguard Worker #endif 127*d9f75844SAndroid Build Coastguard Worker 128*d9f75844SAndroid Build Coastguard Worker // The ratio of input / output sample rates. 129*d9f75844SAndroid Build Coastguard Worker double io_sample_rate_ratio_; 130*d9f75844SAndroid Build Coastguard Worker 131*d9f75844SAndroid Build Coastguard Worker // An index on the source input buffer with sub-sample precision. It must be 132*d9f75844SAndroid Build Coastguard Worker // double precision to avoid drift. 133*d9f75844SAndroid Build Coastguard Worker double virtual_source_idx_; 134*d9f75844SAndroid Build Coastguard Worker 135*d9f75844SAndroid Build Coastguard Worker // The buffer is primed once at the very beginning of processing. 136*d9f75844SAndroid Build Coastguard Worker bool buffer_primed_; 137*d9f75844SAndroid Build Coastguard Worker 138*d9f75844SAndroid Build Coastguard Worker // Source of data for resampling. 139*d9f75844SAndroid Build Coastguard Worker SincResamplerCallback* read_cb_; 140*d9f75844SAndroid Build Coastguard Worker 141*d9f75844SAndroid Build Coastguard Worker // The size (in samples) to request from each `read_cb_` execution. 142*d9f75844SAndroid Build Coastguard Worker const size_t request_frames_; 143*d9f75844SAndroid Build Coastguard Worker 144*d9f75844SAndroid Build Coastguard Worker // The number of source frames processed per pass. 145*d9f75844SAndroid Build Coastguard Worker size_t block_size_; 146*d9f75844SAndroid Build Coastguard Worker 147*d9f75844SAndroid Build Coastguard Worker // The size (in samples) of the internal buffer used by the resampler. 148*d9f75844SAndroid Build Coastguard Worker const size_t input_buffer_size_; 149*d9f75844SAndroid Build Coastguard Worker 150*d9f75844SAndroid Build Coastguard Worker // Contains kKernelOffsetCount kernels back-to-back, each of size kKernelSize. 151*d9f75844SAndroid Build Coastguard Worker // The kernel offsets are sub-sample shifts of a windowed sinc shifted from 152*d9f75844SAndroid Build Coastguard Worker // 0.0 to 1.0 sample. 153*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<float[], AlignedFreeDeleter> kernel_storage_; 154*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<float[], AlignedFreeDeleter> kernel_pre_sinc_storage_; 155*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<float[], AlignedFreeDeleter> kernel_window_storage_; 156*d9f75844SAndroid Build Coastguard Worker 157*d9f75844SAndroid Build Coastguard Worker // Data from the source is copied into this buffer for each processing pass. 158*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_; 159*d9f75844SAndroid Build Coastguard Worker 160*d9f75844SAndroid Build Coastguard Worker // Stores the runtime selection of which Convolve function to use. 161*d9f75844SAndroid Build Coastguard Worker // TODO(ajm): Move to using a global static which must only be initialized 162*d9f75844SAndroid Build Coastguard Worker // once by the user. We're not doing this initially, because we don't have 163*d9f75844SAndroid Build Coastguard Worker // e.g. a LazyInstance helper in webrtc. 164*d9f75844SAndroid Build Coastguard Worker typedef float (*ConvolveProc)(const float*, 165*d9f75844SAndroid Build Coastguard Worker const float*, 166*d9f75844SAndroid Build Coastguard Worker const float*, 167*d9f75844SAndroid Build Coastguard Worker double); 168*d9f75844SAndroid Build Coastguard Worker ConvolveProc convolve_proc_; 169*d9f75844SAndroid Build Coastguard Worker 170*d9f75844SAndroid Build Coastguard Worker // Pointers to the various regions inside `input_buffer_`. See the diagram at 171*d9f75844SAndroid Build Coastguard Worker // the top of the .cc file for more information. 172*d9f75844SAndroid Build Coastguard Worker float* r0_; 173*d9f75844SAndroid Build Coastguard Worker float* const r1_; 174*d9f75844SAndroid Build Coastguard Worker float* const r2_; 175*d9f75844SAndroid Build Coastguard Worker float* r3_; 176*d9f75844SAndroid Build Coastguard Worker float* r4_; 177*d9f75844SAndroid Build Coastguard Worker }; 178*d9f75844SAndroid Build Coastguard Worker 179*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc 180*d9f75844SAndroid Build Coastguard Worker 181*d9f75844SAndroid Build Coastguard Worker #endif // COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ 182