Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/rebuild-testbench.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export_xtensa_setup()
cat <<EOFSETUP > "$export_script"
export XTENSA_TOOLS_ROOT=$XTENSA_TOOLS_ROOT
export XTENSA_CORE=$XTENSA_CORE
XTENSA_PATH=$tools_bin
export XTENSA_PATH=$tools_bin
EOFSETUP
}

Expand Down
2 changes: 1 addition & 1 deletion src/audio/mfcc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ config COMP_MFCC
tristate "MFCC component"
depends on COMP_MODULE_ADAPTER
select CORDIC_FIXED
select MATH_16BIT_MEL_FILTERBANK
select MATH_32BIT_MEL_FILTERBANK
select MATH_AUDITORY
select MATH_DCT
select MATH_DECIBELS
Expand Down
11 changes: 1 addition & 10 deletions src/audio/mfcc/mfcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ static int mfcc_prepare(struct processing_module *mod,
enum sof_ipc_frame source_format;
enum sof_ipc_frame sink_format;
size_t data_size;
uint32_t sink_period_bytes;
int ret;

comp_info(dev, "entry");
Expand All @@ -178,15 +177,7 @@ static int mfcc_prepare(struct processing_module *mod,

/* get sink data format and period bytes */
sink_format = audio_stream_get_frm_fmt(&sinkb->stream);
sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, dev->frames);
comp_info(dev, "source_format = %d, sink_format = %d",
source_format, sink_format);
if (audio_stream_get_size(&sinkb->stream) < sink_period_bytes) {
comp_err(dev, "sink buffer size %d is insufficient < %d",
audio_stream_get_size(&sinkb->stream), sink_period_bytes);
ret = -ENOMEM;
goto err;
}
comp_info(dev, "source_format = %d, sink_format = %d", source_format, sink_format);

cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL);

Expand Down
214 changes: 158 additions & 56 deletions src/audio/mfcc/mfcc_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_comp_data *
struct mfcc_fft *fft = &state->fft;
int mel_scale_shift;
int input_shift;
int i;
int i, j;
int m;
int cc_count = 0;
int32_t s;
int16_t mel_value;
int16_t peak;
int16_t clamp_value;
int64_t s;
int32_t mel_value;
int32_t peak;
int32_t clamp_value;

/* Phase 1, wait until whole fft_size is filled with valid data. This way
* first output cepstral coefficients originate from streamed data and not
Expand Down Expand Up @@ -110,8 +110,8 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_comp_data *
fft_execute_32(fft->fft_plan, false);
#endif

/* Convert powerspectrum to Mel band logarithmic spectrum */
mat_init_16b(state->mel_spectra, 1, state->dct.num_in, 7); /* Q8.7 */
/* Convert powerspectrum to Mel band logarithmic spectrum Q9.23 */
mat_init_16b(state->mel_spectra, 1, state->dct.num_in, 7); /* Q9.7 */

/* Compensate FFT lib scaling to Mel log values, e.g. for 512 long FFT
* the fft_plan->len is 9. The scaling is 1/512. Subtract from input_shift it
Expand All @@ -121,54 +121,69 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_comp_data *
#if MFCC_FFT_BITS == 16
psy_apply_mel_filterbank_16(&state->melfb, fft->fft_out, state->power_spectra,
state->mel_spectra->data, mel_scale_shift);
/* Convert Q9.7 int16_t mel log to Q9.23 int32_t for downstream processing */
for (j = 0; j < state->dct.num_in; j++)
state->mel_log_32[j] = (int32_t)state->mel_spectra->data[j] << 16;
#else
psy_apply_mel_filterbank_32(&state->melfb, fft->fft_out, state->power_spectra,
state->mel_spectra->data, mel_scale_shift);
state->mel_log_32, mel_scale_shift);
#endif

if (state->mel_only) {
/* In Mel-only mode output Mel log spectra directly */
cc_count += state->dct.num_in;

/* Find peak mel value and track state->mmax */
/* Find peak mel value and track state->mmax in Q9.23 */
if (config->dynamic_mmax) {
peak = state->mel_spectra->data[0];
for (i = 1; i < state->dct.num_in; i++) {
if (state->mel_spectra->data[i] > peak)
peak = state->mel_spectra->data[i];
peak = state->mel_log_32[0];
for (j = 1; j < state->dct.num_in; j++) {
if (state->mel_log_32[j] > peak)
peak = state->mel_log_32[j];
}

/* Jump to peak immediately if higher, decay otherwise */
if (peak > state->mmax) {
state->mmax = peak;
} else {
/* Q8.7 * Q1.15, result Q8.7. The coefficient is small so
* no need for saturation.
/* Q9.23 * Q1.15, result Q9.23. The coefficient is small
* so no need for saturation.
*/
s = (int32_t)peak - state->mmax;
s = (int64_t)peak - state->mmax;
state->mmax +=
Q_MULTSR_32X32(s, config->mmax_coef, 7, 15, 7);
Q_MULTSR_32X32(s, config->mmax_coef, 23, 15, 23);
}
}

/* Clamp Mel values lower than mmax - top_db, add offset, and scale */
clamp_value = state->mmax - config->top_db;
for (i = 0; i < state->dct.num_in; i++) {
mel_value = state->mel_spectra->data[i];
/* Clamp Mel values lower than mmax - top_db, add offset, and scale.
* Config top_db and mel_offset are Q9.7, shift to Q9.23.
*/
clamp_value = state->mmax - ((int32_t)config->top_db << 16);
for (j = 0; j < state->dct.num_in; j++) {
mel_value = state->mel_log_32[j];
if (mel_value < clamp_value)
mel_value = clamp_value;

/* Q8.7 * Q4.12, result 8.7 */
s = (int32_t)mel_value + config->mel_offset;
state->mel_spectra->data[i] =
sat_int16(Q_MULTSR_32X32(s, config->mel_scale, 7, 12, 7));
/* Q9.23 * Q4.12, result Q9.23 */
s = (int64_t)mel_value + ((int32_t)config->mel_offset << 16);
state->mel_log_32[j] =
sat_int32(Q_MULTSR_32X32(s, config->mel_scale, 23, 12, 23));
}

/* Store Q9.7 version in mel_spectra for s16 output mode */
for (j = 0; j < state->dct.num_in; j++)
state->mel_spectra->data[j] =
sat_int16(state->mel_log_32[j] >> 16);

/* Enable this to check mmax decay */
comp_dbg(dev, "state->mmax = %d", state->mmax);
} else {
/* Convert Q9.23 to Q9.7 for 16-bit DCT */
for (j = 0; j < state->dct.num_in; j++)
state->mel_spectra->data[j] =
sat_int16(state->mel_log_32[j] >> 16);

/* Multiply Mel spectra with DCT matrix to get cepstral coefficients */
mat_init_16b(state->cepstral_coef, 1, state->dct.num_out, 7); /* Q8.7 */
mat_init_16b(state->cepstral_coef, 1, state->dct.num_out, 7); /* Q9.7 */
mat_multiply(state->mel_spectra, state->dct.matrix, state->cepstral_coef);

/* Apply cepstral lifter */
Expand All @@ -189,6 +204,62 @@ static int mfcc_stft_process(const struct comp_dev *dev, struct mfcc_comp_data *
return cc_count;
}

void mfcc_fill_fft_buffer(struct mfcc_state *state)
{
struct mfcc_buffer *buf = &state->buf;
struct mfcc_fft *fft = &state->fft;
#if MFCC_FFT_BITS == 16
int16_t *d = &fft->fft_buf[fft->fft_fill_start_idx].real;
const int fft_elem_inc = sizeof(fft->fft_buf[0]) / sizeof(int16_t);
#else
int32_t *d = &fft->fft_buf[fft->fft_fill_start_idx].real;
const int fft_elem_inc = sizeof(fft->fft_buf[0]) / sizeof(int32_t);
#endif
int16_t *prev = state->prev_data;
int16_t *prev_end = prev + state->prev_data_size;
int16_t *r = buf->r_ptr;
int copied;
int nmax;
int n;
int j;

/* Copy overlapped samples from state buffer. The fft_buf has been
* cleared by caller so imaginary part remains zero.
*/
while (prev < prev_end) {
*d = *prev++;
d += fft_elem_inc;
}

/* Copy hop size of new data from circular buffer */
for (copied = 0; copied < fft->fft_hop_size; copied += n) {
nmax = fft->fft_hop_size - copied;
n = mfcc_buffer_samples_without_wrap(buf, r);
n = MIN(n, nmax);
for (j = 0; j < n; j++) {
*d = *r++;
d += fft_elem_inc;
}
r = mfcc_buffer_wrap(buf, r);
}

buf->s_avail -= copied;
buf->s_free += copied;
buf->r_ptr = r;

/* Copy for next time data back to overlap buffer */
#if MFCC_FFT_BITS == 16
d = (int16_t *)&fft->fft_buf[fft->fft_fill_start_idx + fft->fft_hop_size].real;
#else
d = (int32_t *)&fft->fft_buf[fft->fft_fill_start_idx + fft->fft_hop_size].real;
#endif
prev = state->prev_data;
while (prev < prev_end) {
*prev++ = *d;
d += fft_elem_inc;
}
}

#if CONFIG_FORMAT_S16LE
static int16_t *mfcc_sink_copy_zero_s16(const struct audio_stream *sink, int16_t *w_ptr,
int samples)
Expand Down Expand Up @@ -338,6 +409,7 @@ void mfcc_s24_default(struct processing_module *mod, struct input_stream_buffer
int sink_samples;
int remain_s32;
int to_copy;
int k;

/* Get samples from source buffer */
mfcc_source_copy_s24(bsource, buf, &state->emph, frames, state->source_channel);
Expand All @@ -347,10 +419,15 @@ void mfcc_s24_default(struct processing_module *mod, struct input_stream_buffer

/* If new output produced, set up pointer into scratch data */
if (num_ceps > 0) {
if (state->mel_only)
state->out_data_ptr = state->mel_spectra->data;
else
if (state->mel_only) {
/* Convert mel_log_32 from Q9.23 to Q9.15 in-place */
for (k = 0; k < num_ceps; k++)
state->mel_log_32[k] >>= 8;

state->out_data_ptr_32 = state->mel_log_32;
} else {
state->out_data_ptr = state->cepstral_coef->data;
}

state->out_remain = num_ceps;
state->magic_pending = true;
Expand All @@ -366,18 +443,30 @@ void mfcc_s24_default(struct processing_module *mod, struct input_stream_buffer
state->magic_pending = false;
}

/* Write cepstral/mel data packed as int32_t from scratch buffer */
remain_s32 = (state->out_remain + 1) / 2;
to_copy = MIN(remain_s32, sink_samples);
if (to_copy > 0) {
w_ptr = mfcc_sink_copy_data_s32(sink, w_ptr, to_copy,
(int32_t *)state->out_data_ptr);
state->out_data_ptr += to_copy * 2;
state->out_remain -= to_copy * 2;
if (state->out_remain < 0)
state->out_remain = 0;

sink_samples -= to_copy;
if (state->mel_only) {
/* Write 32-bit mel data Q9.15, one value per int32_t */
to_copy = MIN(state->out_remain, sink_samples);
if (to_copy > 0) {
w_ptr = mfcc_sink_copy_data_s32(sink, w_ptr, to_copy,
state->out_data_ptr_32);
state->out_data_ptr_32 += to_copy;
state->out_remain -= to_copy;
sink_samples -= to_copy;
}
} else {
/* Write cepstral data packed as int32_t from scratch buffer */
remain_s32 = (state->out_remain + 1) / 2;
to_copy = MIN(remain_s32, sink_samples);
if (to_copy > 0) {
w_ptr = mfcc_sink_copy_data_s32(sink, w_ptr, to_copy,
(int32_t *)state->out_data_ptr);
state->out_data_ptr += to_copy * 2;
state->out_remain -= to_copy * 2;
if (state->out_remain < 0)
state->out_remain = 0;

sink_samples -= to_copy;
}
}

/* Zero-fill remaining sink samples */
Expand Down Expand Up @@ -409,10 +498,11 @@ void mfcc_s32_default(struct processing_module *mod, struct input_stream_buffer

/* If new output produced, set up pointer into scratch data */
if (num_ceps > 0) {
if (state->mel_only)
state->out_data_ptr = state->mel_spectra->data;
else
if (state->mel_only) {
state->out_data_ptr_32 = state->mel_log_32;
} else {
state->out_data_ptr = state->cepstral_coef->data;
}

state->out_remain = num_ceps;
state->magic_pending = true;
Expand All @@ -428,18 +518,30 @@ void mfcc_s32_default(struct processing_module *mod, struct input_stream_buffer
state->magic_pending = false;
}

/* Write cepstral/mel data packed as int32_t from scratch buffer */
remain_s32 = (state->out_remain + 1) / 2;
to_copy = MIN(remain_s32, sink_samples);
if (to_copy > 0) {
w_ptr = mfcc_sink_copy_data_s32(sink, w_ptr, to_copy,
(int32_t *)state->out_data_ptr);
state->out_data_ptr += to_copy * 2;
state->out_remain -= to_copy * 2;
if (state->out_remain < 0)
state->out_remain = 0;

sink_samples -= to_copy;
if (state->mel_only) {
/* Write 32-bit mel data Q9.23, one value per int32_t */
to_copy = MIN(state->out_remain, sink_samples);
if (to_copy > 0) {
w_ptr = mfcc_sink_copy_data_s32(sink, w_ptr, to_copy,
state->out_data_ptr_32);
state->out_data_ptr_32 += to_copy;
state->out_remain -= to_copy;
sink_samples -= to_copy;
}
} else {
/* Write cepstral data packed as int32_t from scratch buffer */
remain_s32 = (state->out_remain + 1) / 2;
to_copy = MIN(remain_s32, sink_samples);
if (to_copy > 0) {
w_ptr = mfcc_sink_copy_data_s32(sink, w_ptr, to_copy,
(int32_t *)state->out_data_ptr);
state->out_data_ptr += to_copy * 2;
state->out_remain -= to_copy * 2;
if (state->out_remain < 0)
state->out_remain = 0;

sink_samples -= to_copy;
}
}

/* Zero-fill remaining sink samples */
Expand Down
Loading
Loading