Fix WEBRTC_AEC_DEBUG_DUMP (broken by int16->float conversion)
And in the process, make it dump WAV files instead of raw PCM. R=andrew@webrtc.org, bjornv@webrtc.org Review URL: https://webrtc-codereview.appspot.com/19089004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6959 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -101,3 +101,15 @@ void rtc_WavWriteSamples(rtc_WavFile* wf,
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ class WavFile {
|
||||
// interleaved channels.
|
||||
void WriteSamples(const float* 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 WriteSamples(const int16_t* samples, size_t num_samples);
|
||||
void Close();
|
||||
@@ -57,6 +61,9 @@ 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"
|
||||
|
||||
@@ -25,10 +25,14 @@ static const float kSamples[] = {0.0, 10.0, 4e4, -1e9};
|
||||
// Write a tiny WAV file with the C++ interface and verify the result.
|
||||
TEST(WavWriterTest, CPP) {
|
||||
const std::string outfile = webrtc::test::OutputPath() + "wavtest1.wav";
|
||||
static const int kNumSamples = 3;
|
||||
static const uint32_t kNumSamples = 3;
|
||||
{
|
||||
webrtc::WavFile w(outfile, 14099, 1);
|
||||
EXPECT_EQ(14099, w.sample_rate());
|
||||
EXPECT_EQ(1, w.num_channels());
|
||||
EXPECT_EQ(0u, w.num_samples());
|
||||
w.WriteSamples(kSamples, kNumSamples);
|
||||
EXPECT_EQ(kNumSamples, w.num_samples());
|
||||
}
|
||||
static const uint8_t kExpectedContents[] = {
|
||||
'R', 'I', 'F', 'F',
|
||||
@@ -64,9 +68,14 @@ TEST(WavWriterTest, CPP) {
|
||||
TEST(WavWriterTest, C) {
|
||||
const std::string outfile = webrtc::test::OutputPath() + "wavtest2.wav";
|
||||
rtc_WavFile *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
|
||||
static const int kNumSamples = 4;
|
||||
EXPECT_EQ(11904, rtc_WavSampleRate(w));
|
||||
EXPECT_EQ(2, rtc_WavNumChannels(w));
|
||||
EXPECT_EQ(0u, rtc_WavNumSamples(w));
|
||||
static const uint32_t kNumSamples = 4;
|
||||
rtc_WavWriteSamples(w, &kSamples[0], 2);
|
||||
EXPECT_EQ(2u, rtc_WavNumSamples(w));
|
||||
rtc_WavWriteSamples(w, &kSamples[2], kNumSamples - 2);
|
||||
EXPECT_EQ(kNumSamples, rtc_WavNumSamples(w));
|
||||
rtc_WavClose(w);
|
||||
static const uint8_t kExpectedContents[] = {
|
||||
'R', 'I', 'F', 'F',
|
||||
@@ -104,9 +113,9 @@ TEST(WavWriterTest, LargeFile) {
|
||||
std::string outfile = webrtc::test::OutputPath() + "wavtest3.wav";
|
||||
static const int kSampleRate = 8000;
|
||||
static const int kNumChannels = 2;
|
||||
static const int kNumSamples = 3 * kSampleRate * kNumChannels;
|
||||
static const uint32_t kNumSamples = 3 * kSampleRate * kNumChannels;
|
||||
float samples[kNumSamples];
|
||||
for (int i = 0; i < kNumSamples; i += kNumChannels) {
|
||||
for (uint32_t i = 0; i < kNumSamples; i += kNumChannels) {
|
||||
// A nice periodic beeping sound.
|
||||
static const double kToneHz = 440;
|
||||
const double t = static_cast<double>(i) / (kNumChannels * kSampleRate);
|
||||
@@ -117,7 +126,11 @@ TEST(WavWriterTest, LargeFile) {
|
||||
}
|
||||
{
|
||||
webrtc::WavFile w(outfile, kSampleRate, kNumChannels);
|
||||
EXPECT_EQ(kSampleRate, w.sample_rate());
|
||||
EXPECT_EQ(kNumChannels, w.num_channels());
|
||||
EXPECT_EQ(0u, w.num_samples());
|
||||
w.WriteSamples(samples, kNumSamples);
|
||||
EXPECT_EQ(kNumSamples, w.num_samples());
|
||||
}
|
||||
EXPECT_EQ(sizeof(int16_t) * kNumSamples + webrtc::kWavHeaderSize,
|
||||
webrtc::test::GetFileSize(outfile));
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stddef.h> // size_t
|
||||
@@ -1054,11 +1058,11 @@ static void ProcessBlock(AecCore* aec) {
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
{
|
||||
int16_t farend[PART_LEN];
|
||||
int16_t* farend_ptr = NULL;
|
||||
float farend[PART_LEN];
|
||||
float* farend_ptr = NULL;
|
||||
WebRtc_ReadBuffer(aec->far_time_buf, (void**)&farend_ptr, farend, 1);
|
||||
(void)fwrite(farend_ptr, sizeof(int16_t), PART_LEN, aec->farFile);
|
||||
(void)fwrite(nearend_ptr, sizeof(int16_t), PART_LEN, aec->nearFile);
|
||||
rtc_WavWriteSamples(aec->farFile, farend_ptr, PART_LEN);
|
||||
rtc_WavWriteSamples(aec->nearFile, nearend_ptr, PART_LEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1208,16 +1212,8 @@ static void ProcessBlock(AecCore* aec) {
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
{
|
||||
int16_t eInt16[PART_LEN];
|
||||
for (i = 0; i < PART_LEN; i++) {
|
||||
eInt16[i] = (int16_t)WEBRTC_SPL_SAT(
|
||||
WEBRTC_SPL_WORD16_MAX, e[i], WEBRTC_SPL_WORD16_MIN);
|
||||
}
|
||||
|
||||
(void)fwrite(eInt16, sizeof(int16_t), PART_LEN, aec->outLinearFile);
|
||||
(void)fwrite(output, sizeof(int16_t), PART_LEN, aec->outFile);
|
||||
}
|
||||
rtc_WavWriteSamples(aec->outLinearFile, e, PART_LEN);
|
||||
rtc_WavWriteSamples(aec->outFile, output, PART_LEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1272,24 +1268,16 @@ int WebRtcAec_CreateAec(AecCore** aecInst) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
aec->instance_index = webrtc_aec_instance_count;
|
||||
aec->far_time_buf =
|
||||
WebRtc_CreateBuffer(kBufSizePartitions, sizeof(int16_t) * PART_LEN);
|
||||
WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * PART_LEN);
|
||||
if (!aec->far_time_buf) {
|
||||
WebRtcAec_FreeAec(aec);
|
||||
aec = NULL;
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
char filename[64];
|
||||
sprintf(filename, "aec_far%d.pcm", webrtc_aec_instance_count);
|
||||
aec->farFile = fopen(filename, "wb");
|
||||
sprintf(filename, "aec_near%d.pcm", webrtc_aec_instance_count);
|
||||
aec->nearFile = fopen(filename, "wb");
|
||||
sprintf(filename, "aec_out%d.pcm", webrtc_aec_instance_count);
|
||||
aec->outFile = fopen(filename, "wb");
|
||||
sprintf(filename, "aec_out_linear%d.pcm", webrtc_aec_instance_count);
|
||||
aec->outLinearFile = fopen(filename, "wb");
|
||||
}
|
||||
aec->farFile = aec->nearFile = aec->outFile = aec->outLinearFile = NULL;
|
||||
aec->debug_dump_count = 0;
|
||||
#endif
|
||||
aec->delay_estimator_farend =
|
||||
WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
|
||||
@@ -1348,10 +1336,10 @@ int WebRtcAec_FreeAec(AecCore* aec) {
|
||||
WebRtc_FreeBuffer(aec->far_buf_windowed);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_FreeBuffer(aec->far_time_buf);
|
||||
fclose(aec->farFile);
|
||||
fclose(aec->nearFile);
|
||||
fclose(aec->outFile);
|
||||
fclose(aec->outLinearFile);
|
||||
rtc_WavClose(aec->farFile);
|
||||
rtc_WavClose(aec->nearFile);
|
||||
rtc_WavClose(aec->outFile);
|
||||
rtc_WavClose(aec->outLinearFile);
|
||||
#endif
|
||||
WebRtc_FreeDelayEstimator(aec->delay_estimator);
|
||||
WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
|
||||
@@ -1360,6 +1348,29 @@ int WebRtcAec_FreeAec(AecCore* aec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
// Open a new Wav file for writing. If it was already open with a different
|
||||
// sample frequency, close it first.
|
||||
static void ReopenWav(rtc_WavFile** wav_file,
|
||||
const char* name,
|
||||
int seq1,
|
||||
int seq2,
|
||||
int sample_rate) {
|
||||
int written UNUSED;
|
||||
char filename[64];
|
||||
if (*wav_file) {
|
||||
if (rtc_WavSampleRate(*wav_file) == sample_rate)
|
||||
return;
|
||||
rtc_WavClose(*wav_file);
|
||||
}
|
||||
written = snprintf(filename, sizeof(filename), "%s%d-%d.wav",
|
||||
name, seq1, seq2);
|
||||
assert(written >= 0); // no output error
|
||||
assert((size_t)written < sizeof(filename)); // buffer was large enough
|
||||
*wav_file = rtc_WavOpen(filename, sample_rate, 1);
|
||||
}
|
||||
#endif // WEBRTC_AEC_DEBUG_DUMP
|
||||
|
||||
int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
||||
int i;
|
||||
|
||||
@@ -1400,6 +1411,15 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
||||
if (WebRtc_InitBuffer(aec->far_time_buf) == -1) {
|
||||
return -1;
|
||||
}
|
||||
ReopenWav(&aec->farFile, "aec_far",
|
||||
aec->instance_index, aec->debug_dump_count, sampFreq);
|
||||
ReopenWav(&aec->nearFile, "aec_near",
|
||||
aec->instance_index, aec->debug_dump_count, sampFreq);
|
||||
ReopenWav(&aec->outFile, "aec_out",
|
||||
aec->instance_index, aec->debug_dump_count, sampFreq);
|
||||
ReopenWav(&aec->outLinearFile, "aec_out_linear",
|
||||
aec->instance_index, aec->debug_dump_count, sampFreq);
|
||||
++aec->debug_dump_count;
|
||||
#endif
|
||||
aec->system_delay = 0;
|
||||
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "webrtc/common_audio/wav_writer.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_common.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
#include "webrtc/modules/audio_processing/utility/ring_buffer.h"
|
||||
@@ -141,11 +138,19 @@ struct AecCore {
|
||||
int num_partitions;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
// Sequence number of this AEC instance, so that different instances can
|
||||
// choose different dump file names.
|
||||
int instance_index;
|
||||
|
||||
// Number of times we've restarted dumping; used to pick new dump file names
|
||||
// each time.
|
||||
int debug_dump_count;
|
||||
|
||||
RingBuffer* far_time_buf;
|
||||
FILE* farFile;
|
||||
FILE* nearFile;
|
||||
FILE* outFile;
|
||||
FILE* outLinearFile;
|
||||
rtc_WavFile* farFile;
|
||||
rtc_WavFile* nearFile;
|
||||
rtc_WavFile* outFile;
|
||||
rtc_WavFile* outLinearFile;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -158,13 +158,6 @@ int32_t WebRtcAec_Create(void** aecInst) {
|
||||
aecpc->lastError = 0;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
aecpc->far_pre_buf_s16 =
|
||||
WebRtc_CreateBuffer(PART_LEN2 + kResamplerBufferSize, sizeof(int16_t));
|
||||
if (!aecpc->far_pre_buf_s16) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
aecpc = NULL;
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
char filename[64];
|
||||
sprintf(filename, "aec_buf%d.dat", webrtc_aec_instance_count);
|
||||
@@ -190,7 +183,6 @@ int32_t WebRtcAec_Free(void* aecInst) {
|
||||
WebRtc_FreeBuffer(aecpc->far_pre_buf);
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_FreeBuffer(aecpc->far_pre_buf_s16);
|
||||
fclose(aecpc->bufFile);
|
||||
fclose(aecpc->skewFile);
|
||||
fclose(aecpc->delayFile);
|
||||
@@ -281,14 +273,6 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
if (WebRtc_InitBuffer(aecpc->far_pre_buf_s16) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN); // Start overlap.
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -332,10 +316,6 @@ int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
WebRtcAec_SetSystemDelay(aecpc->aec,
|
||||
WebRtcAec_system_delay(aecpc->aec) + newNrOfSamples);
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_WriteBuffer(
|
||||
aecpc->far_pre_buf_s16, farend_ptr, (size_t)newNrOfSamples);
|
||||
#endif
|
||||
// Write the time-domain data to |far_pre_buf|.
|
||||
WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, (size_t)newNrOfSamples);
|
||||
|
||||
@@ -347,17 +327,14 @@ int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
float tmp[PART_LEN2];
|
||||
WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**)&ptmp, tmp, PART_LEN2);
|
||||
WebRtcAec_BufferFarendPartition(aecpc->aec, ptmp);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_WriteBuffer(
|
||||
WebRtcAec_far_time_buf(aecpc->aec), &ptmp[PART_LEN], 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
|
||||
WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_ReadBuffer(
|
||||
aecpc->far_pre_buf_s16, (void**)&farend_ptr, new_farend, PART_LEN2);
|
||||
WebRtc_WriteBuffer(
|
||||
WebRtcAec_far_time_buf(aecpc->aec), &farend_ptr[PART_LEN], 1);
|
||||
WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -42,7 +42,6 @@ typedef struct {
|
||||
short lastDelayDiff;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
RingBuffer* far_pre_buf_s16; // Time domain far-end pre-buffer in int16_t.
|
||||
FILE* bufFile;
|
||||
FILE* delayFile;
|
||||
FILE* skewFile;
|
||||
|
||||
@@ -109,4 +109,15 @@ typedef unsigned __int64 uint64_t;
|
||||
#endif
|
||||
#endif // WARN_UNUSED_RESULT
|
||||
|
||||
// Put after a variable that might not be used, to prevent compiler warnings:
|
||||
// int result UNUSED = DoSomething();
|
||||
// assert(result == 17);
|
||||
#ifndef UNUSED
|
||||
#ifdef __GNUC__
|
||||
#define UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define UNUSED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_TYPEDEFS_H_
|
||||
|
||||
Reference in New Issue
Block a user