xref: /aosp_15_r20/external/webrtc/common_audio/resampler/sinc_resampler.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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