• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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