1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019 Intel Corporation. All rights reserved.
4  *
5  * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com>
6  */
7 
8 /**
9  * \file audio/pcm_converter.h
10  * \brief PCM converter header file
11  * \authors Tomasz Lauda <tomasz.lauda@linux.intel.com>
12  */
13 
14 #ifndef __SOF_AUDIO_PCM_CONVERTER_H__
15 #define __SOF_AUDIO_PCM_CONVERTER_H__
16 
17 #include <ipc/stream.h>
18 
19 #include <stddef.h>
20 #include <stdint.h>
21 
22 struct audio_stream;
23 
24 #if __XCC__
25 #include <xtensa/config/core-isa.h>
26 #endif
27 
28 #ifndef UNIT_TEST
29 #if __XCC__ && XCHAL_HAVE_HIFI3 && CONFIG_FORMAT_CONVERT_HIFI3
30 #define PCM_CONVERTER_HIFI3
31 #else
32 #define PCM_CONVERTER_GENERIC
33 #endif
34 #endif /* UNIT_TEST */
35 
36 /**
37  * \brief PCM conversion function interface for data in circular buffer
38  * \param source buffer with samples to process, read pointer is not modified
39  * \param ioffset offset to first sample in source stream
40  * \param sink output buffer, write pointer is not modified
41  * \param ooffset offset to first sample in sink stream
42  * \param samples number of samples to convert
43  * \return error code or number of processed samples.
44  */
45 typedef int (*pcm_converter_func)(const struct audio_stream *source,
46 				  uint32_t ioffset, struct audio_stream *sink,
47 				  uint32_t ooffset, uint32_t samples);
48 
49 /**
50  * \brief PCM conversion function interface for data in linear buffer
51  * \param psrc linear memory region with samples to process
52  * \param pdst linear memory region for output
53  * \param samples number of samples to convert
54  */
55 typedef void (*pcm_converter_lin_func)(const void *psrc, void *pdst,
56 				       uint32_t samples);
57 
58 /** \brief PCM conversion functions map. */
59 struct pcm_func_map {
60 	enum sof_ipc_frame source;	/**< source frame format */
61 	enum sof_ipc_frame sink;	/**< sink frame format */
62 	pcm_converter_func func; /**< PCM conversion function */
63 };
64 
65 /** \brief Map of formats with dedicated conversion functions. */
66 extern const struct pcm_func_map pcm_func_map[];
67 
68 /** \brief Number of conversion functions. */
69 extern const size_t pcm_func_count;
70 
71 /**
72  * \brief Retrieves PCM conversion function.
73  * \param[in] in Source frame format.
74  * \param[in] out Sink frame format.
75  */
76 static inline pcm_converter_func
pcm_get_conversion_function(enum sof_ipc_frame in,enum sof_ipc_frame out)77 pcm_get_conversion_function(enum sof_ipc_frame in,
78 			    enum sof_ipc_frame out)
79 {
80 	uint32_t i;
81 
82 	for (i = 0; i < pcm_func_count; i++) {
83 		if (in != pcm_func_map[i].source)
84 			continue;
85 		if (out != pcm_func_map[i].sink)
86 			continue;
87 
88 		return pcm_func_map[i].func;
89 	}
90 
91 	return NULL;
92 }
93 
94 /** \brief PCM conversion functions mapfor different size of valid bit and container. */
95 struct pcm_func_vc_map {
96 	enum sof_ipc_frame source;	/**< source frame container format */
97 	enum sof_ipc_frame valid_src_bits;	/**< source frame format */
98 	enum sof_ipc_frame sink;	/**< sink frame container format */
99 	enum sof_ipc_frame valid_sink_bits;	/**< sink frame format */
100 	pcm_converter_func func; /**< PCM conversion function */
101 };
102 
103 /** \brief Map of formats with dedicated conversion functions. */
104 extern const struct pcm_func_vc_map pcm_func_vc_map[];
105 
106 /** \brief Number of conversion functions. */
107 extern const size_t pcm_func_vc_count;
108 
109 /**
110  * \brief Retrieves PCM conversion function for different container size.
111  * \param in_bits is source container format.
112  * \param valid_in_bits is source valid sample format.
113  * \param out_bits is sink container format.
114  * \param valid_out_bits is sink valid sample format.
115  */
116 static inline pcm_converter_func
pcm_get_conversion_vc_function(enum sof_ipc_frame in_bits,enum sof_ipc_frame valid_in_bits,enum sof_ipc_frame out_bits,enum sof_ipc_frame valid_out_bits)117 pcm_get_conversion_vc_function(enum sof_ipc_frame in_bits,
118 			       enum sof_ipc_frame valid_in_bits,
119 			       enum sof_ipc_frame out_bits,
120 			       enum sof_ipc_frame valid_out_bits)
121 {
122 	uint32_t i;
123 
124 	for (i = 0; i < pcm_func_vc_count; i++) {
125 		if (in_bits != pcm_func_vc_map[i].source)
126 			continue;
127 		if (valid_in_bits != pcm_func_vc_map[i].valid_src_bits)
128 			continue;
129 		if (out_bits != pcm_func_vc_map[i].sink)
130 			continue;
131 		if (valid_out_bits != pcm_func_vc_map[i].valid_sink_bits)
132 			continue;
133 
134 		return pcm_func_vc_map[i].func;
135 	}
136 
137 	return NULL;
138 }
139 
140 /**
141  * \brief Convert data from circular buffer using converter working on linear
142  *	  memory space
143  * \param source buffer with samples to process, read pointer is not modified
144  * \param ioffset offset to first sample in source stream
145  * \param sink output buffer, write pointer is not modified
146  * \param ooffset offset to first sample in sink stream
147  * \param samples number of samples to convert
148  * \param converter core conversion function working on linear memory regions
149  * \return error code or number of processed samples
150  */
151 int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset,
152 			  struct audio_stream *sink, uint32_t ooffset,
153 			  uint32_t samples, pcm_converter_lin_func converter);
154 
155 #endif /* __SOF_AUDIO_PCM_CONVERTER_H__ */
156