pcm_converter: HiFi3 implementation of conversion between float and fixed

Used method need floating point unit in DSP core.
Vectorized conversion functions are inaccessible for used cores.

Signed-off-by: Karol Trzcinski <karolx.trzcinski@linux.intel.com>
This commit is contained in:
Karol Trzcinski 2020-04-28 08:17:41 +02:00 committed by Liam Girdwood
parent a264e77011
commit 56a660be28
3 changed files with 308 additions and 2 deletions

View File

@ -8,6 +8,7 @@
* \file audio/pcm_converter/pcm_converter_hifi3.c
* \brief PCM converter HiFi3 processing implementation
* \authors Tomasz Lauda <tomasz.lauda@linux.intel.com>
* \authors Karol Trzcinski <karolx.trzcinski@linux.intel.com>
*/
#include <sof/audio/pcm_converter.h>
@ -22,6 +23,10 @@
#include <stddef.h>
#include <stdint.h>
#if XCHAL_HAVE_FP
#include <xtensa/tie/xt_FP.h>
#endif
/**
* \brief Sets buffer to be circular using HiFi3 functions.
* \param[in,out] buffer Circular buffer.
@ -603,6 +608,291 @@ static void pcm_convert_s32_to_s24(const struct audio_stream *source,
#endif /* CONFIG_FORMAT_S24LE && CONFIG_FORMAT_S32LE */
#if XCHAL_HAVE_FP
#if CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S16LE
/**
* \brief HiFi3 enabled PCM conversion from 16 bit to IEEE-754 float.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_s16_to_f_lin(const void *psrc, void *pdst,
uint32_t samples)
{
const ae_int16 *in = psrc;
xtfloat *out = pdst;
ae_int16x4 sample = AE_ZERO16();
xtfloat fl;
int i = 0;
while (i < samples) {
/* load one 16 bit sample */
AE_L16_XC(sample, in, sizeof(ae_int16));
/* run conversion */
fl = XT_FLOAT_S((ae_int16)sample, 15);
/* store one float sample */
/* need address align to 32 bits */
XT_xtfloat_storeip(fl, out, sizeof(fl));
++i;
}
}
/**
* \brief HiFi3 enabled PCM conversion from IEEE-754 float to 16 bit.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst,
uint32_t samples)
{
const xtfloat *in = psrc;
ae_int16x4 *out = pdst;
xtfloat x;
int y;
int i = 0;
while (i < samples) {
/* load one 32 bit sample */
XT_xtfloat_loadip(x, in, sizeof(x));
/* shift and round */
y = XT_ROUND_S(x, 15);
/* store one 16 bit sample */
AE_S16_0_IP(y, (ae_int16 *)out, sizeof(ae_int16));
++i;
}
}
/**
* \brief HiFi3 enabled PCM conversion from 16 bit to IEEE-754 float.
* \param[in] source Source buffer.
* \param[in,out] sink Destination buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_s16_to_f(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
pcm_convert_as_linear(source, ioffset, sink, ooffset, samples,
pcm_convert_s16_to_f_lin);
}
/**
* \brief HiFi3 enabled PCM conversion from IEEE-754 float to 16 bit.
* \param[in] source Source buffer.
* \param[in,out] sink Destination buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_f_to_s16(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
pcm_convert_as_linear(source, ioffset, sink, ooffset, samples,
pcm_convert_f_to_s16_lin);
}
#endif /* CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S16LE */
#if CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S24LE
/**
* \brief HiFi3 enabled PCM conversion from 24 bit to IEEE-754 float.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_s24_to_f_lin(const void *psrc, void *pdst,
uint32_t samples)
{
const ae_int32 *in = psrc;
xtfloat *out = pdst;
ae_int32x2 sample = AE_ZERO32();
xtfloat fl;
const xtfloat ratio = (xtfloat)(1.f / (1 << (23 - 15)));
int i = 0;
while (i < samples) {
/* load one 24 bit sample */
AE_L32_XC(sample, in, sizeof(*in));
/* extend sign */
sample = AE_SRAI32(AE_SLAI32(sample, 8), 8);
/* run conversion */
fl = XT_FLOAT_S(sample, 15);
fl = fl * ratio;
/* store one 32 bit float sample */
/* need address align to 32 bits */
XT_xtfloat_storeip(fl, out, sizeof(fl));
++i;
}
}
/**
* \brief HiFi3 enabled PCM conversion from IEEE-754 float to 24 bit.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst,
uint32_t samples)
{
const xtfloat *in = psrc;
ae_int32 *out = pdst;
xtfloat x;
ae_int32x2 y1;
int i = 0;
const xtfloat ratio = (xtfloat)(1 << (23 - 15));
while (i < samples) {
/* load one 32 bit sample */
/* need address align to 32 bits */
XT_xtfloat_loadxp(x, in, sizeof(x));
/* shift and round */
x = x * ratio;
y1 = XT_ROUND_S(x, 15);
y1 = AE_SAT24S((ae_f32x2)y1);
/* store one 24 bit sample in 32 bit memory size */
AE_S32_L_IP(y1, (ae_int32 *)out, sizeof(*out));
++i;
}
}
/**
* \brief HiFi3 enabled PCM conversion from 24 bit to IEEE-754 float.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_s24_to_f(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
pcm_convert_as_linear(source, ioffset, sink, ooffset, samples,
pcm_convert_s24_to_f_lin);
}
/**
* \brief HiFi3 enabled PCM conversion from IEEE-754 float to 24 bit.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_f_to_s24(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
pcm_convert_as_linear(source, ioffset, sink, ooffset, samples,
pcm_convert_f_to_s24_lin);
}
#endif /* CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_24LE */
#if CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S32LE
/**
* \brief HiFi3 enabled PCM conversion from 32 bit to IEEE-754 float.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_s32_to_f_lin(const void *psrc, void *pdst,
uint32_t samples)
{
const ae_int32 *in = psrc;
xtfloat *out = pdst;
ae_int32x2 sample = AE_ZERO32();
xtfloat fl;
const xtfloat ratio = (xtfloat)(1.f / (1ul << (31 - 15)));
int i = 0;
while (i < samples) {
/* load one 32 bit sample */
AE_L32_XC(sample, in, sizeof(*in));
/* run conversion */
fl = XT_FLOAT_S(sample, 15);
fl = fl * ratio;
/* store one 32 bit float sample */
/* need address align to 32 bits */
XT_xtfloat_storeip(fl, out, sizeof(fl));
++i;
}
}
/**
* \brief HiFi3 enabled PCM conversion from IEEE-754 float to 32 bit.
* \param[in] psrc source linear buffer.
* \param[out] pdst destination linear buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst,
uint32_t samples)
{
const xtfloat *in = psrc;
ae_int32 *out = pdst;
xtfloat x;
ae_int32x2 y1;
int i = 0;
const xtfloat ratio = (xtfloat)(1ul << (31 - 15));
while (i < samples) {
/* load one 32 bit sample */
/* need address align to 32 bits */
XT_xtfloat_loadxp(x, in, sizeof(x));
/* shift and round */
x = x * ratio;
y1 = XT_ROUND_S(x, 15);
/* store one 32 bit sample */
AE_S32_L_IP(y1, (ae_int32 *)out, sizeof(*out));
++i;
}
}
/**
* \brief HiFi3 enabled PCM conversion from 32 bit to IEEE-754 float.
* \param[in] source Source buffer.
* \param[in,out] sink Destination buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_s32_to_f(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
pcm_convert_as_linear(source, ioffset, sink, ooffset, samples,
pcm_convert_s32_to_f_lin);
}
/**
* \brief HiFi3 enabled PCM conversion from IEEE-754 float to 32 bit.
* \param[in] source Source buffer.
* \param[in,out] sink Destination buffer.
* \param[in] samples Number of samples to process.
*/
static void pcm_convert_f_to_s32(const struct audio_stream *source,
uint32_t ioffset, struct audio_stream *sink,
uint32_t ooffset, uint32_t samples)
{
pcm_convert_as_linear(source, ioffset, sink, ooffset, samples,
pcm_convert_f_to_s32_lin);
}
#endif /* CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_32LE */
#endif /* XCHAL_HAVE_FP */
const struct pcm_func_map pcm_func_map[] = {
#if CONFIG_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, audio_stream_copy_s16 },
@ -625,6 +915,23 @@ const struct pcm_func_map pcm_func_map[] = {
{ SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32 },
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24 },
#endif /* CONFIG_FORMAT_S32LE && CONFIG_FORMAT_S24LE */
#if XCHAL_HAVE_FP
#if CONFIG_FORMAT_FLOAT
{ SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, audio_stream_copy_s32 },
#endif /* CONFIG_FORMAT_FLOAT */
#if CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S16LE
{ SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s16_to_f },
{ SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_S16_LE, pcm_convert_f_to_s16 },
#endif /* CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S16LE */
#if CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S24LE
{ SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s24_to_f },
{ SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_S24_4LE, pcm_convert_f_to_s24 },
#endif /* CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S24LE */
#if CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S32LE
{ SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s32_to_f },
{ SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_S32_LE, pcm_convert_f_to_s32 },
#endif /* CONFIG_FORMAT_FLOAT && CONFIG_FORMAT_S32LE */
#endif /* XCHAL_HAVE_FP */
};
const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map);

View File

@ -27,7 +27,7 @@ struct audio_stream;
#endif
#ifndef UNIT_TEST
#if XCHAL_HAVE_HIFI3 && CONFIG_FORMAT_CONVERT_HIFI3
#if __XCC__ && XCHAL_HAVE_HIFI3 && CONFIG_FORMAT_CONVERT_HIFI3
#define PCM_CONVERTER_HIFI3
#else
#define PCM_CONVERTER_GENERIC

View File

@ -10,4 +10,3 @@ if(CONFIG_FORMAT_FLOAT)
target_compile_definitions(pcm_float_generic PRIVATE PCM_CONVERTER_GENERIC)
target_link_libraries(pcm_float_generic PRIVATE sof_options)
endif()