Add AGC1-compliant fake recording device.
The AGC submodule of APM changes analog gain. These gain changes are typically ignored by the test tool audioproc_f. There is an option of the test tool to take action on the gain changes. It's the '--simulate_mic_gain' option. The option converts the analog gain to a digital gain. The digital gain is applied to the capture stream. This change adds a new simulated microphone kind. The new microphone has a gain curve defined by modules/audio_processing/agc/gain_map_internal.h. That gain curve defines how AGC1 expects a microphone to behave. Bug: webrtc:7494 Change-Id: Ifb3f54a8c6f8c001a711fa977f39f32413069780 Reviewed-on: https://webrtc-review.googlesource.com/86128 Commit-Queue: Alex Loiko <aleloi@webrtc.org> Reviewed-by: Sam Zackrisson <saza@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23801}
This commit is contained in:
@ -13,7 +13,10 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "modules/audio_processing/agc/gain_map_internal.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
#include "rtc_base/numerics/safe_minmax.h"
|
||||
#include "rtc_base/ptr_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -21,8 +24,6 @@ namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int16_t kInt16SampleMin = -32768;
|
||||
constexpr int16_t kInt16SampleMax = 32767;
|
||||
constexpr float kFloatSampleMin = -32768.f;
|
||||
constexpr float kFloatSampleMax = 32767.0f;
|
||||
|
||||
@ -76,11 +77,7 @@ class FakeRecordingDeviceLinear final : public FakeRecordingDeviceWorker {
|
||||
const float divisor =
|
||||
(undo_mic_level_ && *undo_mic_level_ > 0) ? *undo_mic_level_ : 255.f;
|
||||
for (size_t i = 0; i < number_of_samples; ++i) {
|
||||
data[i] =
|
||||
std::max(kInt16SampleMin,
|
||||
std::min(kInt16SampleMax,
|
||||
static_cast<int16_t>(static_cast<float>(data[i]) *
|
||||
mic_level_ / divisor)));
|
||||
data[i] = rtc::saturated_cast<int16_t>(data[i] * mic_level_ / divisor);
|
||||
}
|
||||
}
|
||||
void ModifyBufferFloat(ChannelBuffer<float>* buffer) override {
|
||||
@ -91,9 +88,47 @@ class FakeRecordingDeviceLinear final : public FakeRecordingDeviceWorker {
|
||||
for (size_t c = 0; c < buffer->num_channels(); ++c) {
|
||||
for (size_t i = 0; i < buffer->num_frames(); ++i) {
|
||||
buffer->channels()[c][i] =
|
||||
std::max(kFloatSampleMin,
|
||||
std::min(kFloatSampleMax,
|
||||
buffer->channels()[c][i] * mic_level_ / divisor));
|
||||
rtc::SafeClamp(buffer->channels()[c][i] * mic_level_ / divisor,
|
||||
kFloatSampleMin, kFloatSampleMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
float ComputeAgc1LinearFactor(const absl::optional<int>& undo_mic_level,
|
||||
int mic_level) {
|
||||
// If an undo level is specified, virtually restore the unmodified
|
||||
// microphone level; otherwise simulate the mic gain only.
|
||||
const int undo_level =
|
||||
(undo_mic_level && *undo_mic_level > 0) ? *undo_mic_level : 100;
|
||||
return DbToRatio(kGainMap[mic_level] - kGainMap[undo_level]);
|
||||
}
|
||||
|
||||
// Roughly dB-scale fake recording device. Valid levels are [0, 255]. The mic
|
||||
// applies a gain from kGainMap in agc/gain_map_internal.h.
|
||||
class FakeRecordingDeviceAgc1 final : public FakeRecordingDeviceWorker {
|
||||
public:
|
||||
explicit FakeRecordingDeviceAgc1(const int initial_mic_level)
|
||||
: FakeRecordingDeviceWorker(initial_mic_level) {}
|
||||
~FakeRecordingDeviceAgc1() override = default;
|
||||
void ModifyBufferInt16(AudioFrame* buffer) override {
|
||||
const float scaling_factor =
|
||||
ComputeAgc1LinearFactor(undo_mic_level_, mic_level_);
|
||||
const size_t number_of_samples =
|
||||
buffer->samples_per_channel_ * buffer->num_channels_;
|
||||
int16_t* data = buffer->mutable_data();
|
||||
for (size_t i = 0; i < number_of_samples; ++i) {
|
||||
data[i] = rtc::saturated_cast<int16_t>(data[i] * scaling_factor);
|
||||
}
|
||||
}
|
||||
void ModifyBufferFloat(ChannelBuffer<float>* buffer) override {
|
||||
const float scaling_factor =
|
||||
ComputeAgc1LinearFactor(undo_mic_level_, mic_level_);
|
||||
for (size_t c = 0; c < buffer->num_channels(); ++c) {
|
||||
for (size_t i = 0; i < buffer->num_frames(); ++i) {
|
||||
buffer->channels()[c][i] =
|
||||
rtc::SafeClamp(buffer->channels()[c][i] * scaling_factor,
|
||||
kFloatSampleMin, kFloatSampleMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,6 +145,9 @@ FakeRecordingDevice::FakeRecordingDevice(int initial_mic_level,
|
||||
case 1:
|
||||
worker_ = rtc::MakeUnique<FakeRecordingDeviceLinear>(initial_mic_level);
|
||||
break;
|
||||
case 2:
|
||||
worker_ = rtc::MakeUnique<FakeRecordingDeviceAgc1>(initial_mic_level);
|
||||
break;
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
break;
|
||||
|
||||
@ -27,7 +27,7 @@ constexpr int kInitialMicLevel = 100;
|
||||
|
||||
// TODO(alessiob): Add new fake recording device kind values here as they are
|
||||
// added in FakeRecordingDevice::FakeRecordingDevice.
|
||||
const std::vector<int> kFakeRecDeviceKinds = {0, 1};
|
||||
const std::vector<int> kFakeRecDeviceKinds = {0, 1, 2};
|
||||
|
||||
const std::vector<std::vector<float>> kTestMultiChannelSamples{
|
||||
std::vector<float>{-10.f, -1.f, -0.1f, 0.f, 0.1f, 1.f, 10.f}};
|
||||
|
||||
Reference in New Issue
Block a user