1 /*
2  *  Copyright (c) 2021 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 #include "modules/audio_processing/capture_levels_adjuster/audio_samples_scaler.h"
11 
12 #include <algorithm>
13 
14 #include "api/array_view.h"
15 #include "modules/audio_processing/audio_buffer.h"
16 #include "rtc_base/checks.h"
17 #include "rtc_base/numerics/safe_minmax.h"
18 
19 namespace webrtc {
20 
AudioSamplesScaler(float initial_gain)21 AudioSamplesScaler::AudioSamplesScaler(float initial_gain)
22     : previous_gain_(initial_gain), target_gain_(initial_gain) {}
23 
Process(AudioBuffer & audio_buffer)24 void AudioSamplesScaler::Process(AudioBuffer& audio_buffer) {
25   if (static_cast<int>(audio_buffer.num_frames()) != samples_per_channel_) {
26     // Update the members depending on audio-buffer length if needed.
27     RTC_DCHECK_GT(audio_buffer.num_frames(), 0);
28     samples_per_channel_ = static_cast<int>(audio_buffer.num_frames());
29     one_by_samples_per_channel_ = 1.f / samples_per_channel_;
30   }
31 
32   if (target_gain_ == 1.f && previous_gain_ == target_gain_) {
33     // If only a gain of 1 is to be applied, do an early return without applying
34     // any gain.
35     return;
36   }
37 
38   float gain = previous_gain_;
39   if (previous_gain_ == target_gain_) {
40     // Apply a non-changing gain.
41     for (size_t channel = 0; channel < audio_buffer.num_channels(); ++channel) {
42       rtc::ArrayView<float> channel_view(audio_buffer.channels()[channel],
43                                          samples_per_channel_);
44       for (float& sample : channel_view) {
45         sample *= gain;
46       }
47     }
48   } else {
49     const float increment =
50         (target_gain_ - previous_gain_) * one_by_samples_per_channel_;
51 
52     if (increment > 0.f) {
53       // Apply an increasing gain.
54       for (size_t channel = 0; channel < audio_buffer.num_channels();
55            ++channel) {
56         gain = previous_gain_;
57         rtc::ArrayView<float> channel_view(audio_buffer.channels()[channel],
58                                            samples_per_channel_);
59         for (float& sample : channel_view) {
60           gain = std::min(gain + increment, target_gain_);
61           sample *= gain;
62         }
63       }
64     } else {
65       // Apply a decreasing gain.
66       for (size_t channel = 0; channel < audio_buffer.num_channels();
67            ++channel) {
68         gain = previous_gain_;
69         rtc::ArrayView<float> channel_view(audio_buffer.channels()[channel],
70                                            samples_per_channel_);
71         for (float& sample : channel_view) {
72           gain = std::max(gain + increment, target_gain_);
73           sample *= gain;
74         }
75       }
76     }
77   }
78   previous_gain_ = target_gain_;
79 
80   // Saturate the samples to be in the S16 range.
81   for (size_t channel = 0; channel < audio_buffer.num_channels(); ++channel) {
82     rtc::ArrayView<float> channel_view(audio_buffer.channels()[channel],
83                                        samples_per_channel_);
84     for (float& sample : channel_view) {
85       constexpr float kMinFloatS16Value = -32768.f;
86       constexpr float kMaxFloatS16Value = 32767.f;
87       sample = rtc::SafeClamp(sample, kMinFloatS16Value, kMaxFloatS16Value);
88     }
89   }
90 }
91 
92 }  // namespace webrtc
93