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