Skip to content

Commit

Permalink
copier: gain: add processing functions
Browse files Browse the repository at this point in the history
Add HIFI and generic versions of gain processing for
32-bit and 16-bit container size.

Signed-off-by: Ievgen Ganakov <[email protected]>
  • Loading branch information
iganakov committed Sep 30, 2024
1 parent 957f1a2 commit 0955c2f
Show file tree
Hide file tree
Showing 4 changed files with 554 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/audio/copier/copier_gain.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,42 @@ int copier_gain_set_params(struct comp_dev *dev, struct dai_data *dd)

return ret;
}

int copier_gain_input(struct comp_dev *dev, struct comp_buffer *buff,
struct copier_gain_params *gain_params,
enum copier_gain_envelope_dir dir, uint32_t stream_bytes)
{
enum sof_ipc_frame frame_fmt = audio_stream_get_frm_fmt(&buff->stream);
uint32_t frames = stream_bytes / audio_stream_frame_bytes(&buff->stream);
enum copier_gain_state state;

if (!gain_params)
return -EINVAL;

state = copier_gain_eval_state(gain_params);

comp_dbg(dev, "copier selected gain state %d", state);

switch (frame_fmt) {
case SOF_IPC_FRAME_S16_LE:
return copier_gain_input16(buff, state, dir, gain_params, frames);
case SOF_IPC_FRAME_S32_LE:
return copier_gain_input32(buff, state, dir, gain_params, frames);
default:
comp_err(dev, "unsupported frame format %d for copier gain", frame_fmt);
return -EINVAL;
}
}

enum copier_gain_state copier_gain_eval_state(struct copier_gain_params *gain_params)
{
enum copier_gain_state state = STATIC_GAIN;

if (gain_params->silence_sg_count < gain_params->silence_sg_length)
state = MUTE;
else if ((gain_params->fade_in_sg_count < gain_params->fade_sg_length) &&
(gain_params->fade_sg_length != 0))
state = TRANS_GAIN;

return state;
}
54 changes: 54 additions & 0 deletions src/audio/copier/copier_gain.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

/* 16x2 store operation requires shift to middle part of 32 bit register */
#define I64_TO_I16_SHIFT 48
#define I64_TO_I32_SHIFT 32
#define MIDDLE_PART_SHIFT 8

/* Unit gain in q10 format applied by default */
Expand Down Expand Up @@ -142,4 +143,57 @@ int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd,
struct ipc4_base_module_cfg *ipc4_cfg,
uint32_t fade_period, uint32_t frames);

/**
* @brief Applies gain to a 16-bit container size.
*
* This function applies gain to the input audio buffer. There are three gain modes
* supported: static gain, mute, and gain transition (fade-in or fade-out).
*
* @param buff Pointer to the input audio buffer.
* @param state The state of the gain processing.
* @param dir direction of the gain envelope change.
* @param frames The number of frames to be processed.
*/
int copier_gain_input16(struct comp_buffer *buff, enum copier_gain_state state,
enum copier_gain_envelope_dir dir,
struct copier_gain_params *gain_params, uint32_t frames);

/**
* @brief Applies gain to a 32-bit container size.
*
* This function applies gain to the input audio buffer. There are three gain modes
* supported: static gain, mute, and gain transition (fade-in or fade-out).
*
* @param buff Pointer to the input audio buffer.
* @param state The state of the gain processing.
* @param dir Direction of the gain envelope change.
* @param gain_params The pointer to the copier_gain_params structure.
* @param frames The number of frames to be processed.
*/
int copier_gain_input32(struct comp_buffer *buff, enum copier_gain_state state,
enum copier_gain_envelope_dir dir,
struct copier_gain_params *gain_params, uint32_t frames);

/**
* @brief Applies gain to the input audio buffer, selects the appropriate gain method.
*
* @param dev The pointer to the comp_dev structure representing the audio component device.
* @param buff The pointer to the comp_buffer structure representing the input buffer.
* @param gain_params The pointer to the copier_gain_params structure.
* @param dir Direction of the gain envelope change.
* @param stream_bytes The number of bytes in the input buffer.
* @return 0 on success, negative error code on failure.
*/
int copier_gain_input(struct comp_dev *dev, struct comp_buffer *buff,
struct copier_gain_params *gain_params,
enum copier_gain_envelope_dir dir, uint32_t stream_bytes);

/**
* Evaluates appropriate gain mode based on the current gain parameters
*
* @param gain_params The pointer to the copier_gain_params structure.
* @return The state of the copier gain (enum copier_gain_state).
*/
enum copier_gain_state copier_gain_eval_state(struct copier_gain_params *gain_params);

#endif /* __SOF_COPIER_GAIN_H__ */
182 changes: 182 additions & 0 deletions src/audio/copier/copier_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,188 @@ int copier_gain_set_fade_params(struct comp_dev *dev, struct dai_data *dd,
return 0;
}

int copier_gain_input16(struct comp_buffer *buff, enum copier_gain_state state,
enum copier_gain_envelope_dir dir,
struct copier_gain_params *gain_params, uint32_t frames)
{
int16_t *dst = audio_stream_get_rptr(&buff->stream);
const int nch = audio_stream_get_channels(&buff->stream);
int samples = frames * nch;
int16_t gain_env[MAX_GAIN_COEFFS_CNT] = {0};
int16_t gain_env_sq;
int16_t gain_env_i16;
int16_t *dst_tmp;
int16_t gain;
int nmax, i, j;

switch (state) {
case STATIC_GAIN:
/* static gain */
if (gain_params->unity_gain)
return 0;

while (samples) {
nmax = audio_stream_samples_without_wrap_s16(&buff->stream, dst);
nmax = MIN(samples, nmax);

for (j = 0; j < nch; j++) {
dst_tmp = dst + j;
gain = gain_params->gain_coeffs[j];
for (i = 0; i < nmax; i += nch)
dst_tmp[i] = q_multsr_sat_16x16(dst_tmp[i], gain,
GAIN_Q10_INT_SHIFT);
}
samples -= nmax;
dst = audio_stream_wrap(&buff->stream, dst + nmax);
}
break;
case MUTE:
while (samples) {
nmax = audio_stream_samples_without_wrap_s16(&buff->stream, dst);
nmax = MIN(samples, nmax);
size_t zeroed_bytes = nmax * sizeof(int16_t);
/* Apply mute */
memset_s(dst, zeroed_bytes, 0, zeroed_bytes);
samples -= nmax;
dst = audio_stream_wrap(&buff->stream, dst + nmax);
}
break;
case TRANS_GAIN:
while (samples) {
nmax = audio_stream_samples_without_wrap_s16(&buff->stream, dst);
nmax = MIN(samples, nmax);

/* Precalculate gain envelope */
gain_env_i16 = gain_params->gain_env >> I64_TO_I16_SHIFT;
for (i = 0; i < MAX_GAIN_COEFFS_CNT; i++)
gain_env[i] = gain_env_i16 + gain_params->init_gain[i];

/* Apply fade */
for (j = 0; j < nch; j++) {
dst += j;
/* Quadratic fade part in Q15 format*/
gain_env_sq = q_multsr_16x16(gain_env[j], gain_env[j], 15);

/* Calculate gain value. Gain coeffs in Q10 format but
* gain_env_sq in Q15. So shifting result by 15 bits.
*/
gain = q_multsr_16x16(gain_params->gain_coeffs[j],
gain_env_sq, 15);

for (i = 0; i < nmax; i += nch)
dst[i] = q_multsr_sat_16x16(dst[i], gain,
GAIN_Q10_INT_SHIFT);
}
samples -= nmax;
dst = audio_stream_wrap(&buff->stream, dst + nmax);
}
break;
}

if (state == MUTE) {
gain_params->silence_sg_count += frames;
} else if (state == TRANS_GAIN) {
gain_params->fade_in_sg_count += frames;
if (dir == GAIN_ADD)
gain_params->gain_env += gain_params->step_i64 * frames;
else
gain_params->gain_env -= gain_params->step_i64 * frames;
}

return 0;
}

int copier_gain_input32(struct comp_buffer *buff, enum copier_gain_state state,
enum copier_gain_envelope_dir dir,
struct copier_gain_params *gain_params, uint32_t frames)
{
int32_t *dst = audio_stream_get_rptr(&buff->stream);
const int nch = audio_stream_get_channels(&buff->stream);
int samples = frames * nch;
int16_t gain_env[MAX_GAIN_COEFFS_CNT] = {0};
int32_t *dst_tmp;
int16_t gain, gain_env_i16, gain_env_sq;
int nmax, i, j;

switch (state) {
case STATIC_GAIN:
/* static gain */
if (gain_params->unity_gain)
return 0;

while (samples) {
nmax = audio_stream_samples_without_wrap_s32(&buff->stream, dst);
nmax = MIN(samples, nmax);

for (j = 0; j < nch; j++) {
dst_tmp = dst + j;
/* Gain is in Q21.10 format */
gain = gain_params->gain_coeffs[j];
for (i = 0; i < nmax; i += nch)
dst_tmp[i] = q_multsr_sat_32x32(dst_tmp[i], gain,
GAIN_Q10_INT_SHIFT);
}
samples -= nmax;
dst = audio_stream_wrap(&buff->stream, dst + nmax);
}
break;
case MUTE:
while (samples) {
nmax = audio_stream_samples_without_wrap_s32(&buff->stream, dst);
nmax = MIN(samples, nmax);
size_t zeroed_bytes = nmax * sizeof(int32_t);

/* Apply mute*/
memset_s(dst, zeroed_bytes, 0, zeroed_bytes);
samples -= nmax;
dst = audio_stream_wrap(&buff->stream, dst + nmax);
}
break;
case TRANS_GAIN:
while (samples) {
nmax = audio_stream_samples_without_wrap_s32(&buff->stream, dst);
nmax = MIN(samples, nmax);

/* Precalculate gain envelope */
gain_env_i16 = gain_params->gain_env >> I64_TO_I16_SHIFT;
for (i = 0; i < MAX_GAIN_COEFFS_CNT; i++)
gain_env[i] = gain_env_i16 + gain_params->init_gain[i];

/* Apply fade */
for (j = 0; j < nch; j++) {
dst += j;
/* Quadratic fade part in Q15 format*/
gain_env_sq = q_multsr_16x16(gain_env[j], gain_env[j], 15);

/* Calculate gain value. Gain coeffs in Q10 format but
* gain_env_sq in Q15. So shifting result by 15 bits.
*/
gain = q_multsr_16x16(gain_params->gain_coeffs[j],
gain_env_sq, 15);

for (i = 0; i < nmax; i += nch)
dst[i] = q_multsr_sat_32x32(dst[i], gain,
GAIN_Q10_INT_SHIFT);
}
samples -= nmax;
dst = audio_stream_wrap(&buff->stream, dst + nmax);
}
break;
}

if (state == MUTE) {
gain_params->silence_sg_count += frames;
} else if (state == TRANS_GAIN) {
gain_params->fade_in_sg_count += frames;
if (dir == GAIN_ADD)
gain_params->gain_env += gain_params->step_i64 * frames;
else
gain_params->gain_env -= gain_params->step_i64 * frames;
}

return 0;
}

#endif

void copier_update_params(struct copier_data *cd, struct comp_dev *dev,
Expand Down
Loading

0 comments on commit 0955c2f

Please sign in to comment.