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