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
52 changes: 34 additions & 18 deletions src/audio/src/src.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,47 +34,63 @@

LOG_MODULE_DECLARE(src, CONFIG_SOF_LOG_LEVEL);

static int src_prepare(struct processing_module *mod,
struct sof_source **sources, int num_of_sources,
struct sof_sink **sinks, int num_of_sinks)
/* Set rate table pointers, compute rate indices, and copy filter stages.
* Must be in src.c because src_table1/2, src_in_fs, etc. come from
* the coefficient headers included by this file.
*/
static int src_setup_stages(struct processing_module *mod)
{
struct comp_data *cd = module_get_private_data(mod);
struct src_param *a = &cd->param;
int ret;

comp_info(mod->dev, "entry");

if (num_of_sources != 1 || num_of_sinks != 1)
return -EINVAL;

a->in_fs = src_in_fs;
a->out_fs = src_out_fs;
a->num_in_fs = NUM_IN_FS;
a->num_out_fs = NUM_OUT_FS;
a->max_fir_delay_size_xnch = (PLATFORM_MAX_CHANNELS * MAX_FIR_DELAY_SIZE);
a->max_out_delay_size_xnch = (PLATFORM_MAX_CHANNELS * MAX_OUT_DELAY_SIZE);

src_get_source_sink_params(mod->dev, sources[0], sinks[0]);

ret = src_param_set(mod->dev, cd);
if (ret < 0)
return ret;

ret = src_allocate_copy_stages(mod, a,
src_table1[a->idx_out][a->idx_in],
src_table2[a->idx_out][a->idx_in]);
if (ret < 0)
return ret;
return src_allocate_copy_stages(mod, a,
src_table1[a->idx_out][a->idx_in],
src_table2[a->idx_out][a->idx_in]);
}

ret = src_params_general(mod, sources[0], sinks[0]);
static int src_do_init(struct processing_module *mod)
{
struct comp_data *cd;
int ret;

ret = src_init(mod);
if (ret < 0)
return ret;

return src_prepare_general(mod, sources[0], sinks[0]);
cd = module_get_private_data(mod);
cd->setup_stages = src_setup_stages;

return src_init_stages(mod);
}

static int src_prepare(struct processing_module *mod,
struct sof_source **sources, int num_of_sources,
struct sof_sink **sinks, int num_of_sinks)
{
comp_info(mod->dev, "entry");

if (num_of_sources != 1 || num_of_sinks != 1)
return -EINVAL;

src_get_source_sink_params(mod->dev, sources[0], sinks[0]);

return src_do_prepare(mod, sources[0], sinks[0]);
}

static const struct module_interface src_interface = {
.init = src_init,
.init = src_do_init,
.prepare = src_prepare,
.process = src_process,
.is_ready_to_process = src_is_ready_to_process,
Expand Down
87 changes: 86 additions & 1 deletion src/audio/src/src_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,86 @@ int src_params_general(struct processing_module *mod,
return 0;
}

/* Allocate delay lines and initialize the polyphase SRC filter.
* Assumes that cd->param rate table pointers (in_fs, out_fs, etc.)
* and stage pointers (stage1, stage2) are already set up via
* cd->setup_stages().
*/
int src_allocate_delay_lines(struct processing_module *mod)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why in src_common.c if it's only used with IPC4? Looks like this is duplicating code now for IPC3 and IPC4. Can we not extract and reuse some common functions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Common is more correct place for this, but I did not dare to touch ipc3 as I do not know how to test that code.

{
struct comp_data *cd = module_get_private_data(mod);
struct comp_dev *dev = mod->dev;
size_t delay_lines_size;
int32_t *buffer_start;
int n;
int ret;

/* For LL modules dev->period is already set from the pipeline.
* Compute dev->frames so buffer sizing works.
*/
if (!dev->frames)
component_set_nearest_period_frames(dev, cd->sink_rate);

if (!cd->sink_rate) {
comp_err(dev, "zero sink rate");
return -EINVAL;
}

cd->source_frames = dev->frames * cd->source_rate / cd->sink_rate;
cd->sink_frames = dev->frames;

/* Allocate needed memory for delay lines */
ret = src_buffer_lengths(dev, cd, cd->channels_count);
if (ret < 0) {
comp_err(dev, "src_buffer_lengths() failed");
return ret;
}

delay_lines_size = ALIGN_UP(sizeof(int32_t) * cd->param.total, 8);
if (delay_lines_size == 0) {
comp_err(dev, "delay_lines_size = 0");
return -EINVAL;
}

mod_free(mod, cd->delay_lines);

cd->delay_lines = mod_alloc(mod, delay_lines_size);
if (!cd->delay_lines) {
comp_err(dev, "failed to alloc cd->delay_lines, delay_lines_size = %zu",
delay_lines_size);
return -ENOMEM;
}

memset(cd->delay_lines, 0, delay_lines_size);
buffer_start = cd->delay_lines + ALIGN_UP(cd->param.sbuf_length, 2);

/* Initialize SRC for actual sample rate */
n = src_polyphase_init(&cd->src, &cd->param, buffer_start);

/* Reset stage buffer */
cd->sbuf_r_ptr = cd->delay_lines;
cd->sbuf_w_ptr = cd->delay_lines;
cd->sbuf_avail = 0;

switch (n) {
case 0:
cd->src_func = src_copy_sxx;
break;
case 1:
cd->src_func = src_1s;
break;
case 2:
cd->src_func = src_2s;
break;
default:
comp_info(dev, "missing coefficients for requested rates combination");
cd->src_func = src_fallback;
return -EINVAL;
}

return 0;
}

int src_param_set(struct comp_dev *dev, struct comp_data *cd)
{
struct src_param *a = &cd->param;
Expand Down Expand Up @@ -675,7 +755,12 @@ int src_reset(struct processing_module *mod)
comp_info(mod->dev, "entry");

cd->src_func = src_fallback;
src_polyphase_reset(&cd->src);
src_polyphase_reset_state(&cd->src);

/* Reset stage buffer */
cd->sbuf_r_ptr = cd->delay_lines;
cd->sbuf_w_ptr = cd->delay_lines;
cd->sbuf_avail = 0;

return 0;
}
Expand Down
36 changes: 36 additions & 0 deletions src/audio/src/src_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,37 @@ static inline void src_polyphase_reset(struct polyphase_src *src)
src_state_reset(&src->state2);
}

/**
* src_polyphase_reset_state - reset filter state while preserving structure
*
* Zeros the delay line contents and resets read/write pointers to their
* initial positions. The filter stage pointers, delay line allocations,
* and sizes are preserved.
*/
static inline void src_polyphase_reset_state(struct polyphase_src *src)
{
struct src_state *s1 = &src->state1;
struct src_state *s2 = &src->state2;

if (s1->fir_delay && s1->fir_delay_size)
memset(s1->fir_delay, 0, sizeof(int32_t) * s1->fir_delay_size);

if (s1->out_delay && s1->out_delay_size)
memset(s1->out_delay, 0, sizeof(int32_t) * s1->out_delay_size);

s1->fir_wp = s1->fir_delay ? &s1->fir_delay[s1->fir_delay_size - 1] : NULL;
s1->out_rp = s1->out_delay;

if (s2->fir_delay && s2->fir_delay_size)
memset(s2->fir_delay, 0, sizeof(int32_t) * s2->fir_delay_size);

if (s2->out_delay && s2->out_delay_size)
memset(s2->out_delay, 0, sizeof(int32_t) * s2->out_delay_size);

s2->fir_wp = s2->fir_delay ? &s2->fir_delay[s2->fir_delay_size - 1] : NULL;
s2->out_rp = s2->out_delay;
}

int src_polyphase(struct polyphase_src *src, int32_t x[], int32_t y[],
int n_in);

Expand Down Expand Up @@ -167,6 +198,7 @@ struct comp_data {
int (*src_func)(struct comp_data *cd, struct sof_source *source,
struct sof_sink *sink);
void (*polyphase_func)(struct src_stage_prm *s);
int (*setup_stages)(struct processing_module *mod);
};

#if CONFIG_IPC_MAJOR_4
Expand Down Expand Up @@ -218,6 +250,7 @@ static inline int src_fallback(struct comp_data *cd,
int src_allocate_copy_stages(struct processing_module *mod, struct src_param *prm,
const struct src_stage *stage_src1,
const struct src_stage *stage_src2);
int src_allocate_delay_lines(struct processing_module *mod);
int src_rate_check(const void *spec);
int src_set_params(struct processing_module *mod, struct sof_sink *sink);

Expand All @@ -227,6 +260,9 @@ int src_prepare_general(struct processing_module *mod,
struct sof_source *source,
struct sof_sink *sink);
int src_init(struct processing_module *mod);
int src_init_stages(struct processing_module *mod);
int src_do_prepare(struct processing_module *mod,
struct sof_source *source, struct sof_sink *sink);

int src_copy_sxx(struct comp_data *cd, struct sof_source *source,
struct sof_sink *sink);
Expand Down
24 changes: 24 additions & 0 deletions src/audio/src/src_ipc3.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,27 @@ int src_init(struct processing_module *mod)
return 0;
}

/* IPC3: No filter allocation at init, change ipc3 behavior as little as possible */
int src_init_stages(struct processing_module *mod)
{
return 0;
}

/* IPC3: Full filter setup at prepare time */
int src_do_prepare(struct processing_module *mod,
struct sof_source *source, struct sof_sink *sink)
{
struct comp_data *cd = module_get_private_data(mod);
int ret;

ret = cd->setup_stages(mod);
if (ret < 0)
return ret;

ret = src_params_general(mod, source, sink);
if (ret < 0)
return ret;

return src_prepare_general(mod, source, sink);
}

70 changes: 70 additions & 0 deletions src/audio/src/src_ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,73 @@ __cold int src_init(struct processing_module *mod)
return 0;
}

/* Called after src_init() and setup_stages callback is set.
* Allocate filter stages and delay lines at init time.
*/
int src_init_stages(struct processing_module *mod)
{
struct comp_data *cd = module_get_private_data(mod);
struct comp_dev *dev = mod->dev;
int ret;

ret = cd->setup_stages(mod);
if (ret < 0)
return ret;

/* For DP modules, dev->period is not yet set at init time (it's
* computed in src_set_params at prepare). Derive it here from the
* IPC config's output buffer size so that delay line allocation
* uses correct buffer sizes.
*/
if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP && !dev->frames) {
uint32_t frame_bytes = cd->channels_count * cd->sample_container_bytes;

if (frame_bytes && cd->sink_rate) {
dev->period = 1000000ULL * cd->ipc_config.base.obs /
((uint64_t)frame_bytes * cd->sink_rate);
dev->period /= LL_TIMER_PERIOD_US;
dev->period *= LL_TIMER_PERIOD_US;
component_set_nearest_period_frames(dev, cd->sink_rate);
}
}

return src_allocate_delay_lines(mod);
}

/* At prepare time just verify rates and set downstream params */
int src_do_prepare(struct processing_module *mod,
struct sof_source *source, struct sof_sink *sink)
{
struct comp_data *cd = module_get_private_data(mod);
struct comp_dev *dev = mod->dev;
unsigned int source_channels = source_get_channels(source);
unsigned int source_rate = source_get_rate(source);
int ret;

if (cd->source_rate != source_rate ||
cd->sink_rate != cd->ipc_config.sink_rate) {
comp_err(dev, "rate mismatch: init %u/%u, stream %u/%u",
cd->source_rate, cd->sink_rate,
source_rate, cd->ipc_config.sink_rate);
return -EINVAL;
}

if (cd->channels_count != (int)source_channels) {
comp_err(dev, "channels mismatch: init %d, stream %u",
cd->channels_count, source_channels);
return -EINVAL;
}

ret = src_set_params(mod, sink);
if (ret < 0) {
comp_err(mod->dev, "set params failed.");
return ret;
}

/* Update frame counts with final dev->frames from src_set_params */
cd->source_frames = dev->frames * cd->source_rate / cd->sink_rate;
cd->sink_frames = dev->frames;

return src_prepare_general(mod, source, sink);
}

Loading
Loading