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