Add WAV and arbitrary geometry support to nlbf test.
This adds functionality from audioproc_float. The geometry parsing code is now shared from test_utils.h. I removed the "mic_spacing" flag from audioproc_float because it's a redundancy that I suspect isn't very useful. Includes a cleanup of the audio_processing test utils. They're now packaged in targets, with the protobuf-using ones split out to avoid requiring users to depend on protobufs. pcm_utils is no longer needed and removed. The primary motivation for this CL is that AudioProcessing currently doesn't support more than two channels and we'd like a way to pass more channels to the beamformer. R=aluebs@webrtc.org, mgraczyk@chromium.org Review URL: https://webrtc-codereview.appspot.com/50899004 Cr-Commit-Position: refs/heads/master@{#9157}
This commit is contained in:
parent
d3ddc1b69e
commit
cb05b72eb2
@ -8,6 +8,18 @@
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'audioproc_test_utils',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/base/base.gyp:rtc_base_approved',
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
|
||||
],
|
||||
'sources': [
|
||||
'test/test_utils.cc',
|
||||
'test/test_utils.h',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'transient_suppression_test',
|
||||
'type': 'executable',
|
||||
@ -39,13 +51,12 @@
|
||||
'target_name': 'nonlinear_beamformer_test',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'audioproc_test_utils',
|
||||
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
|
||||
'<(webrtc_root)/modules/modules.gyp:audio_processing',
|
||||
],
|
||||
'sources': [
|
||||
'beamformer/nonlinear_beamformer_test.cc',
|
||||
'beamformer/pcm_utils.cc',
|
||||
'beamformer/pcm_utils.h',
|
||||
],
|
||||
}, # nonlinear_beamformer_test
|
||||
],
|
||||
@ -65,12 +76,25 @@
|
||||
},
|
||||
'includes': [ '../../build/protoc.gypi', ],
|
||||
},
|
||||
{
|
||||
'target_name': 'audioproc_protobuf_utils',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'audioproc_debug_proto',
|
||||
],
|
||||
'sources': [
|
||||
'test/protobuf_utils.cc',
|
||||
'test/protobuf_utils.h',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'audioproc',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'audio_processing',
|
||||
'audioproc_debug_proto',
|
||||
'audioproc_test_utils',
|
||||
'audioproc_protobuf_utils',
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
|
||||
'<(webrtc_root)/test/test.gyp:test_support',
|
||||
@ -83,6 +107,8 @@
|
||||
'dependencies': [
|
||||
'audio_processing',
|
||||
'audioproc_debug_proto',
|
||||
'audioproc_test_utils',
|
||||
'audioproc_protobuf_utils',
|
||||
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
|
||||
],
|
||||
'sources': [ 'test/audioproc_float.cc', ],
|
||||
@ -92,6 +118,8 @@
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'audioproc_debug_proto',
|
||||
'audioproc_test_utils',
|
||||
'audioproc_protobuf_utils',
|
||||
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
|
||||
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
|
||||
|
||||
@ -294,7 +294,7 @@ void NonlinearBeamformer::InitInterfCovMats() {
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::ProcessChunk(const ChannelBuffer<float>& input,
|
||||
ChannelBuffer<float>* output) {
|
||||
ChannelBuffer<float>* output) {
|
||||
DCHECK_EQ(input.num_channels(), num_input_channels_);
|
||||
DCHECK_EQ(input.num_frames_per_band(), chunk_length_);
|
||||
|
||||
@ -324,10 +324,10 @@ void NonlinearBeamformer::ProcessChunk(const ChannelBuffer<float>& input,
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::ProcessAudioBlock(const complex_f* const* input,
|
||||
int num_input_channels,
|
||||
int num_freq_bins,
|
||||
int num_output_channels,
|
||||
complex_f* const* output) {
|
||||
int num_input_channels,
|
||||
int num_freq_bins,
|
||||
int num_output_channels,
|
||||
complex_f* const* output) {
|
||||
CHECK_EQ(num_freq_bins, kNumFreqBins);
|
||||
CHECK_EQ(num_input_channels, num_input_channels_);
|
||||
CHECK_EQ(num_output_channels, 1);
|
||||
@ -398,7 +398,7 @@ float NonlinearBeamformer::CalculatePostfilterMask(
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::ApplyMasks(const complex_f* const* input,
|
||||
complex_f* const* output) {
|
||||
complex_f* const* output) {
|
||||
complex_f* output_channel = output[0];
|
||||
for (int f_ix = 0; f_ix < kNumFreqBins; ++f_ix) {
|
||||
output_channel[f_ix] = complex_f(0.f, 0.f);
|
||||
|
||||
@ -8,75 +8,82 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/pcm_utils.h"
|
||||
#include "webrtc/modules/audio_processing/test/test_utils.h"
|
||||
|
||||
DEFINE_int32(sample_rate,
|
||||
48000,
|
||||
"The sample rate of the input file. The output"
|
||||
"file will be of the same sample rate.");
|
||||
DEFINE_int32(num_input_channels,
|
||||
2,
|
||||
"The number of channels in the input file.");
|
||||
DEFINE_double(mic_spacing,
|
||||
0.05,
|
||||
"The spacing between microphones on the chromebook which "
|
||||
"recorded the input file.");
|
||||
DEFINE_string(input_file_path,
|
||||
"input.wav",
|
||||
"The absolute path to the input file.");
|
||||
DEFINE_string(output_file_path,
|
||||
"beamformer_test_output.wav",
|
||||
"The absolute path to the output file.");
|
||||
DEFINE_string(i, "", "The name of the input file to read from.");
|
||||
DEFINE_string(o, "out.wav", "Name of the output file to write to.");
|
||||
DEFINE_string(mic_positions, "",
|
||||
"Space delimited cartesian coordinates of microphones in meters. "
|
||||
"The coordinates of each point are contiguous. "
|
||||
"For a two element array: \"x1 y1 z1 x2 y2 z2\"");
|
||||
|
||||
using webrtc::ChannelBuffer;
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
const int kChunksPerSecond = 100;
|
||||
const int kChunkSizeMs = 1000 / kChunksPerSecond;
|
||||
|
||||
const char kUsage[] =
|
||||
"Command-line tool to run beamforming on WAV files. The signal is passed\n"
|
||||
"in as a single band, unlike the audio processing interface which splits\n"
|
||||
"signals into multiple bands.";
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
google::SetUsageMessage(kUsage);
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
const float kChunkTimeMilliseconds = 10;
|
||||
const int kChunkSize = FLAGS_sample_rate / (1000.f / kChunkTimeMilliseconds);
|
||||
const int kInputSamplesPerChunk = kChunkSize * FLAGS_num_input_channels;
|
||||
WavReader in_file(FLAGS_i);
|
||||
WavWriter out_file(FLAGS_o, in_file.sample_rate(), 1);
|
||||
|
||||
ChannelBuffer<float> captured_audio_cb(kChunkSize, FLAGS_num_input_channels);
|
||||
const size_t num_mics = in_file.num_channels();
|
||||
const std::vector<Point> array_geometry =
|
||||
ParseArrayGeometry(FLAGS_mic_positions, num_mics);
|
||||
CHECK_EQ(array_geometry.size(), num_mics);
|
||||
|
||||
FILE* read_file = fopen(FLAGS_input_file_path.c_str(), "rb");
|
||||
if (!read_file) {
|
||||
std::cerr << "Input file '" << FLAGS_input_file_path << "' not found."
|
||||
<< std::endl;
|
||||
return -1;
|
||||
NonlinearBeamformer bf(array_geometry);
|
||||
bf.Initialize(kChunkSizeMs, in_file.sample_rate());
|
||||
|
||||
printf("Input file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
|
||||
FLAGS_i.c_str(), in_file.num_channels(), in_file.sample_rate());
|
||||
printf("Output file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
|
||||
FLAGS_o.c_str(), out_file.num_channels(), out_file.sample_rate());
|
||||
|
||||
ChannelBuffer<float> in_buf(
|
||||
rtc::CheckedDivExact(in_file.sample_rate(), kChunksPerSecond),
|
||||
in_file.num_channels());
|
||||
ChannelBuffer<float> out_buf(
|
||||
rtc::CheckedDivExact(out_file.sample_rate(), kChunksPerSecond),
|
||||
out_file.num_channels());
|
||||
|
||||
std::vector<float> interleaved(in_buf.size());
|
||||
while (in_file.ReadSamples(interleaved.size(),
|
||||
&interleaved[0]) == interleaved.size()) {
|
||||
FloatS16ToFloat(&interleaved[0], interleaved.size(), &interleaved[0]);
|
||||
Deinterleave(&interleaved[0], in_buf.num_frames(),
|
||||
in_buf.num_channels(), in_buf.channels());
|
||||
|
||||
bf.ProcessChunk(in_buf, &out_buf);
|
||||
|
||||
Interleave(out_buf.channels(), out_buf.num_frames(),
|
||||
out_buf.num_channels(), &interleaved[0]);
|
||||
FloatToFloatS16(&interleaved[0], interleaved.size(), &interleaved[0]);
|
||||
out_file.WriteSamples(&interleaved[0], interleaved.size());
|
||||
}
|
||||
|
||||
// Skipping the .wav header. TODO: Add .wav header parsing.
|
||||
fseek(read_file, 44, SEEK_SET);
|
||||
|
||||
FILE* write_file = fopen(FLAGS_output_file_path.c_str(), "wb");
|
||||
|
||||
std::vector<webrtc::Point> array_geometry;
|
||||
for (int i = 0; i < FLAGS_num_input_channels; ++i) {
|
||||
array_geometry.push_back(webrtc::Point(i * FLAGS_mic_spacing, 0.f, 0.f));
|
||||
}
|
||||
webrtc::NonlinearBeamformer bf(array_geometry);
|
||||
bf.Initialize(kChunkTimeMilliseconds, FLAGS_sample_rate);
|
||||
while (true) {
|
||||
size_t samples_read = webrtc::PcmReadToFloat(read_file,
|
||||
kInputSamplesPerChunk,
|
||||
FLAGS_num_input_channels,
|
||||
captured_audio_cb.channels());
|
||||
|
||||
if (static_cast<int>(samples_read) != kInputSamplesPerChunk) {
|
||||
break;
|
||||
}
|
||||
|
||||
bf.ProcessChunk(captured_audio_cb, &captured_audio_cb);
|
||||
webrtc::PcmWriteFromFloat(
|
||||
write_file, kChunkSize, 1, captured_audio_cb.channels());
|
||||
}
|
||||
fclose(read_file);
|
||||
fclose(write_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
return webrtc::main(argc, argv);
|
||||
}
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/beamformer/pcm_utils.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/common_audio/include/audio_util.h"
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
size_t PcmRead(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
int16_t* const* buffer) {
|
||||
CHECK_GE(num_channels, 1);
|
||||
|
||||
rtc::scoped_ptr<int16_t[]> interleaved_buffer(new int16_t[length]);
|
||||
size_t elements_read = fread(interleaved_buffer.get(), sizeof(int16_t),
|
||||
length, file);
|
||||
if (elements_read != length) {
|
||||
// This is only an error if we haven't reached the end of the file.
|
||||
CHECK_NE(0, feof(file));
|
||||
}
|
||||
|
||||
Deinterleave(interleaved_buffer.get(),
|
||||
static_cast<int>(elements_read) / num_channels,
|
||||
num_channels,
|
||||
buffer);
|
||||
return elements_read;
|
||||
}
|
||||
|
||||
size_t PcmReadToFloat(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
float* const* buffer) {
|
||||
CHECK_GE(num_channels, 1);
|
||||
|
||||
int num_frames = static_cast<int>(length) / num_channels;
|
||||
rtc::scoped_ptr<ChannelBuffer<int16_t> > deinterleaved_buffer(
|
||||
new ChannelBuffer<int16_t>(num_frames, num_channels));
|
||||
|
||||
size_t elements_read =
|
||||
PcmRead(file, length, num_channels, deinterleaved_buffer->channels());
|
||||
|
||||
for (int i = 0; i < num_channels; ++i) {
|
||||
S16ToFloat(deinterleaved_buffer->channels()[i], num_frames, buffer[i]);
|
||||
}
|
||||
return elements_read;
|
||||
}
|
||||
|
||||
void PcmWrite(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
const int16_t* const* buffer) {
|
||||
CHECK_GE(num_channels, 1);
|
||||
|
||||
rtc::scoped_ptr<int16_t[]> interleaved_buffer(new int16_t[length]);
|
||||
Interleave(buffer,
|
||||
static_cast<int>(length) / num_channels,
|
||||
num_channels,
|
||||
interleaved_buffer.get());
|
||||
CHECK_EQ(length,
|
||||
fwrite(interleaved_buffer.get(), sizeof(int16_t), length, file));
|
||||
}
|
||||
|
||||
void PcmWriteFromFloat(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
const float* const* buffer) {
|
||||
CHECK_GE(num_channels, 1);
|
||||
|
||||
int num_frames = static_cast<int>(length) / num_channels;
|
||||
rtc::scoped_ptr<ChannelBuffer<int16_t> > deinterleaved_buffer(
|
||||
new ChannelBuffer<int16_t>(num_frames, num_channels));
|
||||
|
||||
for (int i = 0; i < num_channels; ++i) {
|
||||
FloatToS16(buffer[i], num_frames, deinterleaved_buffer->channels()[i]);
|
||||
}
|
||||
PcmWrite(file, length, num_channels, deinterleaved_buffer->channels());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_PCM_UTILS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_PCM_UTILS_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Utilities for reading from and writing to multichannel pcm files.
|
||||
// Assumes a bit depth of 16 and little-endian. Note that in these functions,
|
||||
// length refers to the number of samples to read from/write to the file,
|
||||
// such that length / num_channels is the number of frames.
|
||||
namespace webrtc {
|
||||
|
||||
// Reads audio from a pcm into a 2D array: buffer[channel_index][frame_index].
|
||||
// Returns the number of frames written. If this is less than |length|, it's
|
||||
// safe to assume the end-of-file was reached, as otherwise this will crash.
|
||||
// In PcmReadToFloat, the floats are within the range [-1, 1].
|
||||
size_t PcmRead(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
int16_t* const* buffer);
|
||||
size_t PcmReadToFloat(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
float* const* buffer);
|
||||
|
||||
// Writes to a pcm file. The resulting file contains the channels interleaved.
|
||||
// Crashes if the correct number of frames aren't written to the file. For
|
||||
// PcmWriteFromFloat, floats must be within the range [-1, 1].
|
||||
void PcmWrite(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
const int16_t* const* buffer);
|
||||
void PcmWriteFromFloat(FILE* file,
|
||||
size_t length,
|
||||
int num_channels,
|
||||
const float* const* buffer);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_PCM_UTILS_H_
|
||||
@ -22,6 +22,7 @@
|
||||
#include "webrtc/modules/audio_processing/beamformer/mock_nonlinear_beamformer.h"
|
||||
#include "webrtc/modules/audio_processing/common.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
|
||||
#include "webrtc/modules/audio_processing/test/test_utils.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/interface/event_wrapper.h"
|
||||
|
||||
@ -18,17 +18,16 @@
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
|
||||
#include "webrtc/modules/audio_processing/test/test_utils.h"
|
||||
#include "webrtc/system_wrappers/interface/tick_util.h"
|
||||
|
||||
DEFINE_string(dump, "", "The name of the debug dump file to read from.");
|
||||
DEFINE_string(c, "", "The name of the capture input file to read from.");
|
||||
DEFINE_string(o, "out.wav", "Name of the capture output file to write to.");
|
||||
DEFINE_int32(o_channels, 0, "Number of output channels. Defaults to input.");
|
||||
DEFINE_int32(o_sample_rate, 0, "Output sample rate in Hz. Defaults to input.");
|
||||
DEFINE_double(mic_spacing, 0.0,
|
||||
"Alternate way to specify mic_positions. "
|
||||
"Assumes uniform linear array with specified spacings.");
|
||||
DEFINE_string(i, "", "The name of the input file to read from.");
|
||||
DEFINE_string(o, "out.wav", "Name of the output file to write to.");
|
||||
DEFINE_int32(out_channels, 0, "Number of output channels. Defaults to input.");
|
||||
DEFINE_int32(out_sample_rate, 0,
|
||||
"Output sample rate in Hz. Defaults to input.");
|
||||
DEFINE_string(mic_positions, "",
|
||||
"Space delimited cartesian coordinates of microphones in meters. "
|
||||
"The coordinates of each point are contiguous. "
|
||||
@ -46,8 +45,11 @@ DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");
|
||||
|
||||
DEFINE_bool(perf, false, "Enable performance tests.");
|
||||
|
||||
static const int kChunksPerSecond = 100;
|
||||
static const char kUsage[] =
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
const int kChunksPerSecond = 100;
|
||||
const char kUsage[] =
|
||||
"Command-line tool to run audio processing on WAV files. Accepts either\n"
|
||||
"an input capture WAV file or protobuf debug dump and writes to an output\n"
|
||||
"WAV file.\n"
|
||||
@ -55,76 +57,15 @@ static const char kUsage[] =
|
||||
"All components are disabled by default. If any bi-directional components\n"
|
||||
"are enabled, only debug dump files are permitted.";
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns a vector<T> parsed from whitespace delimited values in to_parse,
|
||||
// or an empty vector if the string could not be parsed.
|
||||
template<typename T>
|
||||
std::vector<T> parse_list(std::string to_parse) {
|
||||
std::vector<T> values;
|
||||
|
||||
std::istringstream str(to_parse);
|
||||
std::copy(
|
||||
std::istream_iterator<T>(str),
|
||||
std::istream_iterator<T>(),
|
||||
std::back_inserter(values));
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Parses the array geometry from the command line.
|
||||
//
|
||||
// If a vector with size != num_mics is returned, an error has occurred and an
|
||||
// appropriate error message has been printed to stdout.
|
||||
std::vector<Point> get_array_geometry(size_t num_mics) {
|
||||
std::vector<Point> result;
|
||||
result.reserve(num_mics);
|
||||
|
||||
if (FLAGS_mic_positions.length()) {
|
||||
CHECK(FLAGS_mic_spacing == 0.0 &&
|
||||
"mic_positions and mic_spacing should not both be specified");
|
||||
|
||||
const std::vector<float> values = parse_list<float>(FLAGS_mic_positions);
|
||||
if (values.size() != 3 * num_mics) {
|
||||
fprintf(stderr,
|
||||
"Could not parse mic_positions or incorrect number of points.\n");
|
||||
} else {
|
||||
for (size_t i = 0; i < values.size(); i += 3) {
|
||||
double x = values[i + 0];
|
||||
double y = values[i + 1];
|
||||
double z = values[i + 2];
|
||||
result.push_back(Point(x, y, z));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (FLAGS_mic_spacing <= 0) {
|
||||
fprintf(stderr,
|
||||
"mic_spacing must a positive value when beamforming is enabled.\n");
|
||||
} else {
|
||||
for (size_t i = 0; i < num_mics; ++i) {
|
||||
result.push_back(Point(i * FLAGS_mic_spacing, 0.f, 0.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
{
|
||||
const std::string program_name = argv[0];
|
||||
const std::string usage = kUsage;
|
||||
google::SetUsageMessage(usage);
|
||||
}
|
||||
google::SetUsageMessage(kUsage);
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!((FLAGS_c == "") ^ (FLAGS_dump == ""))) {
|
||||
if (!((FLAGS_i == "") ^ (FLAGS_dump == ""))) {
|
||||
fprintf(stderr,
|
||||
"An input file must be specified with either -c or -dump.\n");
|
||||
"An input file must be specified with either -i or -dump.\n");
|
||||
return 1;
|
||||
}
|
||||
if (FLAGS_dump != "") {
|
||||
@ -132,25 +73,22 @@ int main(int argc, char* argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
WavReader c_file(FLAGS_c);
|
||||
WavReader in_file(FLAGS_i);
|
||||
// If the output format is uninitialized, use the input format.
|
||||
int o_channels = FLAGS_o_channels;
|
||||
if (!o_channels)
|
||||
o_channels = c_file.num_channels();
|
||||
int o_sample_rate = FLAGS_o_sample_rate;
|
||||
if (!o_sample_rate)
|
||||
o_sample_rate = c_file.sample_rate();
|
||||
WavWriter o_file(FLAGS_o, o_sample_rate, o_channels);
|
||||
const int out_channels =
|
||||
FLAGS_out_channels ? FLAGS_out_channels : in_file.num_channels();
|
||||
const int out_sample_rate =
|
||||
FLAGS_out_sample_rate ? FLAGS_out_sample_rate : in_file.sample_rate();
|
||||
WavWriter out_file(FLAGS_o, out_sample_rate, out_channels);
|
||||
|
||||
Config config;
|
||||
config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
|
||||
|
||||
if (FLAGS_bf || FLAGS_all) {
|
||||
const size_t num_mics = c_file.num_channels();
|
||||
const std::vector<Point> array_geometry = get_array_geometry(num_mics);
|
||||
if (array_geometry.size() != num_mics) {
|
||||
return 1;
|
||||
}
|
||||
const size_t num_mics = in_file.num_channels();
|
||||
const std::vector<Point> array_geometry =
|
||||
ParseArrayGeometry(FLAGS_mic_positions, num_mics);
|
||||
CHECK_EQ(array_geometry.size(), num_mics);
|
||||
|
||||
config.Set<Beamforming>(new Beamforming(true, array_geometry));
|
||||
}
|
||||
@ -171,46 +109,49 @@ int main(int argc, char* argv[]) {
|
||||
static_cast<NoiseSuppression::Level>(FLAGS_ns_level)));
|
||||
|
||||
printf("Input file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
|
||||
FLAGS_c.c_str(), c_file.num_channels(), c_file.sample_rate());
|
||||
FLAGS_i.c_str(), in_file.num_channels(), in_file.sample_rate());
|
||||
printf("Output file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
|
||||
FLAGS_o.c_str(), o_file.num_channels(), o_file.sample_rate());
|
||||
FLAGS_o.c_str(), out_file.num_channels(), out_file.sample_rate());
|
||||
|
||||
ChannelBuffer<float> c_buf(c_file.sample_rate() / kChunksPerSecond,
|
||||
c_file.num_channels());
|
||||
ChannelBuffer<float> o_buf(o_file.sample_rate() / kChunksPerSecond,
|
||||
o_file.num_channels());
|
||||
ChannelBuffer<float> in_buf(
|
||||
rtc::CheckedDivExact(in_file.sample_rate(), kChunksPerSecond),
|
||||
in_file.num_channels());
|
||||
ChannelBuffer<float> out_buf(
|
||||
rtc::CheckedDivExact(out_file.sample_rate(), kChunksPerSecond),
|
||||
out_file.num_channels());
|
||||
|
||||
const size_t c_length =
|
||||
static_cast<size_t>(c_buf.num_channels() * c_buf.num_frames());
|
||||
const size_t o_length =
|
||||
static_cast<size_t>(o_buf.num_channels() * o_buf.num_frames());
|
||||
rtc::scoped_ptr<float[]> c_interleaved(new float[c_length]);
|
||||
rtc::scoped_ptr<float[]> o_interleaved(new float[o_length]);
|
||||
std::vector<float> in_interleaved(in_buf.size());
|
||||
std::vector<float> out_interleaved(out_buf.size());
|
||||
TickTime processing_start_time;
|
||||
TickInterval accumulated_time;
|
||||
int num_chunks = 0;
|
||||
while (c_file.ReadSamples(c_length, c_interleaved.get()) == c_length) {
|
||||
FloatS16ToFloat(c_interleaved.get(), c_length, c_interleaved.get());
|
||||
Deinterleave(c_interleaved.get(), c_buf.num_frames(),
|
||||
c_buf.num_channels(), c_buf.channels());
|
||||
while (in_file.ReadSamples(in_interleaved.size(),
|
||||
&in_interleaved[0]) == in_interleaved.size()) {
|
||||
FloatS16ToFloat(&in_interleaved[0], in_interleaved.size(),
|
||||
&in_interleaved[0]);
|
||||
Deinterleave(&in_interleaved[0], in_buf.num_frames(),
|
||||
in_buf.num_channels(), in_buf.channels());
|
||||
|
||||
if (FLAGS_perf) {
|
||||
processing_start_time = TickTime::Now();
|
||||
}
|
||||
CHECK_EQ(kNoErr,
|
||||
ap->ProcessStream(c_buf.channels(),
|
||||
c_buf.num_frames(),
|
||||
c_file.sample_rate(),
|
||||
LayoutFromChannels(c_buf.num_channels()),
|
||||
o_file.sample_rate(),
|
||||
LayoutFromChannels(o_buf.num_channels()),
|
||||
o_buf.channels()));
|
||||
ap->ProcessStream(in_buf.channels(),
|
||||
in_buf.num_frames(),
|
||||
in_file.sample_rate(),
|
||||
LayoutFromChannels(in_buf.num_channels()),
|
||||
out_file.sample_rate(),
|
||||
LayoutFromChannels(out_buf.num_channels()),
|
||||
out_buf.channels()));
|
||||
if (FLAGS_perf) {
|
||||
accumulated_time += TickTime::Now() - processing_start_time;
|
||||
}
|
||||
Interleave(o_buf.channels(), o_buf.num_frames(),
|
||||
o_buf.num_channels(), o_interleaved.get());
|
||||
FloatToFloatS16(o_interleaved.get(), o_length, o_interleaved.get());
|
||||
o_file.WriteSamples(o_interleaved.get(), o_length);
|
||||
|
||||
Interleave(out_buf.channels(), out_buf.num_frames(),
|
||||
out_buf.num_channels(), &out_interleaved[0]);
|
||||
FloatToFloatS16(&out_interleaved[0], out_interleaved.size(),
|
||||
&out_interleaved[0]);
|
||||
out_file.WriteSamples(&out_interleaved[0], out_interleaved.size());
|
||||
num_chunks++;
|
||||
}
|
||||
if (FLAGS_perf) {
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
|
||||
#include "webrtc/modules/audio_processing/test/test_utils.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
|
||||
@ -905,7 +906,7 @@ void void_main(int argc, char* argv[]) {
|
||||
// not reaching end-of-file.
|
||||
EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t),
|
||||
SEEK_CUR));
|
||||
break; // This is expected.
|
||||
break; // This is expected.
|
||||
}
|
||||
} else {
|
||||
ASSERT_EQ(size, read_count);
|
||||
@ -948,7 +949,7 @@ void void_main(int argc, char* argv[]) {
|
||||
}
|
||||
if (simulating) {
|
||||
if (read_count != size) {
|
||||
break; // This is expected.
|
||||
break; // This is expected.
|
||||
}
|
||||
|
||||
delay_ms = 0;
|
||||
@ -1040,8 +1041,7 @@ void void_main(int argc, char* argv[]) {
|
||||
size,
|
||||
output_wav_file.get(),
|
||||
output_raw_file.get());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
FAIL() << "Event " << event << " is unrecognized";
|
||||
}
|
||||
}
|
||||
@ -1136,8 +1136,7 @@ void void_main(int argc, char* argv[]) {
|
||||
} // namespace
|
||||
} // namespace webrtc
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char* argv[]) {
|
||||
webrtc::void_main(argc, argv);
|
||||
|
||||
// Optional, but removes memory leak noise from Valgrind.
|
||||
|
||||
42
webrtc/modules/audio_processing/test/protobuf_utils.cc
Normal file
42
webrtc/modules/audio_processing/test/protobuf_utils.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
size_t ReadMessageBytesFromFile(FILE* file, rtc::scoped_ptr<uint8_t[]>* bytes) {
|
||||
// The "wire format" for the size is little-endian. Assume we're running on
|
||||
// a little-endian machine.
|
||||
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#error "Need to convert messsage from little-endian."
|
||||
#endif
|
||||
int32_t size = 0;
|
||||
if (fread(&size, sizeof(size), 1, file) != 1)
|
||||
return 0;
|
||||
if (size <= 0)
|
||||
return 0;
|
||||
|
||||
bytes->reset(new uint8_t[size]);
|
||||
return fread(bytes->get(), sizeof((*bytes)[0]), size, file);
|
||||
}
|
||||
|
||||
// Returns true on success, false on error or end-of-file.
|
||||
bool ReadMessageFromFile(FILE* file, ::google::protobuf::MessageLite* msg) {
|
||||
rtc::scoped_ptr<uint8_t[]> bytes;
|
||||
size_t size = ReadMessageBytesFromFile(file, &bytes);
|
||||
if (!size)
|
||||
return false;
|
||||
|
||||
msg->Clear();
|
||||
return msg->ParseFromArray(bytes.get(), size);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
28
webrtc/modules/audio_processing/test/protobuf_utils.h
Normal file
28
webrtc/modules/audio_processing/test/protobuf_utils.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TEST_PROTOBUF_UTILS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_TEST_PROTOBUF_UTILS_H_
|
||||
|
||||
#include "webrtc/audio_processing/debug.pb.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Allocates new memory in the scoped_ptr to fit the raw message and returns the
|
||||
// number of bytes read.
|
||||
size_t ReadMessageBytesFromFile(FILE* file, rtc::scoped_ptr<uint8_t[]>* bytes);
|
||||
|
||||
// Returns true on success, false on error or end-of-file.
|
||||
bool ReadMessageFromFile(FILE* file, ::google::protobuf::MessageLite* msg);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TEST_PROTOBUF_UTILS_H_
|
||||
119
webrtc/modules/audio_processing/test/test_utils.cc
Normal file
119
webrtc/modules/audio_processing/test/test_utils.cc
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/modules/audio_processing/test/test_utils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
RawFile::RawFile(const std::string& filename)
|
||||
: file_handle_(fopen(filename.c_str(), "wb")) {}
|
||||
|
||||
RawFile::~RawFile() {
|
||||
fclose(file_handle_);
|
||||
}
|
||||
|
||||
void RawFile::WriteSamples(const int16_t* samples, size_t num_samples) {
|
||||
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#error "Need to convert samples to little-endian when writing to PCM file"
|
||||
#endif
|
||||
fwrite(samples, sizeof(*samples), num_samples, file_handle_);
|
||||
}
|
||||
|
||||
void RawFile::WriteSamples(const float* samples, size_t num_samples) {
|
||||
fwrite(samples, sizeof(*samples), num_samples, file_handle_);
|
||||
}
|
||||
|
||||
void WriteIntData(const int16_t* data,
|
||||
size_t length,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file) {
|
||||
if (wav_file) {
|
||||
wav_file->WriteSamples(data, length);
|
||||
}
|
||||
if (raw_file) {
|
||||
raw_file->WriteSamples(data, length);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteFloatData(const float* const* data,
|
||||
int samples_per_channel,
|
||||
int num_channels,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file) {
|
||||
size_t length = num_channels * samples_per_channel;
|
||||
rtc::scoped_ptr<float[]> buffer(new float[length]);
|
||||
Interleave(data, samples_per_channel, num_channels, buffer.get());
|
||||
if (raw_file) {
|
||||
raw_file->WriteSamples(buffer.get(), length);
|
||||
}
|
||||
// TODO(aluebs): Use ScaleToInt16Range() from audio_util
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
buffer[i] = buffer[i] > 0 ?
|
||||
buffer[i] * std::numeric_limits<int16_t>::max() :
|
||||
-buffer[i] * std::numeric_limits<int16_t>::min();
|
||||
}
|
||||
if (wav_file) {
|
||||
wav_file->WriteSamples(buffer.get(), length);
|
||||
}
|
||||
}
|
||||
|
||||
FILE* OpenFile(const std::string& filename, const char* mode) {
|
||||
FILE* file = fopen(filename.c_str(), mode);
|
||||
if (!file) {
|
||||
printf("Unable to open file %s\n", filename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
int SamplesFromRate(int rate) {
|
||||
return AudioProcessing::kChunkSizeMs * rate / 1000;
|
||||
}
|
||||
|
||||
void SetFrameSampleRate(AudioFrame* frame,
|
||||
int sample_rate_hz) {
|
||||
frame->sample_rate_hz_ = sample_rate_hz;
|
||||
frame->samples_per_channel_ = AudioProcessing::kChunkSizeMs *
|
||||
sample_rate_hz / 1000;
|
||||
}
|
||||
|
||||
AudioProcessing::ChannelLayout LayoutFromChannels(int num_channels) {
|
||||
switch (num_channels) {
|
||||
case 1:
|
||||
return AudioProcessing::kMono;
|
||||
case 2:
|
||||
return AudioProcessing::kStereo;
|
||||
default:
|
||||
assert(false);
|
||||
return AudioProcessing::kMono;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Point> ParseArrayGeometry(const std::string& mic_positions,
|
||||
size_t num_mics) {
|
||||
const std::vector<float> values = ParseList<float>(mic_positions);
|
||||
CHECK_EQ(values.size(), 3 * num_mics) <<
|
||||
"Could not parse mic_positions or incorrect number of points.";
|
||||
|
||||
std::vector<Point> result;
|
||||
result.reserve(num_mics);
|
||||
for (size_t i = 0; i < values.size(); i += 3) {
|
||||
double x = values[i + 0];
|
||||
double y = values[i + 1];
|
||||
double z = values[i + 2];
|
||||
result.push_back(Point(x, y, z));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace webrtc
|
||||
@ -8,13 +8,18 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <limits>
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TEST_TEST_UTILS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_TEST_TEST_UTILS_H_
|
||||
|
||||
#include "webrtc/audio_processing/debug.pb.h"
|
||||
#include <math.h>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
#include "webrtc/common_audio/include/audio_util.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
@ -24,84 +29,38 @@ namespace webrtc {
|
||||
static const AudioProcessing::Error kNoErr = AudioProcessing::kNoError;
|
||||
#define EXPECT_NOERR(expr) EXPECT_EQ(kNoErr, (expr))
|
||||
|
||||
class RawFile {
|
||||
class RawFile final {
|
||||
public:
|
||||
RawFile(const std::string& filename)
|
||||
: file_handle_(fopen(filename.c_str(), "wb")) {}
|
||||
explicit RawFile(const std::string& filename);
|
||||
~RawFile();
|
||||
|
||||
~RawFile() {
|
||||
fclose(file_handle_);
|
||||
}
|
||||
|
||||
void WriteSamples(const int16_t* samples, size_t num_samples) {
|
||||
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#error "Need to convert samples to little-endian when writing to PCM file"
|
||||
#endif
|
||||
fwrite(samples, sizeof(*samples), num_samples, file_handle_);
|
||||
}
|
||||
|
||||
void WriteSamples(const float* samples, size_t num_samples) {
|
||||
fwrite(samples, sizeof(*samples), num_samples, file_handle_);
|
||||
}
|
||||
void WriteSamples(const int16_t* samples, size_t num_samples);
|
||||
void WriteSamples(const float* samples, size_t num_samples);
|
||||
|
||||
private:
|
||||
FILE* file_handle_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RawFile);
|
||||
};
|
||||
|
||||
static inline void WriteIntData(const int16_t* data,
|
||||
size_t length,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file) {
|
||||
if (wav_file) {
|
||||
wav_file->WriteSamples(data, length);
|
||||
}
|
||||
if (raw_file) {
|
||||
raw_file->WriteSamples(data, length);
|
||||
}
|
||||
}
|
||||
void WriteIntData(const int16_t* data,
|
||||
size_t length,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file);
|
||||
|
||||
static inline void WriteFloatData(const float* const* data,
|
||||
size_t samples_per_channel,
|
||||
int num_channels,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file) {
|
||||
size_t length = num_channels * samples_per_channel;
|
||||
rtc::scoped_ptr<float[]> buffer(new float[length]);
|
||||
Interleave(data, samples_per_channel, num_channels, buffer.get());
|
||||
if (raw_file) {
|
||||
raw_file->WriteSamples(buffer.get(), length);
|
||||
}
|
||||
// TODO(aluebs): Use ScaleToInt16Range() from audio_util
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
buffer[i] = buffer[i] > 0 ?
|
||||
buffer[i] * std::numeric_limits<int16_t>::max() :
|
||||
-buffer[i] * std::numeric_limits<int16_t>::min();
|
||||
}
|
||||
if (wav_file) {
|
||||
wav_file->WriteSamples(buffer.get(), length);
|
||||
}
|
||||
}
|
||||
void WriteFloatData(const float* const* data,
|
||||
int samples_per_channel,
|
||||
int num_channels,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file);
|
||||
|
||||
// Exits on failure; do not use in unit tests.
|
||||
static inline FILE* OpenFile(const std::string& filename, const char* mode) {
|
||||
FILE* file = fopen(filename.c_str(), mode);
|
||||
if (!file) {
|
||||
printf("Unable to open file %s\n", filename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
FILE* OpenFile(const std::string& filename, const char* mode);
|
||||
|
||||
static inline int SamplesFromRate(int rate) {
|
||||
return AudioProcessing::kChunkSizeMs * rate / 1000;
|
||||
}
|
||||
int SamplesFromRate(int rate);
|
||||
|
||||
static inline void SetFrameSampleRate(AudioFrame* frame,
|
||||
int sample_rate_hz) {
|
||||
frame->sample_rate_hz_ = sample_rate_hz;
|
||||
frame->samples_per_channel_ = AudioProcessing::kChunkSizeMs *
|
||||
sample_rate_hz / 1000;
|
||||
}
|
||||
void SetFrameSampleRate(AudioFrame* frame,
|
||||
int sample_rate_hz);
|
||||
|
||||
template <typename T>
|
||||
void SetContainerFormat(int sample_rate_hz,
|
||||
@ -113,47 +72,7 @@ void SetContainerFormat(int sample_rate_hz,
|
||||
cb->reset(new ChannelBuffer<T>(frame->samples_per_channel_, num_channels));
|
||||
}
|
||||
|
||||
static inline AudioProcessing::ChannelLayout LayoutFromChannels(
|
||||
int num_channels) {
|
||||
switch (num_channels) {
|
||||
case 1:
|
||||
return AudioProcessing::kMono;
|
||||
case 2:
|
||||
return AudioProcessing::kStereo;
|
||||
default:
|
||||
assert(false);
|
||||
return AudioProcessing::kMono;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocates new memory in the scoped_ptr to fit the raw message and returns the
|
||||
// number of bytes read.
|
||||
static inline size_t ReadMessageBytesFromFile(
|
||||
FILE* file,
|
||||
rtc::scoped_ptr<uint8_t[]>* bytes) {
|
||||
// The "wire format" for the size is little-endian. Assume we're running on
|
||||
// a little-endian machine.
|
||||
int32_t size = 0;
|
||||
if (fread(&size, sizeof(size), 1, file) != 1)
|
||||
return 0;
|
||||
if (size <= 0)
|
||||
return 0;
|
||||
|
||||
bytes->reset(new uint8_t[size]);
|
||||
return fread(bytes->get(), sizeof((*bytes)[0]), size, file);
|
||||
}
|
||||
|
||||
// Returns true on success, false on error or end-of-file.
|
||||
static inline bool ReadMessageFromFile(FILE* file,
|
||||
::google::protobuf::MessageLite* msg) {
|
||||
rtc::scoped_ptr<uint8_t[]> bytes;
|
||||
size_t size = ReadMessageBytesFromFile(file, &bytes);
|
||||
if (!size)
|
||||
return false;
|
||||
|
||||
msg->Clear();
|
||||
return msg->ParseFromArray(bytes.get(), size);
|
||||
}
|
||||
AudioProcessing::ChannelLayout LayoutFromChannels(int num_channels);
|
||||
|
||||
template <typename T>
|
||||
float ComputeSNR(const T* ref, const T* test, int length, float* variance) {
|
||||
@ -177,4 +96,28 @@ float ComputeSNR(const T* ref, const T* test, int length, float* variance) {
|
||||
return snr;
|
||||
}
|
||||
|
||||
// Returns a vector<T> parsed from whitespace delimited values in to_parse,
|
||||
// or an empty vector if the string could not be parsed.
|
||||
template<typename T>
|
||||
std::vector<T> ParseList(const std::string& to_parse) {
|
||||
std::vector<T> values;
|
||||
|
||||
std::istringstream str(to_parse);
|
||||
std::copy(
|
||||
std::istream_iterator<T>(str),
|
||||
std::istream_iterator<T>(),
|
||||
std::back_inserter(values));
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Parses the array geometry from the command line.
|
||||
//
|
||||
// If a vector with size != num_mics is returned, an error has occurred and an
|
||||
// appropriate error message has been printed to stdout.
|
||||
std::vector<Point> ParseArrayGeometry(const std::string& mic_positions,
|
||||
size_t num_mics);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TEST_TEST_UTILS_H_
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "gflags/gflags.h"
|
||||
#include "webrtc/audio_processing/debug.pb.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
|
||||
#include "webrtc/modules/audio_processing/test/test_utils.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
|
||||
@ -59,6 +59,8 @@
|
||||
'audio_coding_module',
|
||||
'audio_device' ,
|
||||
'audio_processing',
|
||||
'audioproc_test_utils',
|
||||
'audioproc_protobuf_utils',
|
||||
'bitrate_controller',
|
||||
'bwe_simulator',
|
||||
'CNG',
|
||||
@ -173,8 +175,6 @@
|
||||
'audio_processing/beamformer/matrix_unittest.cc',
|
||||
'audio_processing/beamformer/mock_nonlinear_beamformer.cc',
|
||||
'audio_processing/beamformer/mock_nonlinear_beamformer.h',
|
||||
'audio_processing/beamformer/pcm_utils.cc',
|
||||
'audio_processing/beamformer/pcm_utils.h',
|
||||
'audio_processing/echo_cancellation_impl_unittest.cc',
|
||||
'audio_processing/splitting_filter_unittest.cc',
|
||||
'audio_processing/transient/dyadic_decimator_unittest.cc',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user