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:
@@ -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) {
|
||||||
|
@@ -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_
|
||||||
|
@@ -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,
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -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_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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_);
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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) {
|
||||||
|
Reference in New Issue
Block a user