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:
Alex Loiko
2018-07-02 11:37:47 +02:00
committed by Commit Bot
parent c167673c4d
commit 5c71e74331
3 changed files with 58 additions and 12 deletions

View File

@ -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;

View File

@ -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}};