EchoCancellationImpl::ProcessRenderAudio: Use float samples directly

This patch lets EchoCancellationImpl::ProcessRenderAudio ask the given
AudioBuffer for float sample data directly, instead of asking for
int16 samples and then converting manually.

Since EchoCancellationImpl::ProcessRenderAudio takes a const
AudioBuffer*, it was necessary to add some const accessors for float
data to AudioBuffer.

R=aluebs@webrtc.org, andrew@webrtc.org, bjornv@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/14749004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6590 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
kwiberg@webrtc.org
2014-07-03 09:47:33 +00:00
parent a82f9a243d
commit 38214d53db
8 changed files with 54 additions and 51 deletions

View File

@@ -26,7 +26,7 @@ enum {
}; };
typedef struct { typedef struct {
short buffer[kResamplerBufferSize]; float buffer[kResamplerBufferSize];
float position; float position;
int deviceSampleRateHz; int deviceSampleRateHz;
@@ -71,15 +71,15 @@ int WebRtcAec_FreeResampler(void* resampInst) {
} }
void WebRtcAec_ResampleLinear(void* resampInst, void WebRtcAec_ResampleLinear(void* resampInst,
const short* inspeech, const float* inspeech,
int size, int size,
float skew, float skew,
short* outspeech, float* outspeech,
int* size_out) { int* size_out) {
resampler_t* obj = (resampler_t*)resampInst; resampler_t* obj = (resampler_t*)resampInst;
short* y; float* y;
float be, tnew, interp; float be, tnew;
int tn, mm; int tn, mm;
assert(!(size < 0 || size > 2 * FRAME_LEN)); assert(!(size < 0 || size > 2 * FRAME_LEN));
@@ -91,7 +91,7 @@ void WebRtcAec_ResampleLinear(void* resampInst,
// Add new frame data in lookahead // Add new frame data in lookahead
memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay], memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
inspeech, inspeech,
size * sizeof(short)); size * sizeof(inspeech[0]));
// Sample rate ratio // Sample rate ratio
be = 1 + skew; be = 1 + skew;
@@ -106,15 +106,7 @@ void WebRtcAec_ResampleLinear(void* resampInst,
while (tn < size) { while (tn < size) {
// Interpolation // Interpolation
interp = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]); outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
if (interp > 32767) {
interp = 32767;
} else if (interp < -32768) {
interp = -32768;
}
outspeech[mm] = (short)interp;
mm++; mm++;
tnew = be * mm + obj->position; tnew = be * mm + obj->position;
@@ -127,7 +119,7 @@ void WebRtcAec_ResampleLinear(void* resampInst,
// Shift buffer // Shift buffer
memmove(obj->buffer, memmove(obj->buffer,
&obj->buffer[size], &obj->buffer[size],
(kResamplerBufferSize - size) * sizeof(short)); (kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
} }
int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) { int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {

View File

@@ -30,10 +30,10 @@ int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst);
// Resamples input using linear interpolation. // Resamples input using linear interpolation.
void WebRtcAec_ResampleLinear(void* resampInst, void WebRtcAec_ResampleLinear(void* resampInst,
const short* inspeech, const float* inspeech,
int size, int size,
float skew, float skew,
short* outspeech, float* outspeech,
int* size_out); int* size_out);
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_ #endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_

View File

@@ -294,17 +294,12 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
// only buffer L band for farend // only buffer L band for farend
int32_t WebRtcAec_BufferFarend(void* aecInst, int32_t WebRtcAec_BufferFarend(void* aecInst,
const int16_t* farend, const float* farend,
int16_t nrOfSamples) { int16_t nrOfSamples) {
aecpc_t* aecpc = aecInst; aecpc_t* aecpc = aecInst;
int32_t retVal = 0;
int newNrOfSamples = (int)nrOfSamples; int newNrOfSamples = (int)nrOfSamples;
short newFarend[MAX_RESAMP_LEN]; float new_farend[MAX_RESAMP_LEN];
const int16_t* farend_ptr = farend; const float* farend_ptr = farend;
float tmp_farend[MAX_RESAMP_LEN];
const float* farend_float = tmp_farend;
float skew;
int i = 0;
if (farend == NULL) { if (farend == NULL) {
aecpc->lastError = AEC_NULL_POINTER_ERROR; aecpc->lastError = AEC_NULL_POINTER_ERROR;
@@ -322,17 +317,15 @@ int32_t WebRtcAec_BufferFarend(void* aecInst,
return -1; return -1;
} }
skew = aecpc->skew;
if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) { if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
// Resample and get a new number of samples // Resample and get a new number of samples
WebRtcAec_ResampleLinear(aecpc->resampler, WebRtcAec_ResampleLinear(aecpc->resampler,
farend, farend,
nrOfSamples, nrOfSamples,
skew, aecpc->skew,
newFarend, new_farend,
&newNrOfSamples); &newNrOfSamples);
farend_ptr = (const int16_t*)newFarend; farend_ptr = new_farend;
} }
aecpc->farend_started = 1; aecpc->farend_started = 1;
@@ -343,32 +336,31 @@ int32_t WebRtcAec_BufferFarend(void* aecInst,
WebRtc_WriteBuffer( WebRtc_WriteBuffer(
aecpc->far_pre_buf_s16, farend_ptr, (size_t)newNrOfSamples); aecpc->far_pre_buf_s16, farend_ptr, (size_t)newNrOfSamples);
#endif #endif
// Cast to float and write the time-domain data to |far_pre_buf|. // Write the time-domain data to |far_pre_buf|.
for (i = 0; i < newNrOfSamples; i++) { WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, (size_t)newNrOfSamples);
tmp_farend[i] = (float)farend_ptr[i];
}
WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_float, (size_t)newNrOfSamples);
// Transform to frequency domain if we have enough data. // Transform to frequency domain if we have enough data.
while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) { while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
// We have enough data to pass to the FFT, hence read PART_LEN2 samples. // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
WebRtc_ReadBuffer( {
aecpc->far_pre_buf, (void**)&farend_float, tmp_farend, PART_LEN2); float* ptmp;
float tmp[PART_LEN2];
WebRtcAec_BufferFarendPartition(aecpc->aec, farend_float); WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**)&ptmp, tmp, PART_LEN2);
WebRtcAec_BufferFarendPartition(aecpc->aec, ptmp);
}
// Rewind |far_pre_buf| PART_LEN samples for overlap before continuing. // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN); WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
#ifdef WEBRTC_AEC_DEBUG_DUMP #ifdef WEBRTC_AEC_DEBUG_DUMP
WebRtc_ReadBuffer( WebRtc_ReadBuffer(
aecpc->far_pre_buf_s16, (void**)&farend_ptr, newFarend, PART_LEN2); aecpc->far_pre_buf_s16, (void**)&farend_ptr, new_farend, PART_LEN2);
WebRtc_WriteBuffer( WebRtc_WriteBuffer(
WebRtcAec_far_time_buf(aecpc->aec), &farend_ptr[PART_LEN], 1); WebRtcAec_far_time_buf(aecpc->aec), &farend_ptr[PART_LEN], 1);
WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN); WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);
#endif #endif
} }
return retVal; return 0;
} }
int32_t WebRtcAec_Process(void* aecInst, int32_t WebRtcAec_Process(void* aecInst,

View File

@@ -114,7 +114,7 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq);
* Inputs Description * Inputs Description
* ------------------------------------------------------------------- * -------------------------------------------------------------------
* void* aecInst Pointer to the AEC instance * void* aecInst Pointer to the AEC instance
* int16_t* farend In buffer containing one frame of * const float* farend In buffer containing one frame of
* farend signal for L band * farend signal for L band
* int16_t nrOfSamples Number of samples in farend buffer * int16_t nrOfSamples Number of samples in farend buffer
* *
@@ -124,7 +124,7 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq);
* -1: error * -1: error
*/ */
int32_t WebRtcAec_BufferFarend(void* aecInst, int32_t WebRtcAec_BufferFarend(void* aecInst,
const int16_t* farend, const float* farend,
int16_t nrOfSamples); int16_t nrOfSamples);
/* /*

View File

@@ -47,7 +47,7 @@ class SystemDelayTest : public ::testing::Test {
int samples_per_frame_; int samples_per_frame_;
// Dummy input/output speech data. // Dummy input/output speech data.
static const int kSamplesPerChunk = 160; static const int kSamplesPerChunk = 160;
int16_t far_[kSamplesPerChunk]; float far_[kSamplesPerChunk];
float near_[kSamplesPerChunk]; float near_[kSamplesPerChunk];
float out_[kSamplesPerChunk]; float out_[kSamplesPerChunk];
}; };
@@ -55,9 +55,10 @@ class SystemDelayTest : public ::testing::Test {
SystemDelayTest::SystemDelayTest() SystemDelayTest::SystemDelayTest()
: handle_(NULL), self_(NULL), samples_per_frame_(0) { : handle_(NULL), self_(NULL), samples_per_frame_(0) {
// Dummy input data are set with more or less arbitrary non-zero values. // Dummy input data are set with more or less arbitrary non-zero values.
memset(far_, 1, sizeof(far_)); for (int i = 0; i < kSamplesPerChunk; i++) {
for (int i = 0; i < kSamplesPerChunk; i++) far_[i] = 257.0;
near_[i] = 514.0; near_[i] = 514.0;
}
memset(out_, 0, sizeof(out_)); memset(out_, 0, sizeof(out_));
} }

View File

@@ -294,11 +294,16 @@ int16_t* AudioBuffer::data(int channel) {
return const_cast<int16_t*>(t->data(channel)); return const_cast<int16_t*>(t->data(channel));
} }
float* AudioBuffer::data_f(int channel) { const float* AudioBuffer::data_f(int channel) const {
assert(channel >= 0 && channel < num_proc_channels_); assert(channel >= 0 && channel < num_proc_channels_);
return channels_->fbuf()->channel(channel); return channels_->fbuf()->channel(channel);
} }
float* AudioBuffer::data_f(int channel) {
const AudioBuffer* t = this;
return const_cast<float*>(t->data_f(channel));
}
const int16_t* AudioBuffer::low_pass_split_data(int channel) const { const int16_t* AudioBuffer::low_pass_split_data(int channel) const {
assert(channel >= 0 && channel < num_proc_channels_); assert(channel >= 0 && channel < num_proc_channels_);
return split_channels_.get() ? split_channels_->low_channel(channel) return split_channels_.get() ? split_channels_->low_channel(channel)
@@ -310,12 +315,17 @@ int16_t* AudioBuffer::low_pass_split_data(int channel) {
return const_cast<int16_t*>(t->low_pass_split_data(channel)); return const_cast<int16_t*>(t->low_pass_split_data(channel));
} }
float* AudioBuffer::low_pass_split_data_f(int channel) { const float* AudioBuffer::low_pass_split_data_f(int channel) const {
assert(channel >= 0 && channel < num_proc_channels_); assert(channel >= 0 && channel < num_proc_channels_);
return split_channels_.get() ? split_channels_->low_channel_f(channel) return split_channels_.get() ? split_channels_->low_channel_f(channel)
: data_f(channel); : data_f(channel);
} }
float* AudioBuffer::low_pass_split_data_f(int channel) {
const AudioBuffer* t = this;
return const_cast<float*>(t->low_pass_split_data_f(channel));
}
const int16_t* AudioBuffer::high_pass_split_data(int channel) const { const int16_t* AudioBuffer::high_pass_split_data(int channel) const {
assert(channel >= 0 && channel < num_proc_channels_); assert(channel >= 0 && channel < num_proc_channels_);
return split_channels_.get() ? split_channels_->high_channel(channel) : NULL; return split_channels_.get() ? split_channels_->high_channel(channel) : NULL;
@@ -326,12 +336,17 @@ int16_t* AudioBuffer::high_pass_split_data(int channel) {
return const_cast<int16_t*>(t->high_pass_split_data(channel)); return const_cast<int16_t*>(t->high_pass_split_data(channel));
} }
float* AudioBuffer::high_pass_split_data_f(int channel) { const float* AudioBuffer::high_pass_split_data_f(int channel) const {
assert(channel >= 0 && channel < num_proc_channels_); assert(channel >= 0 && channel < num_proc_channels_);
return split_channels_.get() ? split_channels_->high_channel_f(channel) return split_channels_.get() ? split_channels_->high_channel_f(channel)
: NULL; : NULL;
} }
float* AudioBuffer::high_pass_split_data_f(int channel) {
const AudioBuffer* t = this;
return const_cast<float*>(t->high_pass_split_data_f(channel));
}
const int16_t* AudioBuffer::mixed_data(int channel) const { const int16_t* AudioBuffer::mixed_data(int channel) const {
assert(channel >= 0 && channel < num_mixed_channels_); assert(channel >= 0 && channel < num_mixed_channels_);

View File

@@ -69,8 +69,11 @@ class AudioBuffer {
// Float versions of the accessors, with automatic conversion back and forth // Float versions of the accessors, with automatic conversion back and forth
// as necessary. The range of the numbers are the same as for int16_t. // as necessary. The range of the numbers are the same as for int16_t.
float* data_f(int channel); float* data_f(int channel);
const float* data_f(int channel) const;
float* low_pass_split_data_f(int channel); float* low_pass_split_data_f(int channel);
const float* low_pass_split_data_f(int channel) const;
float* high_pass_split_data_f(int channel); float* high_pass_split_data_f(int channel);
const float* high_pass_split_data_f(int channel) const;
const float* keyboard_data() const; const float* keyboard_data() const;

View File

@@ -89,7 +89,7 @@ int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
Handle* my_handle = static_cast<Handle*>(handle(handle_index)); Handle* my_handle = static_cast<Handle*>(handle(handle_index));
err = WebRtcAec_BufferFarend( err = WebRtcAec_BufferFarend(
my_handle, my_handle,
audio->low_pass_split_data(j), audio->low_pass_split_data_f(j),
static_cast<int16_t>(audio->samples_per_split_channel())); static_cast<int16_t>(audio->samples_per_split_channel()));
if (err != apm_->kNoError) { if (err != apm_->kNoError) {