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/modules/audio_processing/splitting_filter.h"
12 
13 #include "webrtc/base/checks.h"
14 #include "webrtc/common_audio/include/audio_util.h"
15 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
16 #include "webrtc/common_audio/channel_buffer.h"
17 
18 namespace webrtc {
19 
SplittingFilter(int channels)20 SplittingFilter::SplittingFilter(int channels)
21     : channels_(channels),
22       two_bands_states_(new TwoBandsStates[channels]),
23       band1_states_(new TwoBandsStates[channels]),
24       band2_states_(new TwoBandsStates[channels]) {
25   for (int i = 0; i < channels; ++i) {
26     analysis_resamplers_.push_back(new PushSincResampler(
27         kSamplesPer48kHzChannel, kSamplesPer64kHzChannel));
28     synthesis_resamplers_.push_back(new PushSincResampler(
29         kSamplesPer64kHzChannel, kSamplesPer48kHzChannel));
30   }
31 }
32 
Analysis(const IFChannelBuffer * data,IFChannelBuffer * bands)33 void SplittingFilter::Analysis(const IFChannelBuffer* data,
34                                IFChannelBuffer* bands) {
35   DCHECK(bands->num_bands() == 2 || bands->num_bands() == 3);
36   DCHECK_EQ(channels_, data->num_channels());
37   DCHECK_EQ(channels_, bands->num_channels());
38   DCHECK_EQ(data->num_frames(),
39             bands->num_frames_per_band() * bands->num_bands());
40   if (bands->num_bands() == 2) {
41     TwoBandsAnalysis(data, bands);
42   } else if (bands->num_bands() == 3) {
43     ThreeBandsAnalysis(data, bands);
44   }
45 }
46 
Synthesis(const IFChannelBuffer * bands,IFChannelBuffer * data)47 void SplittingFilter::Synthesis(const IFChannelBuffer* bands,
48                                 IFChannelBuffer* data) {
49   DCHECK(bands->num_bands() == 2 || bands->num_bands() == 3);
50   DCHECK_EQ(channels_, data->num_channels());
51   DCHECK_EQ(channels_, bands->num_channels());
52   DCHECK_EQ(data->num_frames(),
53             bands->num_frames_per_band() * bands->num_bands());
54   if (bands->num_bands() == 2) {
55     TwoBandsSynthesis(bands, data);
56   } else if (bands->num_bands() == 3) {
57     ThreeBandsSynthesis(bands, data);
58   }
59 }
60 
TwoBandsAnalysis(const IFChannelBuffer * data,IFChannelBuffer * bands)61 void SplittingFilter::TwoBandsAnalysis(const IFChannelBuffer* data,
62                                        IFChannelBuffer* bands) {
63   for (int i = 0; i < channels_; ++i) {
64     WebRtcSpl_AnalysisQMF(data->ibuf_const()->channels()[i],
65                           data->num_frames(),
66                           bands->ibuf()->channels(0)[i],
67                           bands->ibuf()->channels(1)[i],
68                           two_bands_states_[i].analysis_state1,
69                           two_bands_states_[i].analysis_state2);
70   }
71 }
72 
TwoBandsSynthesis(const IFChannelBuffer * bands,IFChannelBuffer * data)73 void SplittingFilter::TwoBandsSynthesis(const IFChannelBuffer* bands,
74                                         IFChannelBuffer* data) {
75   for (int i = 0; i < channels_; ++i) {
76     WebRtcSpl_SynthesisQMF(bands->ibuf_const()->channels(0)[i],
77                            bands->ibuf_const()->channels(1)[i],
78                            bands->num_frames_per_band(),
79                            data->ibuf()->channels()[i],
80                            two_bands_states_[i].synthesis_state1,
81                            two_bands_states_[i].synthesis_state2);
82   }
83 }
84 
85 // This is a simple implementation using the existing code and will be replaced
86 // by a proper 3 band filter bank.
87 // It up-samples from 48kHz to 64kHz, splits twice into 2 bands and discards the
88 // uppermost band, because it is empty anyway.
ThreeBandsAnalysis(const IFChannelBuffer * data,IFChannelBuffer * bands)89 void SplittingFilter::ThreeBandsAnalysis(const IFChannelBuffer* data,
90                                          IFChannelBuffer* bands) {
91   DCHECK_EQ(kSamplesPer48kHzChannel,
92             data->num_frames());
93   InitBuffers();
94   for (int i = 0; i < channels_; ++i) {
95     analysis_resamplers_[i]->Resample(data->ibuf_const()->channels()[i],
96                                       kSamplesPer48kHzChannel,
97                                       int_buffer_.get(),
98                                       kSamplesPer64kHzChannel);
99     WebRtcSpl_AnalysisQMF(int_buffer_.get(),
100                           kSamplesPer64kHzChannel,
101                           int_buffer_.get(),
102                           int_buffer_.get() + kSamplesPer32kHzChannel,
103                           two_bands_states_[i].analysis_state1,
104                           two_bands_states_[i].analysis_state2);
105     WebRtcSpl_AnalysisQMF(int_buffer_.get(),
106                           kSamplesPer32kHzChannel,
107                           bands->ibuf()->channels(0)[i],
108                           bands->ibuf()->channels(1)[i],
109                           band1_states_[i].analysis_state1,
110                           band1_states_[i].analysis_state2);
111     WebRtcSpl_AnalysisQMF(int_buffer_.get() + kSamplesPer32kHzChannel,
112                           kSamplesPer32kHzChannel,
113                           int_buffer_.get(),
114                           bands->ibuf()->channels(2)[i],
115                           band2_states_[i].analysis_state1,
116                           band2_states_[i].analysis_state2);
117   }
118 }
119 
120 // This is a simple implementation using the existing code and will be replaced
121 // by a proper 3 band filter bank.
122 // Using an empty uppermost band, it merges the 4 bands in 2 steps and
123 // down-samples from 64kHz to 48kHz.
ThreeBandsSynthesis(const IFChannelBuffer * bands,IFChannelBuffer * data)124 void SplittingFilter::ThreeBandsSynthesis(const IFChannelBuffer* bands,
125                                           IFChannelBuffer* data) {
126   DCHECK_EQ(kSamplesPer48kHzChannel,
127             data->num_frames());
128   InitBuffers();
129   for (int i = 0; i < channels_; ++i) {
130     memset(int_buffer_.get(),
131            0,
132            kSamplesPer64kHzChannel * sizeof(int_buffer_[0]));
133     WebRtcSpl_SynthesisQMF(bands->ibuf_const()->channels(0)[i],
134                            bands->ibuf_const()->channels(1)[i],
135                            kSamplesPer16kHzChannel,
136                            int_buffer_.get(),
137                            band1_states_[i].synthesis_state1,
138                            band1_states_[i].synthesis_state2);
139     WebRtcSpl_SynthesisQMF(int_buffer_.get() + kSamplesPer32kHzChannel,
140                            bands->ibuf_const()->channels(2)[i],
141                            kSamplesPer16kHzChannel,
142                            int_buffer_.get() + kSamplesPer32kHzChannel,
143                            band2_states_[i].synthesis_state1,
144                            band2_states_[i].synthesis_state2);
145     WebRtcSpl_SynthesisQMF(int_buffer_.get(),
146                            int_buffer_.get() + kSamplesPer32kHzChannel,
147                            kSamplesPer32kHzChannel,
148                            int_buffer_.get(),
149                            two_bands_states_[i].synthesis_state1,
150                            two_bands_states_[i].synthesis_state2);
151     synthesis_resamplers_[i]->Resample(int_buffer_.get(),
152                                        kSamplesPer64kHzChannel,
153                                        data->ibuf()->channels()[i],
154                                        kSamplesPer48kHzChannel);
155   }
156 }
157 
InitBuffers()158 void SplittingFilter::InitBuffers() {
159   if (!int_buffer_) {
160     int_buffer_.reset(new int16_t[kSamplesPer64kHzChannel]);
161   }
162 }
163 
164 }  // namespace webrtc
165