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