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