Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 367
audio: volume: optimize volume component with HIFI3#5169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -32,6 +32,25 @@ static void vol_setup_circular(const struct audio_stream *buffer) | ||
| AE_SETCEND0(buffer->end_addr); | ||
| } | ||
andrula-song marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| /** | ||
| * \brief store volume gain 4 times for xtensa multi-way intrinsic operations. | ||
| * Simultaneous processing 2 data. | ||
| * \param[in,out] cd Volume component private data. | ||
| * \param[in] channels_count Number of channels to process. | ||
| */ | ||
| static void vol_store_gain(struct vol_data *cd, const int channels_count) | ||
andrula-song marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| { | ||
| int32_t i; | ||
| /* using for loop instead of memcpy_s(), because for loop costs less cycles */ | ||
| for (i = 0; i < channels_count; i++) { | ||
andrula-song marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| cd->vol[i] = cd->volume[i]; | ||
| cd->vol[i + channels_count * 1] = cd->volume[i]; | ||
| cd->vol[i + channels_count * 2] = cd->volume[i]; | ||
| cd->vol[i + channels_count * 3] = cd->volume[i]; | ||
| } | ||
| } | ||
| #if CONFIG_FORMAT_S24LE | ||
| /** | ||
| * \brief HiFi3 enabled volume processing from 24/32 bit to 24/32 or 32 bit. | ||
| @@ -45,50 +64,64 @@ static void vol_s24_to_s24_s32(struct comp_dev *dev, struct audio_stream *sink, | ||
| uint32_t frames) | ||
| { | ||
| struct vol_data *cd = comp_get_drvdata(dev); | ||
| ae_f64 mult; | ||
| ae_f32x2 in_sample = AE_ZERO32(); | ||
| ae_f32x2 out_sample; | ||
| ae_f32x2 volume; | ||
| size_t channel; | ||
| ae_f32x2 *buf; | ||
| ae_f32x2 *buf_end; | ||
| ae_valign inu; | ||
| ae_valign outu; | ||
| int i; | ||
| int shift = 8; | ||
| ae_int32 *in = (ae_int32 *)source->r_ptr; | ||
| ae_int32 *out = (ae_int32 *)sink->w_ptr; | ||
| /* Main processing loop */ | ||
| for (i = 0; i < frames; i++) { | ||
| /* Processing per channel */ | ||
| for (channel = 0; channel < sink->channels; channel++) { | ||
| /* Set source as circular buffer */ | ||
| vol_setup_circular(source); | ||
| /* Load the input sample */ | ||
| AE_L32_XC(in_sample, in, sizeof(ae_int32)); | ||
| /* Load volume */ | ||
| volume = (ae_f32x2)cd->volume[channel]; | ||
| /* Multiply the input sample */ | ||
| mult = AE_MULF32S_LL(volume, AE_SLAA32(in_sample, 8)); | ||
| /* Multiplication of Q1.31 x Q1.31 gives Q1.63. | ||
| * Now multiplication is Q8.16 x Q1.31, the result | ||
| * is Q9.48. Need to shift right by one to get Q17.47 | ||
| * compatible format for round. | ||
| */ | ||
| out_sample = AE_ROUND32F48SSYM(AE_SRAI64(mult, 1)); | ||
| /* Shift for S24_LE */ | ||
| out_sample = AE_SRAA32RS(out_sample, shift); | ||
| out_sample = AE_SLAA32S(out_sample, shift); | ||
| out_sample = AE_SRAA32(out_sample, shift); | ||
| /* Set sink as circular buffer */ | ||
| vol_setup_circular(sink); | ||
| /* Store the output sample */ | ||
| AE_S32_L_XC(out_sample, out, sizeof(ae_int32)); | ||
| } | ||
| ae_f32x2 *in = (ae_f32x2 *)source->r_ptr; | ||
| ae_f32x2 *out = (ae_f32x2 *)sink->w_ptr; | ||
| ae_f32x2 *vol; | ||
| const int channels_count = sink->channels; | ||
| const int inc = sizeof(ae_f32x2); | ||
| const int samples = channels_count * frames; | ||
| /** to ensure the adsress is 8-byte aligned and avoid risk of | ||
| * error loading of volume gain while the cd->vol would be set | ||
| * as circular buffer | ||
| */ | ||
| vol_store_gain(cd, channels_count); | ||
| buf = (ae_f32x2 *)cd->vol; | ||
| buf_end = (ae_f32x2 *)(cd->vol + channels_count * 2); | ||
| vol = (ae_f32x2 *)buf; | ||
| /* use alignment register to prime the memory to | ||
| * avoid risk of buf not aligned to 64 bits. | ||
| */ | ||
| AE_LA32X2POS_PC(inu, in); | ||
| AE_SA64POS_FC(outu, out); | ||
| /* process two continuous sample data once */ | ||
| for (i = 0; i < samples; i += 2) { | ||
| /* Set buf who stores the volume gain data as circular buffer */ | ||
| AE_SETCBEGIN0(buf); | ||
| AE_SETCEND0(buf_end); | ||
| /* Load the volume value */ | ||
| AE_L32X2_XC(volume, vol, inc); | ||
| /* Set source as circular buffer */ | ||
| vol_setup_circular(source); | ||
| /* Load the input sample */ | ||
| AE_LA32X2_IC(in_sample, inu, in); | ||
| /* Multiply the input sample */ | ||
| out_sample = AE_MULFP32X2RS(AE_SLAA32S(volume, 7), AE_SLAA32(in_sample, 8)); | ||
| /* Shift for S24_LE */ | ||
| out_sample = AE_SLAA32S(out_sample, 8); | ||
| out_sample = AE_SRAA32(out_sample, 8); | ||
| /* Set sink as circular buffer */ | ||
| vol_setup_circular(sink); | ||
| /* Store the output sample */ | ||
| AE_SA32X2_IC(out_sample, outu, out); | ||
| } | ||
| } | ||
| #endif /* CONFIG_FORMAT_S24LE */ | ||
| @@ -106,51 +139,63 @@ static void vol_s32_to_s24_s32(struct comp_dev *dev, struct audio_stream *sink, | ||
| uint32_t frames) | ||
| { | ||
| struct vol_data *cd = comp_get_drvdata(dev); | ||
| ae_f64 mult; | ||
| ae_f32x2 in_sample = AE_ZERO32(); | ||
| ae_f32x2 out_sample; | ||
| ae_f32x2 volume; | ||
| size_t channel; | ||
| int shift = 0; | ||
| int i; | ||
| ae_int32 *in = (ae_int32 *)source->r_ptr; | ||
| ae_int32 *out = (ae_int32 *)sink->w_ptr; | ||
| /* Main processing loop */ | ||
| for (i = 0; i < frames; i++) { | ||
| /* Processing per channel */ | ||
| for (channel = 0; channel < sink->channels; channel++) { | ||
| /* Set source as circular buffer */ | ||
| vol_setup_circular(source); | ||
| /* Load the input sample */ | ||
| AE_L32_XC(in_sample, in, sizeof(ae_int32)); | ||
| /* Load volume */ | ||
| volume = (ae_f32x2)cd->volume[channel]; | ||
| /* Multiply the input sample */ | ||
| mult = AE_MULF32S_LL(volume, in_sample); | ||
| /* Multiplication of Q1.31 x Q1.31 gives Q1.63. | ||
| * Now multiplication is Q8.16 x Q1.31, the result | ||
| * is Q9.48. Need to shift right by one to get Q17.47 | ||
| * compatible format for round. | ||
| */ | ||
| out_sample = AE_ROUND32F48SSYM(AE_SRAI64(mult, 1)); | ||
| /* Shift for S24_LE */ | ||
| out_sample = AE_SRAA32RS(out_sample, shift); | ||
| out_sample = AE_SLAA32S(out_sample, shift); | ||
| out_sample = AE_SRAA32(out_sample, shift); | ||
| /* Set sink as circular buffer */ | ||
| vol_setup_circular(sink); | ||
| /* Store the output sample */ | ||
| AE_S32_L_XC(out_sample, out, sizeof(ae_int32)); | ||
| } | ||
| ae_f64 mult0; | ||
| ae_f64 mult1; | ||
| ae_f32x2 *buf; | ||
| ae_f32x2 *buf_end; | ||
| ae_f32x2 *vol; | ||
| const int inc = sizeof(ae_f32x2); | ||
| const int channels_count = sink->channels; | ||
| const int samples = channels_count * frames; | ||
| ae_f32x2 *in = (ae_f32x2 *)source->r_ptr; | ||
| ae_f32x2 *out = (ae_f32x2 *)sink->w_ptr; | ||
| ae_valign inu; | ||
| ae_valign outu; | ||
| /** to ensure the address is 8-byte aligned and avoid risk of | ||
| * error loading of volume gain while the cd->vol would be set | ||
| * as circular buffer | ||
| */ | ||
| vol_store_gain(cd, channels_count); | ||
| buf = (ae_f32x2 *)cd->vol; | ||
| buf_end = (ae_f32x2 *)(cd->vol + channels_count * 2); | ||
| vol = (ae_f32x2 *)buf; | ||
| /* use alignment register to prime the memory to | ||
| * avoid risk of buf not aligned to 64 bits. | ||
| */ | ||
| AE_LA32X2POS_PC(inu, in); | ||
| AE_SA64POS_FC(outu, out); | ||
| /* process two continuous sample data once */ | ||
| for (i = 0; i < samples; i += 2) { | ||
| /* Set buf who stores the volume gain data as circular buffer */ | ||
| AE_SETCBEGIN0(buf); | ||
| AE_SETCEND0(buf_end); | ||
| /* Load the volume value */ | ||
| AE_L32X2_XC(volume, vol, inc); | ||
| /* Set source as circular buffer */ | ||
| vol_setup_circular(source); | ||
| /* Load the input sample */ | ||
| AE_LA32X2_IC(in_sample, inu, in); | ||
| mult0 = AE_MULF32S_HH(volume, in_sample); | ||
| mult0 = AE_SRAI64(mult0, 1); | ||
| mult1 = AE_MULF32S_LL(volume, in_sample); | ||
| mult1 = AE_SRAI64(mult1, 1); | ||
| out_sample = AE_ROUND32X2F48SSYM(mult0, mult1); | ||
| vol_setup_circular(sink); | ||
| AE_SA32X2_IC(out_sample, outu, out); | ||
| } | ||
| } | ||
| #endif /* CONFIG_FORMAT_S32LE */ | ||
| @@ -166,44 +211,73 @@ static void vol_s16_to_s16(struct comp_dev *dev, struct audio_stream *sink, | ||
| const struct audio_stream *source, uint32_t frames) | ||
| { | ||
| struct vol_data *cd = comp_get_drvdata(dev); | ||
| ae_f64 mult; | ||
| ae_f32x2 volume; | ||
| ae_f32x2 out_sample; | ||
| ae_f32x2 volume0, volume1; | ||
| ae_f32x2 out_sample0, out_sample1; | ||
| ae_f16x4 in_sample = AE_ZERO16(); | ||
| size_t channel; | ||
| ae_f16x4 out_sample = AE_ZERO16(); | ||
| int i; | ||
| ae_int16 *in = (ae_int16 *)source->r_ptr; | ||
| ae_int16 *out = (ae_int16 *)sink->w_ptr; | ||
| /* Main processing loop */ | ||
| for (i = 0; i < frames; i++) { | ||
| /* Processing per channel */ | ||
| for (channel = 0; channel < sink->channels; channel++) { | ||
| /* Set source as circular buffer */ | ||
| vol_setup_circular(source); | ||
| /* Load the input sample */ | ||
| AE_L16_XC(in_sample, in, sizeof(ae_int16)); | ||
| /* Load volume */ | ||
| volume = (ae_f32x2)cd->volume[channel]; | ||
| /* Multiply the input sample */ | ||
| mult = AE_MULF32X16_L0(volume, in_sample); | ||
| /* Multiply of Q1.31 x Q1.15 gives Q1.47. Multiply of | ||
| * Q8.16 x Q1.15 gives Q8.32, so need to shift left | ||
| * by 31 to get Q1.63. Sample is Q1.31. | ||
| */ | ||
| out_sample = AE_ROUND32F64SSYM(AE_SLAI64S(mult, 31)); | ||
| /* Set sink as circular buffer */ | ||
| vol_setup_circular(sink); | ||
| /* Round to Q1.15 and store the output sample */ | ||
| AE_S16_0_XC(AE_ROUND16X4F32SSYM(out_sample, out_sample), | ||
| out, sizeof(ae_int16)); | ||
| } | ||
| ae_f32x2 *buf; | ||
| ae_f32x2 *buf_end; | ||
| ae_f32x2 *vol; | ||
| ae_valign inu; | ||
| ae_valign outu; | ||
| ae_f16x4 *in = (ae_f16x4 *)source->r_ptr; | ||
| ae_f16x4 *out = (ae_f16x4 *)sink->w_ptr; | ||
| const int channels_count = sink->channels; | ||
| const int inc = sizeof(ae_f32x2); | ||
| const int samples = channels_count * frames; | ||
| /** to ensure the adsress is 8-byte aligned and avoid risk of | ||
| * error loading of volume gain while the cd->vol would be set | ||
| * as circular buffer | ||
| */ | ||
| vol_store_gain(cd, channels_count); | ||
| buf = (ae_f32x2 *)cd->vol; | ||
| buf_end = (ae_f32x2 *)(cd->vol + channels_count * 4); | ||
| vol = buf; | ||
| /* | ||
| * use alignment register to prime the volume memory to avoid | ||
| * risk of buf not aligned to 8-byte | ||
| */ | ||
| AE_LA16X4POS_PC(inu, in); | ||
| AE_SA64POS_FC(outu, out); | ||
| for (i = 0; i < samples; i += 4) { | ||
| /* Set buf as circular buffer */ | ||
| AE_SETCBEGIN0(buf); | ||
| AE_SETCEND0(buf_end); | ||
| /* load first two volume gain */ | ||
| AE_L32X2_XC(volume0, vol, inc); | ||
| /* load second two volume gain */ | ||
| AE_L32X2_XC(volume1, vol, inc); | ||
| /* Q8.16 to Q9.23 */ | ||
| volume0 = AE_SLAA32(volume0, 7); | ||
| volume1 = AE_SLAA32(volume1, 7); | ||
| /* Set source as circular buffer */ | ||
| vol_setup_circular(source); | ||
| /* Load the input sample */ | ||
| AE_LA16X4_IC(in_sample, inu, in); | ||
| /* Multiply the input sample */ | ||
| out_sample0 = AE_MULFP32X16X2RS_H(volume0, in_sample); | ||
| out_sample1 = AE_MULFP32X16X2RS_L(volume1, in_sample); | ||
| /* Q9.23 to Q1.31 */ | ||
| out_sample0 = AE_SLAA32S(out_sample0, 8); | ||
| out_sample1 = AE_SLAA32S(out_sample1, 8); | ||
| /* Set sink as circular buffer */ | ||
| vol_setup_circular(sink); | ||
| /* store the output */ | ||
| out_sample = AE_ROUND16X4F32SSYM(out_sample0, out_sample1); | ||
| AE_SA16X4_IC(out_sample, outu, out); | ||
| } | ||
| } | ||
| #endif /* CONFIG_FORMAT_S16LE */ | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.