1 /*
2  *  Copyright (c) 2014 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 #include "common_audio/audio_converter.h"
12 
13 #include <cstring>
14 #include <memory>
15 #include <utility>
16 #include <vector>
17 
18 #include "common_audio/channel_buffer.h"
19 #include "common_audio/resampler/push_sinc_resampler.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/numerics/safe_conversions.h"
22 
23 namespace webrtc {
24 
25 class CopyConverter : public AudioConverter {
26  public:
CopyConverter(size_t src_channels,size_t src_frames,size_t dst_channels,size_t dst_frames)27   CopyConverter(size_t src_channels,
28                 size_t src_frames,
29                 size_t dst_channels,
30                 size_t dst_frames)
31       : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
~CopyConverter()32   ~CopyConverter() override {}
33 
Convert(const float * const * src,size_t src_size,float * const * dst,size_t dst_capacity)34   void Convert(const float* const* src,
35                size_t src_size,
36                float* const* dst,
37                size_t dst_capacity) override {
38     CheckSizes(src_size, dst_capacity);
39     if (src != dst) {
40       for (size_t i = 0; i < src_channels(); ++i)
41         std::memcpy(dst[i], src[i], dst_frames() * sizeof(*dst[i]));
42     }
43   }
44 };
45 
46 class UpmixConverter : public AudioConverter {
47  public:
UpmixConverter(size_t src_channels,size_t src_frames,size_t dst_channels,size_t dst_frames)48   UpmixConverter(size_t src_channels,
49                  size_t src_frames,
50                  size_t dst_channels,
51                  size_t dst_frames)
52       : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
~UpmixConverter()53   ~UpmixConverter() override {}
54 
Convert(const float * const * src,size_t src_size,float * const * dst,size_t dst_capacity)55   void Convert(const float* const* src,
56                size_t src_size,
57                float* const* dst,
58                size_t dst_capacity) override {
59     CheckSizes(src_size, dst_capacity);
60     for (size_t i = 0; i < dst_frames(); ++i) {
61       const float value = src[0][i];
62       for (size_t j = 0; j < dst_channels(); ++j)
63         dst[j][i] = value;
64     }
65   }
66 };
67 
68 class DownmixConverter : public AudioConverter {
69  public:
DownmixConverter(size_t src_channels,size_t src_frames,size_t dst_channels,size_t dst_frames)70   DownmixConverter(size_t src_channels,
71                    size_t src_frames,
72                    size_t dst_channels,
73                    size_t dst_frames)
74       : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
~DownmixConverter()75   ~DownmixConverter() override {}
76 
Convert(const float * const * src,size_t src_size,float * const * dst,size_t dst_capacity)77   void Convert(const float* const* src,
78                size_t src_size,
79                float* const* dst,
80                size_t dst_capacity) override {
81     CheckSizes(src_size, dst_capacity);
82     float* dst_mono = dst[0];
83     for (size_t i = 0; i < src_frames(); ++i) {
84       float sum = 0;
85       for (size_t j = 0; j < src_channels(); ++j)
86         sum += src[j][i];
87       dst_mono[i] = sum / src_channels();
88     }
89   }
90 };
91 
92 class ResampleConverter : public AudioConverter {
93  public:
ResampleConverter(size_t src_channels,size_t src_frames,size_t dst_channels,size_t dst_frames)94   ResampleConverter(size_t src_channels,
95                     size_t src_frames,
96                     size_t dst_channels,
97                     size_t dst_frames)
98       : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {
99     resamplers_.reserve(src_channels);
100     for (size_t i = 0; i < src_channels; ++i)
101       resamplers_.push_back(std::unique_ptr<PushSincResampler>(
102           new PushSincResampler(src_frames, dst_frames)));
103   }
~ResampleConverter()104   ~ResampleConverter() override {}
105 
Convert(const float * const * src,size_t src_size,float * const * dst,size_t dst_capacity)106   void Convert(const float* const* src,
107                size_t src_size,
108                float* const* dst,
109                size_t dst_capacity) override {
110     CheckSizes(src_size, dst_capacity);
111     for (size_t i = 0; i < resamplers_.size(); ++i)
112       resamplers_[i]->Resample(src[i], src_frames(), dst[i], dst_frames());
113   }
114 
115  private:
116   std::vector<std::unique_ptr<PushSincResampler>> resamplers_;
117 };
118 
119 // Apply a vector of converters in serial, in the order given. At least two
120 // converters must be provided.
121 class CompositionConverter : public AudioConverter {
122  public:
CompositionConverter(std::vector<std::unique_ptr<AudioConverter>> converters)123   explicit CompositionConverter(
124       std::vector<std::unique_ptr<AudioConverter>> converters)
125       : converters_(std::move(converters)) {
126     RTC_CHECK_GE(converters_.size(), 2);
127     // We need an intermediate buffer after every converter.
128     for (auto it = converters_.begin(); it != converters_.end() - 1; ++it)
129       buffers_.push_back(
130           std::unique_ptr<ChannelBuffer<float>>(new ChannelBuffer<float>(
131               (*it)->dst_frames(), (*it)->dst_channels())));
132   }
~CompositionConverter()133   ~CompositionConverter() override {}
134 
Convert(const float * const * src,size_t src_size,float * const * dst,size_t dst_capacity)135   void Convert(const float* const* src,
136                size_t src_size,
137                float* const* dst,
138                size_t dst_capacity) override {
139     converters_.front()->Convert(src, src_size, buffers_.front()->channels(),
140                                  buffers_.front()->size());
141     for (size_t i = 2; i < converters_.size(); ++i) {
142       auto& src_buffer = buffers_[i - 2];
143       auto& dst_buffer = buffers_[i - 1];
144       converters_[i]->Convert(src_buffer->channels(), src_buffer->size(),
145                               dst_buffer->channels(), dst_buffer->size());
146     }
147     converters_.back()->Convert(buffers_.back()->channels(),
148                                 buffers_.back()->size(), dst, dst_capacity);
149   }
150 
151  private:
152   std::vector<std::unique_ptr<AudioConverter>> converters_;
153   std::vector<std::unique_ptr<ChannelBuffer<float>>> buffers_;
154 };
155 
Create(size_t src_channels,size_t src_frames,size_t dst_channels,size_t dst_frames)156 std::unique_ptr<AudioConverter> AudioConverter::Create(size_t src_channels,
157                                                        size_t src_frames,
158                                                        size_t dst_channels,
159                                                        size_t dst_frames) {
160   std::unique_ptr<AudioConverter> sp;
161   if (src_channels > dst_channels) {
162     if (src_frames != dst_frames) {
163       std::vector<std::unique_ptr<AudioConverter>> converters;
164       converters.push_back(std::unique_ptr<AudioConverter>(new DownmixConverter(
165           src_channels, src_frames, dst_channels, src_frames)));
166       converters.push_back(
167           std::unique_ptr<AudioConverter>(new ResampleConverter(
168               dst_channels, src_frames, dst_channels, dst_frames)));
169       sp.reset(new CompositionConverter(std::move(converters)));
170     } else {
171       sp.reset(new DownmixConverter(src_channels, src_frames, dst_channels,
172                                     dst_frames));
173     }
174   } else if (src_channels < dst_channels) {
175     if (src_frames != dst_frames) {
176       std::vector<std::unique_ptr<AudioConverter>> converters;
177       converters.push_back(
178           std::unique_ptr<AudioConverter>(new ResampleConverter(
179               src_channels, src_frames, src_channels, dst_frames)));
180       converters.push_back(std::unique_ptr<AudioConverter>(new UpmixConverter(
181           src_channels, dst_frames, dst_channels, dst_frames)));
182       sp.reset(new CompositionConverter(std::move(converters)));
183     } else {
184       sp.reset(new UpmixConverter(src_channels, src_frames, dst_channels,
185                                   dst_frames));
186     }
187   } else if (src_frames != dst_frames) {
188     sp.reset(new ResampleConverter(src_channels, src_frames, dst_channels,
189                                    dst_frames));
190   } else {
191     sp.reset(
192         new CopyConverter(src_channels, src_frames, dst_channels, dst_frames));
193   }
194 
195   return sp;
196 }
197 
198 // For CompositionConverter.
AudioConverter()199 AudioConverter::AudioConverter()
200     : src_channels_(0), src_frames_(0), dst_channels_(0), dst_frames_(0) {}
201 
AudioConverter(size_t src_channels,size_t src_frames,size_t dst_channels,size_t dst_frames)202 AudioConverter::AudioConverter(size_t src_channels,
203                                size_t src_frames,
204                                size_t dst_channels,
205                                size_t dst_frames)
206     : src_channels_(src_channels),
207       src_frames_(src_frames),
208       dst_channels_(dst_channels),
209       dst_frames_(dst_frames) {
210   RTC_CHECK(dst_channels == src_channels || dst_channels == 1 ||
211             src_channels == 1);
212 }
213 
CheckSizes(size_t src_size,size_t dst_capacity) const214 void AudioConverter::CheckSizes(size_t src_size, size_t dst_capacity) const {
215   RTC_CHECK_EQ(src_size, src_channels() * src_frames());
216   RTC_CHECK_GE(dst_capacity, dst_channels() * dst_frames());
217 }
218 
219 }  // namespace webrtc
220