Home | History | Annotate | Download | only in resampler
      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 WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
     15 #define WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
     16 
     17 #include "webrtc/base/constructormagic.h"
     18 #include "webrtc/system_wrappers/interface/aligned_malloc.h"
     19 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
     20 #include "webrtc/test/testsupport/gtest_prod_util.h"
     21 #include "webrtc/typedefs.h"
     22 
     23 namespace webrtc {
     24 
     25 // Callback class for providing more data into the resampler.  Expects |frames|
     26 // of data to be rendered into |destination|; zero padded if not enough frames
     27 // are available to satisfy the request.
     28 class SincResamplerCallback {
     29  public:
     30   virtual ~SincResamplerCallback() {}
     31   virtual void Run(int frames, float* destination) = 0;
     32 };
     33 
     34 // SincResampler is a high-quality single-channel sample-rate converter.
     35 class SincResampler {
     36  public:
     37   enum {
     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+.
     41     kKernelSize = 32,
     42 
     43     // Default request size.  Affects how often and for how much SincResampler
     44     // calls back for input.  Must be greater than kKernelSize.
     45     kDefaultRequestSize = 512,
     46 
     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.
     50     kKernelOffsetCount = 32,
     51     kKernelStorageSize = kKernelSize * (kKernelOffsetCount + 1),
     52   };
     53 
     54   // Constructs a SincResampler with the specified |read_cb|, which is used to
     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.
     60   SincResampler(double io_sample_rate_ratio,
     61                 int request_frames,
     62                 SincResamplerCallback* read_cb);
     63   virtual ~SincResampler();
     64 
     65   // Resample |frames| of data from |read_cb_| into |destination|.
     66   void Resample(int frames, float* destination);
     67 
     68   // The maximum size in frames that guarantees Resample() will only make a
     69   // single call to |read_cb_| for more data.
     70   int ChunkSize() const;
     71 
     72   int request_frames() const { return request_frames_; }
     73 
     74   // Flush all buffered data and reset internal indices.  Not thread safe, do
     75   // not call while Resample() is in progress.
     76   void Flush();
     77 
     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   //
     82   // TODO(ajm): Use this in PushSincResampler rather than reconstructing
     83   // SincResampler.  We would also need a way to update |request_frames_|.
     84   void SetRatio(double io_sample_rate_ratio);
     85 
     86   float* get_kernel_for_testing() { return kernel_storage_.get(); }
     87 
     88  private:
     89   FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve);
     90   FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark);
     91 
     92   void InitializeKernel();
     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();
    100 
    101   // Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are
    102   // linearly interpolated using |kernel_interpolation_factor|.  On x86 and ARM
    103   // the underlying implementation is chosen at run time.
    104   static float Convolve_C(const float* input_ptr, const float* k1,
    105                           const float* k2, double kernel_interpolation_factor);
    106 #if defined(WEBRTC_ARCH_X86_FAMILY)
    107   static float Convolve_SSE(const float* input_ptr, const float* k1,
    108                             const float* k2,
    109                             double kernel_interpolation_factor);
    110 #elif defined(WEBRTC_ARCH_ARM_V7)
    111   static float Convolve_NEON(const float* input_ptr, const float* k1,
    112                              const float* k2,
    113                              double kernel_interpolation_factor);
    114 #endif
    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.
    127   SincResamplerCallback* read_cb_;
    128 
    129   // The size (in samples) to request from each |read_cb_| execution.
    130   const int request_frames_;
    131 
    132   // The number of source frames processed per pass.
    133   int block_size_;
    134 
    135   // The size (in samples) of the internal buffer used by the resampler.
    136   const int input_buffer_size_;
    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.
    141   scoped_ptr<float[], AlignedFreeDeleter> kernel_storage_;
    142   scoped_ptr<float[], AlignedFreeDeleter> kernel_pre_sinc_storage_;
    143   scoped_ptr<float[], AlignedFreeDeleter> kernel_window_storage_;
    144 
    145   // Data from the source is copied into this buffer for each processing pass.
    146   scoped_ptr<float[], AlignedFreeDeleter> input_buffer_;
    147 
    148   // Stores the runtime selection of which Convolve function to use.
    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.
    152 #if defined(WEBRTC_CPU_DETECTION)
    153   typedef float (*ConvolveProc)(const float*, const float*, const float*,
    154                                 double);
    155   ConvolveProc convolve_proc_;
    156 #endif
    157 
    158   // Pointers to the various regions inside |input_buffer_|.  See the diagram at
    159   // the top of the .cc file for more information.
    160   float* r0_;
    161   float* const r1_;
    162   float* const r2_;
    163   float* r3_;
    164   float* r4_;
    165 
    166   DISALLOW_COPY_AND_ASSIGN(SincResampler);
    167 };
    168 
    169 }  // namespace webrtc
    170 
    171 #endif  // WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
    172