summaryrefslogtreecommitdiff
path: root/common_audio
diff options
context:
space:
mode:
Diffstat (limited to 'common_audio')
-rw-r--r--common_audio/BUILD.gn6
-rw-r--r--common_audio/audio_converter.cc16
-rw-r--r--common_audio/audio_converter.h4
-rw-r--r--common_audio/audio_util.cc22
-rw-r--r--common_audio/audio_util_unittest.cc48
-rw-r--r--common_audio/common_audio.gyp11
-rw-r--r--common_audio/common_audio_unittests.isolate7
-rw-r--r--common_audio/include/audio_util.h54
-rw-r--r--common_audio/resampler/push_sinc_resampler.cc2
-rw-r--r--common_audio/resampler/push_sinc_resampler_unittest.cc9
-rw-r--r--common_audio/signal_processing/complex_fft.c69
-rw-r--r--common_audio/signal_processing/division_operations.c15
-rw-r--r--common_audio/signal_processing/include/signal_processing_library.h1
-rw-r--r--common_audio/signal_processing/levinson_durbin.c58
-rw-r--r--common_audio/signal_processing/lpc_to_refl_coef.c4
-rw-r--r--common_audio/signal_processing/signal_processing_unittest.cc1
-rw-r--r--common_audio/signal_processing/spl_sqrt.c22
-rw-r--r--common_audio/signal_processing/splitting_filter.c10
-rw-r--r--common_audio/vad/include/vad.h45
-rw-r--r--common_audio/vad/mock/mock_vad.h34
-rw-r--r--common_audio/vad/vad.cc43
-rw-r--r--common_audio/wav_file.cc166
-rw-r--r--common_audio/wav_file.h98
-rw-r--r--common_audio/wav_file_unittest.cc (renamed from common_audio/wav_writer_unittest.cc)34
-rw-r--r--common_audio/wav_header.cc130
-rw-r--r--common_audio/wav_header.h14
-rw-r--r--common_audio/wav_header_unittest.cc90
-rw-r--r--common_audio/wav_writer.cc115
-rw-r--r--common_audio/wav_writer.h72
29 files changed, 812 insertions, 388 deletions
diff --git a/common_audio/BUILD.gn b/common_audio/BUILD.gn
index ad49d17f..ba1d1795 100644
--- a/common_audio/BUILD.gn
+++ b/common_audio/BUILD.gn
@@ -71,7 +71,9 @@ source_set("common_audio") {
"signal_processing/splitting_filter.c",
"signal_processing/sqrt_of_one_minus_x_squared.c",
"signal_processing/vector_scaling_operations.c",
+ "vad/include/vad.h",
"vad/include/webrtc_vad.h",
+ "vad/vad.cc",
"vad/webrtc_vad.c",
"vad/vad_core.c",
"vad/vad_core.h",
@@ -83,8 +85,8 @@ source_set("common_audio") {
"vad/vad_sp.h",
"wav_header.cc",
"wav_header.h",
- "wav_writer.cc",
- "wav_writer.h",
+ "wav_file.cc",
+ "wav_file.h",
"window_generator.cc",
"window_generator.h",
]
diff --git a/common_audio/audio_converter.cc b/common_audio/audio_converter.cc
index 9e18033f..f085ff13 100644
--- a/common_audio/audio_converter.cc
+++ b/common_audio/audio_converter.cc
@@ -43,10 +43,13 @@ void UpmixFromMono(const float* src,
} // namespace
AudioConverter::AudioConverter(int src_channels, int src_frames,
- int dst_channels, int dst_frames) {
+ int dst_channels, int dst_frames)
+ : src_channels_(src_channels),
+ src_frames_(src_frames),
+ dst_channels_(dst_channels),
+ dst_frames_(dst_frames) {
CHECK(dst_channels == src_channels || dst_channels == 1 || src_channels == 1);
- const int resample_channels = src_channels < dst_channels ? src_channels :
- dst_channels;
+ const int resample_channels = std::min(src_channels, dst_channels);
// Prepare buffers as needed for intermediate stages.
if (dst_channels < src_channels)
@@ -66,8 +69,11 @@ void AudioConverter::Convert(const float* const* src,
int dst_channels,
int dst_frames,
float* const* dst) {
- DCHECK(dst_channels == src_channels || dst_channels == 1 ||
- src_channels == 1);
+ DCHECK_EQ(src_channels_, src_channels);
+ DCHECK_EQ(src_frames_, src_frames);
+ DCHECK_EQ(dst_channels_, dst_channels);
+ DCHECK_EQ(dst_frames_, dst_frames);;
+
if (src_channels == dst_channels && src_frames == dst_frames) {
// Shortcut copy.
if (src != dst) {
diff --git a/common_audio/audio_converter.h b/common_audio/audio_converter.h
index df31755e..6365f587 100644
--- a/common_audio/audio_converter.h
+++ b/common_audio/audio_converter.h
@@ -40,6 +40,10 @@ class AudioConverter {
float* const* dest);
private:
+ const int src_channels_;
+ const int src_frames_;
+ const int dst_channels_;
+ const int dst_frames_;
scoped_ptr<ChannelBuffer<float>> downmix_buffer_;
ScopedVector<PushSincResampler> resamplers_;
diff --git a/common_audio/audio_util.cc b/common_audio/audio_util.cc
index f2936b07..2047295c 100644
--- a/common_audio/audio_util.cc
+++ b/common_audio/audio_util.cc
@@ -14,19 +14,29 @@
namespace webrtc {
-void RoundToInt16(const float* src, size_t size, int16_t* dest) {
+void FloatToS16(const float* src, size_t size, int16_t* dest) {
for (size_t i = 0; i < size; ++i)
- dest[i] = RoundToInt16(src[i]);
+ dest[i] = FloatToS16(src[i]);
}
-void ScaleAndRoundToInt16(const float* src, size_t size, int16_t* dest) {
+void S16ToFloat(const int16_t* src, size_t size, float* dest) {
for (size_t i = 0; i < size; ++i)
- dest[i] = ScaleAndRoundToInt16(src[i]);
+ dest[i] = S16ToFloat(src[i]);
}
-void ScaleToFloat(const int16_t* src, size_t size, float* dest) {
+void FloatS16ToS16(const float* src, size_t size, int16_t* dest) {
for (size_t i = 0; i < size; ++i)
- dest[i] = ScaleToFloat(src[i]);
+ dest[i] = FloatS16ToS16(src[i]);
+}
+
+void FloatToFloatS16(const float* src, size_t size, float* dest) {
+ for (size_t i = 0; i < size; ++i)
+ dest[i] = FloatToFloatS16(src[i]);
+}
+
+void FloatS16ToFloat(const float* src, size_t size, float* dest) {
+ for (size_t i = 0; i < size; ++i)
+ dest[i] = FloatS16ToFloat(src[i]);
}
} // namespace webrtc
diff --git a/common_audio/audio_util_unittest.cc b/common_audio/audio_util_unittest.cc
index bf9ad812..2cdf5381 100644
--- a/common_audio/audio_util_unittest.cc
+++ b/common_audio/audio_util_unittest.cc
@@ -26,35 +26,59 @@ void ExpectArraysEq(const float* ref, const float* test, int length) {
}
}
-TEST(AudioUtilTest, RoundToInt16) {
+TEST(AudioUtilTest, FloatToS16) {
+ const int kSize = 9;
+ const float kInput[kSize] = {
+ 0.f, 0.4f / 32767.f, 0.6f / 32767.f, -0.4f / 32768.f, -0.6f / 32768.f,
+ 1.f, -1.f, 1.1f, -1.1f};
+ const int16_t kReference[kSize] = {
+ 0, 0, 1, 0, -1, 32767, -32768, 32767, -32768};
+ int16_t output[kSize];
+ FloatToS16(kInput, kSize, output);
+ ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, S16ToFloat) {
+ const int kSize = 7;
+ const int16_t kInput[kSize] = {0, 1, -1, 16384, -16384, 32767, -32768};
+ const float kReference[kSize] = {
+ 0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f};
+ float output[kSize];
+ S16ToFloat(kInput, kSize, output);
+ ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, FloatS16ToS16) {
const int kSize = 7;
const float kInput[kSize] = {
0.f, 0.4f, 0.5f, -0.4f, -0.5f, 32768.f, -32769.f};
const int16_t kReference[kSize] = {0, 0, 1, 0, -1, 32767, -32768};
int16_t output[kSize];
- RoundToInt16(kInput, kSize, output);
+ FloatS16ToS16(kInput, kSize, output);
ExpectArraysEq(kReference, output, kSize);
}
-TEST(AudioUtilTest, ScaleAndRoundToInt16) {
+TEST(AudioUtilTest, FloatToFloatS16) {
const int kSize = 9;
const float kInput[kSize] = {
0.f, 0.4f / 32767.f, 0.6f / 32767.f, -0.4f / 32768.f, -0.6f / 32768.f,
1.f, -1.f, 1.1f, -1.1f};
- const int16_t kReference[kSize] = {
- 0, 0, 1, 0, -1, 32767, -32768, 32767, -32768};
- int16_t output[kSize];
- ScaleAndRoundToInt16(kInput, kSize, output);
+ const float kReference[kSize] = {
+ 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f};
+ float output[kSize];
+ FloatToFloatS16(kInput, kSize, output);
ExpectArraysEq(kReference, output, kSize);
}
-TEST(AudioUtilTest, ScaleToFloat) {
- const int kSize = 7;
- const int16_t kInput[kSize] = {0, 1, -1, 16384, -16384, 32767, -32768};
+TEST(AudioUtilTest, FloatS16ToFloat) {
+ const int kSize = 9;
+ const float kInput[kSize] = {
+ 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f};
const float kReference[kSize] = {
- 0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f};
+ 0.f, 0.4f / 32767.f, 0.6f / 32767.f, -0.4f / 32768.f, -0.6f / 32768.f,
+ 1.f, -1.f, 1.1f, -1.1f};
float output[kSize];
- ScaleToFloat(kInput, kSize, output);
+ FloatS16ToFloat(kInput, kSize, output);
ExpectArraysEq(kReference, output, kSize);
}
diff --git a/common_audio/common_audio.gyp b/common_audio/common_audio.gyp
index 6c1b7960..8f96674f 100644
--- a/common_audio/common_audio.gyp
+++ b/common_audio/common_audio.gyp
@@ -85,7 +85,9 @@
'signal_processing/splitting_filter.c',
'signal_processing/sqrt_of_one_minus_x_squared.c',
'signal_processing/vector_scaling_operations.c',
+ 'vad/include/vad.h',
'vad/include/webrtc_vad.h',
+ 'vad/vad.cc',
'vad/webrtc_vad.c',
'vad/vad_core.c',
'vad/vad_core.h',
@@ -97,8 +99,8 @@
'vad/vad_sp.h',
'wav_header.cc',
'wav_header.h',
- 'wav_writer.cc',
- 'wav_writer.h',
+ 'wav_file.cc',
+ 'wav_file.h',
'window_generator.cc',
'window_generator.h',
],
@@ -138,7 +140,7 @@
}],
], # conditions
}],
- ['target_arch=="mipsel"', {
+ ['target_arch=="mipsel" and mips_arch_variant!="r6"', {
'sources': [
'signal_processing/include/spl_inl_mips.h',
'signal_processing/complex_bit_reverse_mips.c',
@@ -243,7 +245,7 @@
'vad/vad_unittest.cc',
'vad/vad_unittest.h',
'wav_header_unittest.cc',
- 'wav_writer_unittest.cc',
+ 'wav_file_unittest.cc',
'window_generator_unittest.cc',
],
'conditions': [
@@ -283,7 +285,6 @@
],
'includes': [
'../build/isolate.gypi',
- 'common_audio_unittests.isolate',
],
'sources': [
'common_audio_unittests.isolate',
diff --git a/common_audio/common_audio_unittests.isolate b/common_audio/common_audio_unittests.isolate
index cc5e6ab4..80eb0fc4 100644
--- a/common_audio/common_audio_unittests.isolate
+++ b/common_audio/common_audio_unittests.isolate
@@ -9,7 +9,7 @@
'conditions': [
['OS=="android"', {
'variables': {
- 'isolate_dependency_untracked': [
+ 'files': [
'<(DEPTH)/data/',
'<(DEPTH)/resources/',
],
@@ -21,13 +21,10 @@
'<(DEPTH)/testing/test_env.py',
'<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
],
- 'isolate_dependency_tracked': [
+ 'files': [
'<(DEPTH)/testing/test_env.py',
'<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
],
- 'isolate_dependency_untracked': [
- '<(DEPTH)/tools/swarming_client/',
- ],
},
}],
],
diff --git a/common_audio/include/audio_util.h b/common_audio/include/audio_util.h
index 0ce034be..767b21c5 100644
--- a/common_audio/include/audio_util.h
+++ b/common_audio/include/audio_util.h
@@ -20,18 +20,11 @@ namespace webrtc {
typedef std::numeric_limits<int16_t> limits_int16;
-static inline int16_t RoundToInt16(float v) {
- const float kMaxRound = limits_int16::max() - 0.5f;
- const float kMinRound = limits_int16::min() + 0.5f;
- if (v > 0)
- return v >= kMaxRound ? limits_int16::max() :
- static_cast<int16_t>(v + 0.5f);
- return v <= kMinRound ? limits_int16::min() :
- static_cast<int16_t>(v - 0.5f);
-}
-
-// Scale (from [-1, 1]) and round to full-range int16 with clamping.
-static inline int16_t ScaleAndRoundToInt16(float v) {
+// The conversion functions use the following naming convention:
+// S16: int16_t [-32768, 32767]
+// Float: float [-1.0, 1.0]
+// FloatS16: float [-32768.0, 32767.0]
+static inline int16_t FloatToS16(float v) {
if (v > 0)
return v >= 1 ? limits_int16::max() :
static_cast<int16_t>(v * limits_int16::max() + 0.5f);
@@ -39,22 +32,37 @@ static inline int16_t ScaleAndRoundToInt16(float v) {
static_cast<int16_t>(-v * limits_int16::min() - 0.5f);
}
-// Scale to float [-1, 1].
-static inline float ScaleToFloat(int16_t v) {
- const float kMaxInt16Inverse = 1.f / limits_int16::max();
- const float kMinInt16Inverse = 1.f / limits_int16::min();
+static inline float S16ToFloat(int16_t v) {
+ static const float kMaxInt16Inverse = 1.f / limits_int16::max();
+ static const float kMinInt16Inverse = 1.f / limits_int16::min();
return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
}
-// Round |size| elements of |src| to int16 with clamping and write to |dest|.
-void RoundToInt16(const float* src, size_t size, int16_t* dest);
+static inline int16_t FloatS16ToS16(float v) {
+ static const float kMaxRound = limits_int16::max() - 0.5f;
+ static const float kMinRound = limits_int16::min() + 0.5f;
+ if (v > 0)
+ return v >= kMaxRound ? limits_int16::max() :
+ static_cast<int16_t>(v + 0.5f);
+ return v <= kMinRound ? limits_int16::min() :
+ static_cast<int16_t>(v - 0.5f);
+}
-// Scale (from [-1, 1]) and round |size| elements of |src| to full-range int16
-// with clamping and write to |dest|.
-void ScaleAndRoundToInt16(const float* src, size_t size, int16_t* dest);
+static inline float FloatToFloatS16(float v) {
+ return v * (v > 0 ? limits_int16::max() : -limits_int16::min());
+}
+
+static inline float FloatS16ToFloat(float v) {
+ static const float kMaxInt16Inverse = 1.f / limits_int16::max();
+ static const float kMinInt16Inverse = 1.f / limits_int16::min();
+ return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
+}
-// Scale |size| elements of |src| to float [-1, 1] and write to |dest|.
-void ScaleToFloat(const int16_t* src, size_t size, float* dest);
+void FloatToS16(const float* src, size_t size, int16_t* dest);
+void S16ToFloat(const int16_t* src, size_t size, float* dest);
+void FloatS16ToS16(const float* src, size_t size, int16_t* dest);
+void FloatToFloatS16(const float* src, size_t size, float* dest);
+void FloatS16ToFloat(const float* src, size_t size, float* dest);
// Deinterleave audio from |interleaved| to the channel buffers pointed to
// by |deinterleaved|. There must be sufficient space allocated in the
diff --git a/common_audio/resampler/push_sinc_resampler.cc b/common_audio/resampler/push_sinc_resampler.cc
index 02755590..49e2e12e 100644
--- a/common_audio/resampler/push_sinc_resampler.cc
+++ b/common_audio/resampler/push_sinc_resampler.cc
@@ -40,7 +40,7 @@ int PushSincResampler::Resample(const int16_t* source,
source_ptr_int_ = source;
// Pass NULL as the float source to have Run() read from the int16 source.
Resample(NULL, source_length, float_buffer_.get(), destination_frames_);
- RoundToInt16(float_buffer_.get(), destination_frames_, destination);
+ FloatS16ToS16(float_buffer_.get(), destination_frames_, destination);
source_ptr_int_ = NULL;
return destination_frames_;
}
diff --git a/common_audio/resampler/push_sinc_resampler_unittest.cc b/common_audio/resampler/push_sinc_resampler_unittest.cc
index 1ca4fdf9..90ac0cf0 100644
--- a/common_audio/resampler/push_sinc_resampler_unittest.cc
+++ b/common_audio/resampler/push_sinc_resampler_unittest.cc
@@ -160,16 +160,15 @@ void PushSincResamplerTest::ResampleTest(bool int_format) {
resampler_source.Run(input_samples, source.get());
if (int_format) {
for (int i = 0; i < kNumBlocks; ++i) {
- ScaleAndRoundToInt16(
- &source[i * input_block_size], input_block_size, source_int.get());
+ FloatToS16(&source[i * input_block_size], input_block_size,
+ source_int.get());
EXPECT_EQ(output_block_size,
resampler.Resample(source_int.get(),
input_block_size,
destination_int.get(),
output_block_size));
- ScaleToFloat(destination_int.get(),
- output_block_size,
- &resampled_destination[i * output_block_size]);
+ S16ToFloat(destination_int.get(), output_block_size,
+ &resampled_destination[i * output_block_size]);
}
} else {
for (int i = 0; i < kNumBlocks; ++i) {
diff --git a/common_audio/signal_processing/complex_fft.c b/common_audio/signal_processing/complex_fft.c
index c8230647..74b4258a 100644
--- a/common_audio/signal_processing/complex_fft.c
+++ b/common_audio/signal_processing/complex_fft.c
@@ -65,18 +65,16 @@ int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode)
{
j = i + l;
- tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
- - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1])), 15);
+ tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
- ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
- + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j])), 15);
+ ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
qr32 = (int32_t)frfi[2 * i];
qi32 = (int32_t)frfi[2 * i + 1];
- frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, 1);
- frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, 1);
- frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, 1);
- frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, 1);
+ frfi[2 * j] = (int16_t)((qr32 - tr32) >> 1);
+ frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> 1);
+ frfi[2 * i] = (int16_t)((qr32 + tr32) >> 1);
+ frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> 1);
}
}
@@ -135,20 +133,20 @@ int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode)
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND;
#endif
- tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CFFTSFT);
- ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CFFTSFT);
+ tr32 >>= 15 - CFFTSFT;
+ ti32 >>= 15 - CFFTSFT;
qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
- frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
- (qr32 - tr32 + CFFTRND2), 1 + CFFTSFT);
- frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
- (qi32 - ti32 + CFFTRND2), 1 + CFFTSFT);
- frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
- (qr32 + tr32 + CFFTRND2), 1 + CFFTSFT);
- frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
- (qi32 + ti32 + CFFTRND2), 1 + CFFTSFT);
+ frfi[2 * j] = (int16_t)(
+ (qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT));
+ frfi[2 * j + 1] = (int16_t)(
+ (qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT));
+ frfi[2 * i] = (int16_t)(
+ (qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT));
+ frfi[2 * i + 1] = (int16_t)(
+ (qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT));
}
}
@@ -219,19 +217,16 @@ int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
{
j = i + l;
- tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0)
- - WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15);
+ tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
- ti32 = WEBRTC_SPL_RSHIFT_W32(
- (WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0)
- + WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15);
+ ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
qr32 = (int32_t)frfi[2 * i];
qi32 = (int32_t)frfi[2 * i + 1];
- frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift);
- frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift);
- frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift);
- frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift);
+ frfi[2 * j] = (int16_t)((qr32 - tr32) >> shift);
+ frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> shift);
+ frfi[2 * i] = (int16_t)((qr32 + tr32) >> shift);
+ frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> shift);
}
}
} else
@@ -281,20 +276,20 @@ int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CIFFTRND;
#endif
- tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CIFFTSFT);
- ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CIFFTSFT);
+ tr32 >>= 15 - CIFFTSFT;
+ ti32 >>= 15 - CIFFTSFT;
qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
- frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2),
- shift+CIFFTSFT);
- frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
- (qi32 - ti32 + round2), shift + CIFFTSFT);
- frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2),
- shift + CIFFTSFT);
- frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
- (qi32 + ti32 + round2), shift + CIFFTSFT);
+ frfi[2 * j] = (int16_t)(
+ (qr32 - tr32 + round2) >> (shift + CIFFTSFT));
+ frfi[2 * j + 1] = (int16_t)(
+ (qi32 - ti32 + round2) >> (shift + CIFFTSFT));
+ frfi[2 * i] = (int16_t)(
+ (qr32 + tr32 + round2) >> (shift + CIFFTSFT));
+ frfi[2 * i + 1] = (int16_t)(
+ (qi32 + ti32 + round2) >> (shift + CIFFTSFT));
}
}
diff --git a/common_audio/signal_processing/division_operations.c b/common_audio/signal_processing/division_operations.c
index e9554f44..6aeb0fb2 100644
--- a/common_audio/signal_processing/division_operations.c
+++ b/common_audio/signal_processing/division_operations.c
@@ -113,23 +113,20 @@ int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
// Store tmpW32 in hi and low format
- tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
- tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+ tmp_hi = (int16_t)(tmpW32 >> 16);
+ tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
// tmpW32 = 1/den in Q29
tmpW32 = ((WEBRTC_SPL_MUL_16_16(tmp_hi, approx) + (WEBRTC_SPL_MUL_16_16(tmp_low, approx)
>> 15)) << 1);
// 1/den in hi and low format
- tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
- tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+ tmp_hi = (int16_t)(tmpW32 >> 16);
+ tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);
// Store num in hi and low format
- num_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(num, 16);
- num_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((num
- - WEBRTC_SPL_LSHIFT_W32((int32_t)num_hi, 16)), 1);
+ num_hi = (int16_t)(num >> 16);
+ num_low = (int16_t)((num - ((int32_t)num_hi << 16)) >> 1);
// num * (1/den) by 32 bit multiplication (result in Q28)
diff --git a/common_audio/signal_processing/include/signal_processing_library.h b/common_audio/signal_processing/include/signal_processing_library.h
index d13973ca..2bdfc23c 100644
--- a/common_audio/signal_processing/include/signal_processing_library.h
+++ b/common_audio/signal_processing/include/signal_processing_library.h
@@ -87,7 +87,6 @@
// Shifting with negative numbers not allowed
// We cannot do casting here due to signed/unsigned problem
-#define WEBRTC_SPL_RSHIFT_W32(x, c) ((x) >> (c))
#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c))
#define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c))
diff --git a/common_audio/signal_processing/levinson_durbin.c b/common_audio/signal_processing/levinson_durbin.c
index 5c5d2246..29f2398d 100644
--- a/common_audio/signal_processing/levinson_durbin.c
+++ b/common_audio/signal_processing/levinson_durbin.c
@@ -45,9 +45,8 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
{
temp1W32 = WEBRTC_SPL_LSHIFT_W32(R[i], norm);
// Put R in hi and low format
- R_hi[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- R_low[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[i], 16)), 1);
+ R_hi[i] = (int16_t)(temp1W32 >> 16);
+ R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] << 16)) >> 1);
}
// K = A[1] = -R[1] / R[0]
@@ -63,19 +62,17 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
}
// Put K in hi and low format
- K_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- K_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)K_hi, 16)), 1);
+ K_hi = (int16_t)(temp1W32 >> 16);
+ K_low = (int16_t)((temp1W32 - ((int32_t)K_hi << 16)) >> 1);
// Store first reflection coefficient
K[0] = K_hi;
- temp1W32 = WEBRTC_SPL_RSHIFT_W32(temp1W32, 4); // A[1] in Q27
+ temp1W32 >>= 4; // A[1] in Q27.
// Put A[1] in hi and low format
- A_hi[1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- A_low[1] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[1], 16)), 1);
+ A_hi[1] = (int16_t)(temp1W32 >> 16);
+ A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] << 16)) >> 1);
// Alpha = R[0] * (1-K^2)
@@ -86,9 +83,8 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
temp1W32 = (int32_t)0x7fffffffL - temp1W32; // temp1W32 = (1 - K[0]*K[0]) in Q31
// Store temp1W32 = 1 - K[0]*K[0] on hi and low format
- tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+ tmp_hi = (int16_t)(temp1W32 >> 16);
+ tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
// Calculate Alpha in Q31
temp1W32 = ((WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_hi)
@@ -99,9 +95,8 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
Alpha_exp = WebRtcSpl_NormW32(temp1W32);
temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp);
- Alpha_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- Alpha_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)Alpha_hi, 16)), 1);
+ Alpha_hi = (int16_t)(temp1W32 >> 16);
+ Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
// Perform the iterative calculations in the Levinson-Durbin algorithm
@@ -155,9 +150,8 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
}
// Put K on hi and low format
- K_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp3W32, 16);
- K_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp3W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)K_hi, 16)), 1);
+ K_hi = (int16_t)(temp3W32 >> 16);
+ K_low = (int16_t)((temp3W32 - ((int32_t)K_hi << 16)) >> 1);
// Store Reflection coefficient in Q15
K[i - 1] = K_hi;
@@ -188,18 +182,18 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
+ (WEBRTC_SPL_MUL_16_16(K_low, A_hi[i-j]) >> 15)) << 1);
// Put Anew in hi and low format
- A_upd_hi[j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- A_upd_low[j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)A_upd_hi[j], 16)), 1);
+ A_upd_hi[j] = (int16_t)(temp1W32 >> 16);
+ A_upd_low[j] = (int16_t)(
+ (temp1W32 - ((int32_t)A_upd_hi[j] << 16)) >> 1);
}
// temp3W32 = K in Q27 (Convert from Q31 to Q27)
- temp3W32 = WEBRTC_SPL_RSHIFT_W32(temp3W32, 4);
+ temp3W32 >>= 4;
// Store Anew in hi and low format
- A_upd_hi[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp3W32, 16);
- A_upd_low[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp3W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)A_upd_hi[i], 16)), 1);
+ A_upd_hi[i] = (int16_t)(temp3W32 >> 16);
+ A_upd_low[i] = (int16_t)(
+ (temp3W32 - ((int32_t)A_upd_hi[i] << 16)) >> 1);
// Alpha = Alpha * (1-K^2)
@@ -210,9 +204,8 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
temp1W32 = (int32_t)0x7fffffffL - temp1W32; // 1 - K*K in Q31
// Convert 1- K^2 in hi and low format
- tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
+ tmp_hi = (int16_t)(temp1W32 >> 16);
+ tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1);
// Calculate Alpha = Alpha * (1-K^2) in Q31
temp1W32 = ((WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_hi)
@@ -224,9 +217,8 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
norm = WebRtcSpl_NormW32(temp1W32);
temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm);
- Alpha_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(temp1W32, 16);
- Alpha_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32
- - WEBRTC_SPL_LSHIFT_W32((int32_t)Alpha_hi, 16)), 1);
+ Alpha_hi = (int16_t)(temp1W32 >> 16);
+ Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1);
// Update the total normalization of Alpha
Alpha_exp = Alpha_exp + norm;
@@ -253,7 +245,7 @@ int16_t WebRtcSpl_LevinsonDurbin(int32_t *R, int16_t *A, int16_t *K,
temp1W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[i], 16)
+ WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1);
// Round and store upper word
- A[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((temp1W32<<1)+(int32_t)32768, 16);
+ A[i] = (int16_t)(((temp1W32 << 1) + 32768) >> 16);
}
return 1; // Stable filters
}
diff --git a/common_audio/signal_processing/lpc_to_refl_coef.c b/common_audio/signal_processing/lpc_to_refl_coef.c
index b1a34d48..5fb4d859 100644
--- a/common_audio/signal_processing/lpc_to_refl_coef.c
+++ b/common_audio/signal_processing/lpc_to_refl_coef.c
@@ -32,7 +32,7 @@ void WebRtcSpl_LpcToReflCoef(int16_t* a16, int use_order, int16_t* k16)
// (1 - k^2) in Q30
tmp_inv_denom32 = ((int32_t)1073741823) - WEBRTC_SPL_MUL_16_16(k16[m], k16[m]);
// (1 - k^2) in Q15
- tmp_inv_denom16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp_inv_denom32, 15);
+ tmp_inv_denom16 = (int16_t)(tmp_inv_denom32 >> 15);
for (k = 1; k <= m; k++)
{
@@ -47,7 +47,7 @@ void WebRtcSpl_LpcToReflCoef(int16_t* a16, int use_order, int16_t* k16)
for (k = 1; k < m; k++)
{
- a16[k] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32[k], 1); //Q13>>1 => Q12
+ a16[k] = (int16_t)(tmp32[k] >> 1); // Q13>>1 => Q12
}
tmp32[m] = WEBRTC_SPL_SAT(8191, tmp32[m], -8191);
diff --git a/common_audio/signal_processing/signal_processing_unittest.cc b/common_audio/signal_processing/signal_processing_unittest.cc
index aa1f1787..611d2bfa 100644
--- a/common_audio/signal_processing/signal_processing_unittest.cc
+++ b/common_audio/signal_processing/signal_processing_unittest.cc
@@ -65,7 +65,6 @@ TEST_F(SplTest, MacroTest) {
// Shifting with negative numbers not allowed
// We cannot do casting here due to signed/unsigned problem
- EXPECT_EQ(8191, WEBRTC_SPL_RSHIFT_W32(a, 1));
EXPECT_EQ(32766, WEBRTC_SPL_LSHIFT_W32(a, 1));
EXPECT_EQ(8191u, WEBRTC_SPL_RSHIFT_U32(a, 1));
diff --git a/common_audio/signal_processing/spl_sqrt.c b/common_audio/signal_processing/spl_sqrt.c
index fff73c03..1de6ccd7 100644
--- a/common_audio/signal_processing/spl_sqrt.c
+++ b/common_audio/signal_processing/spl_sqrt.c
@@ -35,11 +35,10 @@ int32_t WebRtcSpl_SqrtLocal(int32_t in)
+ 0.875*((x_half)^5)
*/
- B = in;
+ B = in / 2;
- B = WEBRTC_SPL_RSHIFT_W32(B, 1); // B = in/2
B = B - ((int32_t)0x40000000); // B = in/2 - 1/2
- x_half = (int16_t)WEBRTC_SPL_RSHIFT_W32(B, 16);// x_half = x/2 = (in-1)/2
+ x_half = (int16_t)(B >> 16); // x_half = x/2 = (in-1)/2
B = B + ((int32_t)0x40000000); // B = 1 + x/2
B = B + ((int32_t)0x40000000); // Add 0.5 twice (since 1.0 does not exist in Q31)
@@ -47,19 +46,18 @@ int32_t WebRtcSpl_SqrtLocal(int32_t in)
A = -x2; // A = -(x/2)^2
B = B + (A >> 1); // B = 1 + x/2 - 0.5*(x/2)^2
- A = WEBRTC_SPL_RSHIFT_W32(A, 16);
+ A >>= 16;
A = A * A * 2; // A = (x/2)^4
- t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
+ t16 = (int16_t)(A >> 16);
B = B + WEBRTC_SPL_MUL_16_16(-20480, t16) * 2; // B = B - 0.625*A
// After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4
- t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = (x/2)^5
- t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
+ t16 = (int16_t)(A >> 16);
B = B + WEBRTC_SPL_MUL_16_16(28672, t16) * 2; // B = B + 0.875*A
// After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + 0.875*(x/2)^5
- t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(x2, 16);
+ t16 = (int16_t)(x2 >> 16);
A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = x/2^3
B = B + (A >> 1); // B = B + 0.5*A
@@ -154,7 +152,7 @@ int32_t WebRtcSpl_Sqrt(int32_t value)
A = WEBRTC_SPL_WORD32_MAX;
}
- x_norm = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16); // x_norm = AH
+ x_norm = (int16_t)(A >> 16); // x_norm = AH
nshift = (sh / 2);
assert(nshift >= 0);
@@ -166,17 +164,17 @@ int32_t WebRtcSpl_Sqrt(int32_t value)
if (2 * nshift == sh) {
// Even shift value case
- t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16); // t16 = AH
+ t16 = (int16_t)(A >> 16); // t16 = AH
A = WEBRTC_SPL_MUL_16_16(k_sqrt_2, t16) * 2; // A = 1/sqrt(2)*t16
A = A + ((int32_t)32768); // Round off
A = A & ((int32_t)0x7fff0000); // Round off
- A = WEBRTC_SPL_RSHIFT_W32(A, 15); // A = A>>16
+ A >>= 15; // A = A>>16
} else
{
- A = WEBRTC_SPL_RSHIFT_W32(A, 16); // A = A>>16
+ A >>= 16; // A = A>>16
}
A = A & ((int32_t)0x0000ffff);
diff --git a/common_audio/signal_processing/splitting_filter.c b/common_audio/signal_processing/splitting_filter.c
index 4f6430c2..15c37240 100644
--- a/common_audio/signal_processing/splitting_filter.c
+++ b/common_audio/signal_processing/splitting_filter.c
@@ -156,12 +156,10 @@ void WebRtcSpl_AnalysisQMF(const int16_t* in_data, int in_data_length,
// branches to get upper & lower band.
for (i = 0; i < band_length; i++)
{
- tmp = filter1[i] + filter2[i] + 1024;
- tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11);
+ tmp = (filter1[i] + filter2[i] + 1024) >> 11;
low_band[i] = WebRtcSpl_SatW32ToW16(tmp);
- tmp = filter1[i] - filter2[i] + 1024;
- tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11);
+ tmp = (filter1[i] - filter2[i] + 1024) >> 11;
high_band[i] = WebRtcSpl_SatW32ToW16(tmp);
}
}
@@ -200,10 +198,10 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band,
// saturation.
for (i = 0, k = 0; i < band_length; i++)
{
- tmp = WEBRTC_SPL_RSHIFT_W32(filter2[i] + 512, 10);
+ tmp = (filter2[i] + 512) >> 10;
out_data[k++] = WebRtcSpl_SatW32ToW16(tmp);
- tmp = WEBRTC_SPL_RSHIFT_W32(filter1[i] + 512, 10);
+ tmp = (filter1[i] + 512) >> 10;
out_data[k++] = WebRtcSpl_SatW32ToW16(tmp);
}
diff --git a/common_audio/vad/include/vad.h b/common_audio/vad/include/vad.h
new file mode 100644
index 00000000..f1d12123
--- /dev/null
+++ b/common_audio/vad/include/vad.h
@@ -0,0 +1,45 @@
+/*
+ * 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_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/vad/include/webrtc_vad.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+// This is a C++ wrapper class for WebRtcVad.
+class Vad {
+ public:
+ enum Aggressiveness {
+ kVadNormal = 0,
+ kVadLowBitrate = 1,
+ kVadAggressive = 2,
+ kVadVeryAggressive = 3
+ };
+
+ enum Activity { kPassive = 0, kActive = 1, kError = -1 };
+
+ explicit Vad(enum Aggressiveness mode);
+
+ virtual ~Vad();
+
+ enum Activity VoiceActivity(const int16_t* audio,
+ size_t num_samples,
+ int sample_rate_hz);
+
+ private:
+ VadInst* handle_;
+};
+
+} // namespace webrtc
+#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
diff --git a/common_audio/vad/mock/mock_vad.h b/common_audio/vad/mock/mock_vad.h
new file mode 100644
index 00000000..f1d8c226
--- /dev/null
+++ b/common_audio/vad/mock/mock_vad.h
@@ -0,0 +1,34 @@
+/*
+ * 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_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
+#define WEBRTC_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
+
+#include "webrtc/common_audio/vad/include/vad.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace webrtc {
+
+class MockVad : public Vad {
+ public:
+ explicit MockVad(enum Aggressiveness mode) {}
+ virtual ~MockVad() { Die(); }
+ MOCK_METHOD0(Die, void());
+
+ MOCK_METHOD3(VoiceActivity,
+ enum Activity(const int16_t* audio,
+ size_t num_samples,
+ int sample_rate_hz));
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
diff --git a/common_audio/vad/vad.cc b/common_audio/vad/vad.cc
new file mode 100644
index 00000000..9cc0c198
--- /dev/null
+++ b/common_audio/vad/vad.cc
@@ -0,0 +1,43 @@
+/*
+ * 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/common_audio/vad/include/vad.h"
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+Vad::Vad(enum Aggressiveness mode) {
+ CHECK_EQ(WebRtcVad_Create(&handle_), 0);
+ CHECK_EQ(WebRtcVad_Init(handle_), 0);
+ CHECK_EQ(WebRtcVad_set_mode(handle_, mode), 0);
+}
+
+Vad::~Vad() {
+ WebRtcVad_Free(handle_);
+}
+
+enum Vad::Activity Vad::VoiceActivity(const int16_t* audio,
+ size_t num_samples,
+ int sample_rate_hz) {
+ int ret = WebRtcVad_Process(
+ handle_, sample_rate_hz, audio, static_cast<int>(num_samples));
+ switch (ret) {
+ case 0:
+ return kPassive;
+ case 1:
+ return kActive;
+ default:
+ DCHECK(false) << "WebRtcVad_Process returned an error.";
+ return kError;
+ }
+}
+
+} // namespace webrtc
diff --git a/common_audio/wav_file.cc b/common_audio/wav_file.cc
new file mode 100644
index 00000000..880e1ec4
--- /dev/null
+++ b/common_audio/wav_file.cc
@@ -0,0 +1,166 @@
+/*
+ * 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/common_audio/wav_file.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <limits>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/include/audio_util.h"
+#include "webrtc/common_audio/wav_header.h"
+
+namespace webrtc {
+
+// We write 16-bit PCM WAV files.
+static const WavFormat kWavFormat = kWavFormatPcm;
+static const int kBytesPerSample = 2;
+
+WavReader::WavReader(const std::string& filename)
+ : file_handle_(fopen(filename.c_str(), "rb")) {
+ CHECK(file_handle_);
+ uint8_t header[kWavHeaderSize];
+ const size_t read =
+ fread(header, sizeof(*header), kWavHeaderSize, file_handle_);
+ CHECK_EQ(kWavHeaderSize, read);
+
+ WavFormat format;
+ int bytes_per_sample;
+ CHECK(ReadWavHeader(header, &num_channels_, &sample_rate_, &format,
+ &bytes_per_sample, &num_samples_));
+ CHECK_EQ(kWavFormat, format);
+ CHECK_EQ(kBytesPerSample, bytes_per_sample);
+}
+
+WavReader::~WavReader() {
+ Close();
+}
+
+size_t WavReader::ReadSamples(size_t num_samples, int16_t* samples) {
+#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
+#error "Need to convert samples to big-endian when reading from WAV file"
+#endif
+ const size_t read =
+ fread(samples, sizeof(*samples), num_samples, file_handle_);
+ // If we didn't read what was requested, ensure we've reached the EOF.
+ CHECK(read == num_samples || feof(file_handle_));
+ return read;
+}
+
+size_t WavReader::ReadSamples(size_t num_samples, float* samples) {
+ static const size_t kChunksize = 4096 / sizeof(uint16_t);
+ size_t read = 0;
+ for (size_t i = 0; i < num_samples; i += kChunksize) {
+ int16_t isamples[kChunksize];
+ size_t chunk = std::min(kChunksize, num_samples - i);
+ chunk = ReadSamples(chunk, isamples);
+ for (size_t j = 0; j < chunk; ++j)
+ samples[i + j] = isamples[j];
+ read += chunk;
+ }
+ return read;
+}
+
+void WavReader::Close() {
+ CHECK_EQ(0, fclose(file_handle_));
+ file_handle_ = NULL;
+}
+
+WavWriter::WavWriter(const std::string& filename, int sample_rate,
+ int num_channels)
+ : sample_rate_(sample_rate),
+ num_channels_(num_channels),
+ num_samples_(0),
+ file_handle_(fopen(filename.c_str(), "wb")) {
+ CHECK(file_handle_);
+ CHECK(CheckWavParameters(num_channels_,
+ sample_rate_,
+ kWavFormat,
+ kBytesPerSample,
+ num_samples_));
+
+ // Write a blank placeholder header, since we need to know the total number
+ // of samples before we can fill in the real data.
+ static const uint8_t blank_header[kWavHeaderSize] = {0};
+ CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
+}
+
+WavWriter::~WavWriter() {
+ Close();
+}
+
+void WavWriter::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 WAV file"
+#endif
+ const size_t written =
+ fwrite(samples, sizeof(*samples), num_samples, file_handle_);
+ CHECK_EQ(num_samples, written);
+ num_samples_ += static_cast<uint32_t>(written);
+ CHECK(written <= std::numeric_limits<uint32_t>::max() ||
+ num_samples_ >= written); // detect uint32_t overflow
+ CHECK(CheckWavParameters(num_channels_,
+ sample_rate_,
+ kWavFormat,
+ kBytesPerSample,
+ num_samples_));
+}
+
+void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
+ static const size_t kChunksize = 4096 / sizeof(uint16_t);
+ for (size_t i = 0; i < num_samples; i += kChunksize) {
+ int16_t isamples[kChunksize];
+ const size_t chunk = std::min(kChunksize, num_samples - i);
+ FloatS16ToS16(samples + i, chunk, isamples);
+ WriteSamples(isamples, chunk);
+ }
+}
+
+void WavWriter::Close() {
+ CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
+ uint8_t header[kWavHeaderSize];
+ WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
+ kBytesPerSample, num_samples_);
+ CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
+ CHECK_EQ(0, fclose(file_handle_));
+ file_handle_ = NULL;
+}
+
+} // namespace webrtc
+
+rtc_WavWriter* rtc_WavOpen(const char* filename,
+ int sample_rate,
+ int num_channels) {
+ return reinterpret_cast<rtc_WavWriter*>(
+ new webrtc::WavWriter(filename, sample_rate, num_channels));
+}
+
+void rtc_WavClose(rtc_WavWriter* wf) {
+ delete reinterpret_cast<webrtc::WavWriter*>(wf);
+}
+
+void rtc_WavWriteSamples(rtc_WavWriter* wf,
+ const float* samples,
+ size_t num_samples) {
+ reinterpret_cast<webrtc::WavWriter*>(wf)->WriteSamples(samples, num_samples);
+}
+
+int rtc_WavSampleRate(const rtc_WavWriter* wf) {
+ return reinterpret_cast<const webrtc::WavWriter*>(wf)->sample_rate();
+}
+
+int rtc_WavNumChannels(const rtc_WavWriter* wf) {
+ return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_channels();
+}
+
+uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf) {
+ return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_samples();
+}
diff --git a/common_audio/wav_file.h b/common_audio/wav_file.h
new file mode 100644
index 00000000..c6c5d6b7
--- /dev/null
+++ b/common_audio/wav_file.h
@@ -0,0 +1,98 @@
+/*
+ * 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_COMMON_AUDIO_WAV_FILE_H_
+#define WEBRTC_COMMON_AUDIO_WAV_FILE_H_
+
+#ifdef __cplusplus
+
+#include <stdint.h>
+#include <cstddef>
+#include <string>
+
+namespace webrtc {
+
+// Simple C++ class for writing 16-bit PCM WAV files. All error handling is
+// by calls to CHECK(), making it unsuitable for anything but debug code.
+class WavWriter {
+ public:
+ // Open a new WAV file for writing.
+ WavWriter(const std::string& filename, int sample_rate, int num_channels);
+
+ // Close the WAV file, after writing its header.
+ ~WavWriter();
+
+ // Write additional samples to the file. Each sample is in the range
+ // [-32768,32767], and there must be the previously specified number of
+ // interleaved channels.
+ void WriteSamples(const float* samples, size_t num_samples);
+ void WriteSamples(const int16_t* samples, size_t num_samples);
+
+ int sample_rate() const { return sample_rate_; }
+ int num_channels() const { return num_channels_; }
+ uint32_t num_samples() const { return num_samples_; }
+
+ private:
+ void Close();
+ const int sample_rate_;
+ const int num_channels_;
+ uint32_t num_samples_; // Total number of samples written to file.
+ FILE* file_handle_; // Output file, owned by this class
+};
+
+// Follows the conventions of WavWriter.
+class WavReader {
+ public:
+ // Opens an existing WAV file for reading.
+ explicit WavReader(const std::string& filename);
+
+ // Close the WAV file.
+ ~WavReader();
+
+ // Returns the number of samples read. If this is less than requested,
+ // verifies that the end of the file was reached.
+ size_t ReadSamples(size_t num_samples, float* samples);
+ size_t ReadSamples(size_t num_samples, int16_t* samples);
+
+ int sample_rate() const { return sample_rate_; }
+ int num_channels() const { return num_channels_; }
+ uint32_t num_samples() const { return num_samples_; }
+
+ private:
+ void Close();
+ int sample_rate_;
+ int num_channels_;
+ uint32_t num_samples_; // Total number of samples in the file.
+ FILE* file_handle_; // Input file, owned by this class.
+};
+
+} // namespace webrtc
+
+extern "C" {
+#endif // __cplusplus
+
+// C wrappers for the WavWriter class.
+typedef struct rtc_WavWriter rtc_WavWriter;
+rtc_WavWriter* rtc_WavOpen(const char* filename,
+ int sample_rate,
+ int num_channels);
+void rtc_WavClose(rtc_WavWriter* wf);
+void rtc_WavWriteSamples(rtc_WavWriter* wf,
+ const float* samples,
+ size_t num_samples);
+int rtc_WavSampleRate(const rtc_WavWriter* wf);
+int rtc_WavNumChannels(const rtc_WavWriter* wf);
+uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBRTC_COMMON_AUDIO_WAV_FILE_H_
diff --git a/common_audio/wav_writer_unittest.cc b/common_audio/wav_file_unittest.cc
index 9c593be6..1bdb655d 100644
--- a/common_audio/wav_writer_unittest.cc
+++ b/common_audio/wav_file_unittest.cc
@@ -17,7 +17,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/compile_assert.h"
#include "webrtc/common_audio/wav_header.h"
-#include "webrtc/common_audio/wav_writer.h"
+#include "webrtc/common_audio/wav_file.h"
#include "webrtc/test/testsupport/fileutils.h"
static const float kSamples[] = {0.0, 10.0, 4e4, -1e9};
@@ -27,7 +27,7 @@ TEST(WavWriterTest, CPP) {
const std::string outfile = webrtc::test::OutputPath() + "wavtest1.wav";
static const uint32_t kNumSamples = 3;
{
- webrtc::WavFile w(outfile, 14099, 1);
+ webrtc::WavWriter w(outfile, 14099, 1);
EXPECT_EQ(14099, w.sample_rate());
EXPECT_EQ(1, w.num_channels());
EXPECT_EQ(0u, w.num_samples());
@@ -62,12 +62,24 @@ TEST(WavWriterTest, CPP) {
ASSERT_EQ(1u, fread(contents, kContentSize, 1, f));
EXPECT_EQ(0, fclose(f));
EXPECT_EQ(0, memcmp(kExpectedContents, contents, kContentSize));
+
+ {
+ webrtc::WavReader r(outfile);
+ EXPECT_EQ(14099, r.sample_rate());
+ EXPECT_EQ(1, r.num_channels());
+ EXPECT_EQ(kNumSamples, r.num_samples());
+ static const float kTruncatedSamples[] = {0.0, 10.0, 32767.0};
+ float samples[kNumSamples];
+ EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, samples));
+ EXPECT_EQ(0, memcmp(kTruncatedSamples, samples, sizeof(samples)));
+ EXPECT_EQ(0u, r.ReadSamples(kNumSamples, samples));
+ }
}
// Write a tiny WAV file with the C interface and verify the result.
TEST(WavWriterTest, C) {
const std::string outfile = webrtc::test::OutputPath() + "wavtest2.wav";
- rtc_WavFile *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
+ rtc_WavWriter *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
EXPECT_EQ(11904, rtc_WavSampleRate(w));
EXPECT_EQ(2, rtc_WavNumChannels(w));
EXPECT_EQ(0u, rtc_WavNumSamples(w));
@@ -125,7 +137,7 @@ TEST(WavWriterTest, LargeFile) {
samples[i + 1] = std::pow(std::cos(t * 2 * 2 * M_PI), 10) * x;
}
{
- webrtc::WavFile w(outfile, kSampleRate, kNumChannels);
+ webrtc::WavWriter w(outfile, kSampleRate, kNumChannels);
EXPECT_EQ(kSampleRate, w.sample_rate());
EXPECT_EQ(kNumChannels, w.num_channels());
EXPECT_EQ(0u, w.num_samples());
@@ -134,4 +146,18 @@ TEST(WavWriterTest, LargeFile) {
}
EXPECT_EQ(sizeof(int16_t) * kNumSamples + webrtc::kWavHeaderSize,
webrtc::test::GetFileSize(outfile));
+
+ {
+ webrtc::WavReader r(outfile);
+ EXPECT_EQ(kSampleRate, r.sample_rate());
+ EXPECT_EQ(kNumChannels, r.num_channels());
+ EXPECT_EQ(kNumSamples, r.num_samples());
+
+ float read_samples[kNumSamples];
+ EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, read_samples));
+ for (size_t i = 0; i < kNumSamples; ++i)
+ EXPECT_NEAR(samples[i], read_samples[i], 1);
+
+ EXPECT_EQ(0u, r.ReadSamples(kNumSamples, read_samples));
+ }
}
diff --git a/common_audio/wav_header.cc b/common_audio/wav_header.cc
index ce43896f..8c781fb4 100644
--- a/common_audio/wav_header.cc
+++ b/common_audio/wav_header.cc
@@ -18,9 +18,11 @@
#include <cstring>
#include <limits>
+#include "webrtc/base/checks.h"
#include "webrtc/common_audio/include/audio_util.h"
namespace webrtc {
+namespace {
struct ChunkHeader {
uint32_t ID;
@@ -28,6 +30,34 @@ struct ChunkHeader {
};
COMPILE_ASSERT(sizeof(ChunkHeader) == 8, chunk_header_size);
+// We can't nest this definition in WavHeader, because VS2013 gives an error
+// on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand".
+struct FmtSubchunk {
+ ChunkHeader header;
+ uint16_t AudioFormat;
+ uint16_t NumChannels;
+ uint32_t SampleRate;
+ uint32_t ByteRate;
+ uint16_t BlockAlign;
+ uint16_t BitsPerSample;
+};
+COMPILE_ASSERT(sizeof(FmtSubchunk) == 24, fmt_subchunk_size);
+const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader);
+
+struct WavHeader {
+ struct {
+ ChunkHeader header;
+ uint32_t Format;
+ } riff;
+ FmtSubchunk fmt;
+ struct {
+ ChunkHeader header;
+ } data;
+};
+COMPILE_ASSERT(sizeof(WavHeader) == kWavHeaderSize, no_padding_in_header);
+
+} // namespace
+
bool CheckWavParameters(int num_channels,
int sample_rate,
WavFormat format,
@@ -91,54 +121,53 @@ static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
| static_cast<uint32_t>(c) << 16
| static_cast<uint32_t>(d) << 24;
}
+
+static inline uint16_t ReadLE16(uint16_t x) { return x; }
+static inline uint32_t ReadLE32(uint32_t x) { return x; }
+static inline std::string ReadFourCC(uint32_t x) {
+ return std::string(reinterpret_cast<char*>(&x), 4);
+}
#else
#error "Write be-to-le conversion functions"
#endif
+static inline uint32_t RiffChunkSize(uint32_t bytes_in_payload) {
+ return bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader);
+}
+
+static inline uint32_t ByteRate(int num_channels, int sample_rate,
+ int bytes_per_sample) {
+ return static_cast<uint32_t>(num_channels) * sample_rate * bytes_per_sample;
+}
+
+static inline uint16_t BlockAlign(int num_channels, int bytes_per_sample) {
+ return num_channels * bytes_per_sample;
+}
+
void WriteWavHeader(uint8_t* buf,
int num_channels,
int sample_rate,
WavFormat format,
int bytes_per_sample,
uint32_t num_samples) {
- assert(CheckWavParameters(num_channels, sample_rate, format,
- bytes_per_sample, num_samples));
-
- struct {
- struct {
- ChunkHeader header;
- uint32_t Format;
- } riff;
- struct {
- ChunkHeader header;
- uint16_t AudioFormat;
- uint16_t NumChannels;
- uint32_t SampleRate;
- uint32_t ByteRate;
- uint16_t BlockAlign;
- uint16_t BitsPerSample;
- } fmt;
- struct {
- ChunkHeader header;
- } data;
- } header;
- COMPILE_ASSERT(sizeof(header) == kWavHeaderSize, no_padding_in_header);
+ CHECK(CheckWavParameters(num_channels, sample_rate, format,
+ bytes_per_sample, num_samples));
+ WavHeader header;
const uint32_t bytes_in_payload = bytes_per_sample * num_samples;
WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F');
- WriteLE32(&header.riff.header.Size,
- bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader));
+ WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload));
WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E');
WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' ');
- WriteLE32(&header.fmt.header.Size, sizeof(header.fmt) - sizeof(ChunkHeader));
+ WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize);
WriteLE16(&header.fmt.AudioFormat, format);
WriteLE16(&header.fmt.NumChannels, num_channels);
WriteLE32(&header.fmt.SampleRate, sample_rate);
- WriteLE32(&header.fmt.ByteRate, (static_cast<uint32_t>(num_channels)
- * sample_rate * bytes_per_sample));
- WriteLE16(&header.fmt.BlockAlign, num_channels * bytes_per_sample);
+ WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate,
+ bytes_per_sample));
+ WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample));
WriteLE16(&header.fmt.BitsPerSample, 8 * bytes_per_sample);
WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a');
@@ -149,4 +178,49 @@ void WriteWavHeader(uint8_t* buf,
memcpy(buf, &header, kWavHeaderSize);
}
+bool ReadWavHeader(const uint8_t* buf,
+ int* num_channels,
+ int* sample_rate,
+ WavFormat* format,
+ int* bytes_per_sample,
+ uint32_t* num_samples) {
+ WavHeader header;
+ memcpy(&header, buf, kWavHeaderSize);
+
+ // Parse needed fields.
+ *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
+ *num_channels = ReadLE16(header.fmt.NumChannels);
+ *sample_rate = ReadLE32(header.fmt.SampleRate);
+ *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8;
+ const uint32_t bytes_in_payload = ReadLE32(header.data.header.Size);
+ if (*bytes_per_sample <= 0)
+ return false;
+ *num_samples = bytes_in_payload / *bytes_per_sample;
+
+ // Sanity check remaining fields.
+ if (ReadFourCC(header.riff.header.ID) != "RIFF")
+ return false;
+ if (ReadFourCC(header.riff.Format) != "WAVE")
+ return false;
+ if (ReadFourCC(header.fmt.header.ID) != "fmt ")
+ return false;
+ if (ReadFourCC(header.data.header.ID) != "data")
+ return false;
+
+ if (ReadLE32(header.riff.header.Size) != RiffChunkSize(bytes_in_payload))
+ return false;
+ if (ReadLE32(header.fmt.header.Size) != kFmtSubchunkSize)
+ return false;
+ if (ReadLE32(header.fmt.ByteRate) !=
+ ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
+ return false;
+ if (ReadLE16(header.fmt.BlockAlign) !=
+ BlockAlign(*num_channels, *bytes_per_sample))
+ return false;
+
+ return CheckWavParameters(*num_channels, *sample_rate, *format,
+ *bytes_per_sample, *num_samples);
+}
+
+
} // namespace webrtc
diff --git a/common_audio/wav_header.h b/common_audio/wav_header.h
index f9ed8a57..37f78a6f 100644
--- a/common_audio/wav_header.h
+++ b/common_audio/wav_header.h
@@ -11,11 +11,12 @@
#ifndef WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
#define WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
+#include <stddef.h>
#include <stdint.h>
namespace webrtc {
-static const int kWavHeaderSize = 44;
+static const size_t kWavHeaderSize = 44;
enum WavFormat {
kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample
@@ -33,7 +34,7 @@ bool CheckWavParameters(int num_channels,
// Write a kWavHeaderSize bytes long WAV header to buf. The payload that
// follows the header is supposed to have the specified number of interleaved
// channels and contain the specified total number of samples of the specified
-// type.
+// type. CHECKs the input parameters for validity.
void WriteWavHeader(uint8_t* buf,
int num_channels,
int sample_rate,
@@ -41,6 +42,15 @@ void WriteWavHeader(uint8_t* buf,
int bytes_per_sample,
uint32_t num_samples);
+// Read a kWavHeaderSize bytes long WAV header from buf and parse the values
+// into the provided output parameters. Returns false if the header is invalid.
+bool ReadWavHeader(const uint8_t* buf,
+ int* num_channels,
+ int* sample_rate,
+ WavFormat* format,
+ int* bytes_per_sample,
+ uint32_t* num_samples);
+
} // namespace webrtc
#endif // WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
diff --git a/common_audio/wav_header_unittest.cc b/common_audio/wav_header_unittest.cc
index f05160ea..677affa5 100644
--- a/common_audio/wav_header_unittest.cc
+++ b/common_audio/wav_header_unittest.cc
@@ -48,8 +48,80 @@ TEST(WavHeaderTest, CheckWavParameters) {
webrtc::CheckWavParameters(3, 8000, webrtc::kWavFormatPcm, 1, 5));
}
-// Try writing a WAV header and make sure it looks OK.
-TEST(WavHeaderTest, WriteWavHeader) {
+TEST(WavHeaderTest, ReadWavHeaderWithErrors) {
+ int num_channels = 0;
+ int sample_rate = 0;
+ webrtc::WavFormat format = webrtc::kWavFormatPcm;
+ int bytes_per_sample = 0;
+ uint32_t num_samples = 0;
+
+ // Test a few ways the header can be invalid. We start with the valid header
+ // used in WriteAndReadWavHeader, and invalidate one field per test. The
+ // invalid field is indicated in the array name, and in the comments with
+ // *BAD*.
+ static const uint8_t kBadRiffID[] = {
+ 'R', 'i', 'f', 'f', // *BAD*
+ 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
+ 'W', 'A', 'V', 'E',
+ 'f', 'm', 't', ' ',
+ 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
+ 6, 0, // format: A-law (6)
+ 17, 0, // channels: 17
+ 0x39, 0x30, 0, 0, // sample rate: 12345
+ 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
+ 17, 0, // block align: NumChannels * BytesPerSample
+ 8, 0, // bits per sample: 1 * 8
+ 'd', 'a', 't', 'a',
+ 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
+ 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
+ };
+ EXPECT_FALSE(
+ webrtc::ReadWavHeader(kBadRiffID, &num_channels, &sample_rate,
+ &format, &bytes_per_sample, &num_samples));
+
+ static const uint8_t kBadBitsPerSample[] = {
+ 'R', 'I', 'F', 'F',
+ 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
+ 'W', 'A', 'V', 'E',
+ 'f', 'm', 't', ' ',
+ 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
+ 6, 0, // format: A-law (6)
+ 17, 0, // channels: 17
+ 0x39, 0x30, 0, 0, // sample rate: 12345
+ 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
+ 17, 0, // block align: NumChannels * BytesPerSample
+ 1, 0, // bits per sample: *BAD*
+ 'd', 'a', 't', 'a',
+ 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
+ 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
+ };
+ EXPECT_FALSE(
+ webrtc::ReadWavHeader(kBadBitsPerSample, &num_channels, &sample_rate,
+ &format, &bytes_per_sample, &num_samples));
+
+ static const uint8_t kBadByteRate[] = {
+ 'R', 'I', 'F', 'F',
+ 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
+ 'W', 'A', 'V', 'E',
+ 'f', 'm', 't', ' ',
+ 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
+ 6, 0, // format: A-law (6)
+ 17, 0, // channels: 17
+ 0x39, 0x30, 0, 0, // sample rate: 12345
+ 0x00, 0x33, 0x03, 0, // byte rate: *BAD*
+ 17, 0, // block align: NumChannels * BytesPerSample
+ 8, 0, // bits per sample: 1 * 8
+ 'd', 'a', 't', 'a',
+ 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
+ 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
+ };
+ EXPECT_FALSE(
+ webrtc::ReadWavHeader(kBadByteRate, &num_channels, &sample_rate,
+ &format, &bytes_per_sample, &num_samples));
+}
+
+// Try writing and reading a valid WAV header and make sure it looks OK.
+TEST(WavHeaderTest, WriteAndReadWavHeader) {
static const int kSize = 4 + webrtc::kWavHeaderSize + 4;
uint8_t buf[kSize];
memset(buf, 0xa4, sizeof(buf));
@@ -74,4 +146,18 @@ TEST(WavHeaderTest, WriteWavHeader) {
};
COMPILE_ASSERT(sizeof(kExpectedBuf) == kSize, buf_size);
EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
+
+ int num_channels = 0;
+ int sample_rate = 0;
+ webrtc::WavFormat format = webrtc::kWavFormatPcm;
+ int bytes_per_sample = 0;
+ uint32_t num_samples = 0;
+ EXPECT_TRUE(
+ webrtc::ReadWavHeader(buf + 4, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ EXPECT_EQ(17, num_channels);
+ EXPECT_EQ(12345, sample_rate);
+ EXPECT_EQ(webrtc::kWavFormatALaw, format);
+ EXPECT_EQ(1, bytes_per_sample);
+ EXPECT_EQ(123457689u, num_samples);
}
diff --git a/common_audio/wav_writer.cc b/common_audio/wav_writer.cc
deleted file mode 100644
index 30a220c2..00000000
--- a/common_audio/wav_writer.cc
+++ /dev/null
@@ -1,115 +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/common_audio/wav_writer.h"
-
-#include <algorithm>
-#include <cstdio>
-#include <limits>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/wav_header.h"
-
-namespace webrtc {
-
-// We write 16-bit PCM WAV files.
-static const WavFormat kWavFormat = kWavFormatPcm;
-static const int kBytesPerSample = 2;
-
-WavFile::WavFile(const std::string& filename, int sample_rate, int num_channels)
- : sample_rate_(sample_rate),
- num_channels_(num_channels),
- num_samples_(0),
- file_handle_(fopen(filename.c_str(), "wb")) {
- CHECK(file_handle_);
- CHECK(CheckWavParameters(num_channels_,
- sample_rate_,
- kWavFormat,
- kBytesPerSample,
- num_samples_));
-
- // Write a blank placeholder header, since we need to know the total number
- // of samples before we can fill in the real data.
- static const uint8_t blank_header[kWavHeaderSize] = {0};
- CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
-}
-
-WavFile::~WavFile() {
- Close();
-}
-
-void WavFile::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 WAV file"
-#endif
- const size_t written =
- fwrite(samples, sizeof(*samples), num_samples, file_handle_);
- CHECK_EQ(num_samples, written);
- num_samples_ += static_cast<uint32_t>(written);
- CHECK(written <= std::numeric_limits<uint32_t>::max() ||
- num_samples_ >= written); // detect uint32_t overflow
- CHECK(CheckWavParameters(num_channels_,
- sample_rate_,
- kWavFormat,
- kBytesPerSample,
- num_samples_));
-}
-
-void WavFile::WriteSamples(const float* samples, size_t num_samples) {
- static const size_t kChunksize = 4096 / sizeof(uint16_t);
- for (size_t i = 0; i < num_samples; i += kChunksize) {
- int16_t isamples[kChunksize];
- const size_t chunk = std::min(kChunksize, num_samples - i);
- RoundToInt16(samples + i, chunk, isamples);
- WriteSamples(isamples, chunk);
- }
-}
-
-void WavFile::Close() {
- CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
- uint8_t header[kWavHeaderSize];
- WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
- kBytesPerSample, num_samples_);
- CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
- CHECK_EQ(0, fclose(file_handle_));
- file_handle_ = NULL;
-}
-
-} // namespace webrtc
-
-rtc_WavFile* rtc_WavOpen(const char* filename,
- int sample_rate,
- int num_channels) {
- return reinterpret_cast<rtc_WavFile*>(
- new webrtc::WavFile(filename, sample_rate, num_channels));
-}
-
-void rtc_WavClose(rtc_WavFile* wf) {
- delete reinterpret_cast<webrtc::WavFile*>(wf);
-}
-
-void rtc_WavWriteSamples(rtc_WavFile* wf,
- const float* samples,
- size_t num_samples) {
- reinterpret_cast<webrtc::WavFile*>(wf)->WriteSamples(samples, num_samples);
-}
-
-int rtc_WavSampleRate(const rtc_WavFile* wf) {
- return reinterpret_cast<const webrtc::WavFile*>(wf)->sample_rate();
-}
-
-int rtc_WavNumChannels(const rtc_WavFile* wf) {
- return reinterpret_cast<const webrtc::WavFile*>(wf)->num_channels();
-}
-
-uint32_t rtc_WavNumSamples(const rtc_WavFile* wf) {
- return reinterpret_cast<const webrtc::WavFile*>(wf)->num_samples();
-}
diff --git a/common_audio/wav_writer.h b/common_audio/wav_writer.h
deleted file mode 100644
index 09667279..00000000
--- a/common_audio/wav_writer.h
+++ /dev/null
@@ -1,72 +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_COMMON_AUDIO_WAV_WRITER_H_
-#define WEBRTC_COMMON_AUDIO_WAV_WRITER_H_
-
-#ifdef __cplusplus
-
-#include <stdint.h>
-#include <cstddef>
-#include <string>
-
-namespace webrtc {
-
-// Simple C++ class for writing 16-bit PCM WAV files. All error handling is
-// by calls to CHECK(), making it unsuitable for anything but debug code.
-class WavFile {
- public:
- // Open a new WAV file for writing.
- WavFile(const std::string& filename, int sample_rate, int num_channels);
-
- // Close the WAV file, after writing its header.
- ~WavFile();
-
- // Write additional samples to the file. Each sample is in the range
- // [-32768,32767], and there must be the previously specified number of
- // interleaved channels.
- void WriteSamples(const float* samples, size_t num_samples);
- void WriteSamples(const int16_t* samples, size_t num_samples);
-
- int sample_rate() const { return sample_rate_; }
- int num_channels() const { return num_channels_; }
- uint32_t num_samples() const { return num_samples_; }
-
- private:
- void Close();
- const int sample_rate_;
- const int num_channels_;
- uint32_t num_samples_; // total number of samples written to file
- FILE* file_handle_; // output file, owned by this class
-};
-
-} // namespace webrtc
-
-extern "C" {
-#endif // __cplusplus
-
-// C wrappers for the WavFile class.
-typedef struct rtc_WavFile rtc_WavFile;
-rtc_WavFile* rtc_WavOpen(const char* filename,
- int sample_rate,
- int num_channels);
-void rtc_WavClose(rtc_WavFile* wf);
-void rtc_WavWriteSamples(rtc_WavFile* wf,
- const float* samples,
- size_t num_samples);
-int rtc_WavSampleRate(const rtc_WavFile* wf);
-int rtc_WavNumChannels(const rtc_WavFile* wf);
-uint32_t rtc_WavNumSamples(const rtc_WavFile* wf);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBRTC_COMMON_AUDIO_WAV_WRITER_H_