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