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